diff --git a/Sd1/P/Maven/bluej/.gitignore b/Sd1/P/Maven/bluej/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..a1c3ab4d08c0f9f91918f21c730272a4711885e8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/.gitignore
@@ -0,0 +1,4 @@
+/target/
+/.settings/
+.classpath
+.project
diff --git a/Sd1/P/Maven/bluej/pom.xml b/Sd1/P/Maven/bluej/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..333a671637e0a813cf79381366f29a84d3a41cbf
--- /dev/null
+++ b/Sd1/P/Maven/bluej/pom.xml
@@ -0,0 +1,139 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>de.hdm-stuttgart.mi</groupId>
+	<artifactId>bluej</artifactId>
+	<version>3.0.9</version>
+	<packaging>jar</packaging>
+	<description>Repackaging Buej as Maven dependency currently requiring minor tweaks due to version and licensing issues</description>
+
+	<name>bluej</name>
+
+	<!--Fixme: Add a sensible project related domain here -->
+	<url>http://somedomain.org</url>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+
+	<profiles>
+		<profile>
+			<!-- Credits to http://stackoverflow.com/questions/3080437/jdk-tools-jar-as-maven-dependency -->
+			<id>default-profile</id>
+			<activation>
+				<activeByDefault>true</activeByDefault>
+				<file>
+					<exists>${java.home}/../lib/tools.jar</exists>
+				</file>
+			</activation>
+			<properties>
+				<toolsjar>${java.home}/../lib/tools.jar</toolsjar>
+			</properties>
+		</profile>
+		<profile>
+			<id>osx_profile</id>
+			<activation>
+				<activeByDefault>false</activeByDefault>
+				<os>
+					<family>mac</family>
+				</os>
+			</activation>
+			<properties>
+				<toolsjar>${java.home}/../Classes/classes.jar</toolsjar>
+			</properties>
+		</profile>
+
+	</profiles>
+
+	<dependencies>
+
+		<dependency>
+			<groupId>com.sun</groupId>
+			<artifactId>tools</artifactId>
+			<version>1.8.0</version>
+			<scope>system</scope>
+			<systemPath>${toolsjar}</systemPath>
+		</dependency>
+
+		<dependency>
+			<groupId>com.yuvimasory</groupId>
+			<artifactId>orange-extensions</artifactId>
+			<version>1.3.0</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.netbeans.lib</groupId>
+			<artifactId>cvsclient</artifactId>
+			<version>20060125</version>
+		</dependency>
+
+		<!-- <dependency> <groupId>org.tmatesoft.svnkit</groupId> <artifactId>svnkit</artifactId> 
+			<version>1.7.5</version> </dependency> -->
+		<dependency>
+			<groupId>org.tmatesoft</groupId>
+			<artifactId>svnkit</artifactId>
+			<version>1.1.2</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.tmatesoft.svnkit</groupId>
+			<artifactId>svnkit-javahl</artifactId>
+			<version>1.3.5</version>
+		</dependency>
+
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.8.2</version>
+		</dependency>
+
+	</dependencies>
+
+	<build>
+		<plugins>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.1</version>
+				<configuration>
+					<source>1.8</source>
+					<target>1.8</target>
+				</configuration>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-javadoc-plugin</artifactId>
+				<version>2.10.1</version>
+				<configuration />
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-shade-plugin</artifactId>
+				<version>2.3</version>
+				<configuration>
+					<transformers>
+						<transformer
+							implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+							<manifestEntries>
+								<Main-Class>de.hdm_stuttgart.mi.bluej.App</Main-Class>
+							</manifestEntries>
+						</transformer>
+					</transformers>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>shade</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+
+		</plugins>
+	</build>
+</project>
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..e777302b092d8d5836788fac5d3a6647e8658b02
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJEvent.java
@@ -0,0 +1,112 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+
+package bluej;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+  * Class to handle (throw and deliver) BlueJ events. Event are defined
+  * for things that might be caused by low level parts of the system which
+  * other parts of the system might be interested in. Objects can register
+  * themselves as event listeners. They then get notified of events.
+  *
+  * <p>A BlueJEvent has one argument. The argument passed differs for every 
+  * event type.
+  *
+  * <p>Event types and their arguments:<PRE>
+  *
+  *  type               argument            sent when...
+  *  -----------------------------------------------------------------------
+  *  CREATE_VM          (unused)            creation of VM has started
+  * 
+  *  CREATE_VM_FAILED   (unused)            creation of VM has failed
+  *
+  *  CREATE_VM_DONE     (unused)            creation of VM completed
+  *
+  *  METHOD_CALL        InvokerRecord       an interactive method call was started
+  *
+  *  EXECUTION_RESULT   bluej.debugmgr.ExecutionEvent   VM execution finished
+  *
+  *  GENERATING_DOCU    (unused)            documentation generation started
+  *
+  *  DOCU_GENERATED     (unused)            documentation generation finished
+  *
+  *  DOCU_ABORTED       (unused)            documentation generation aborted
+  *
+  * </PRE>
+  * 
+  * @author Michael Kolling
+  */
+public class BlueJEvent
+{
+    // BlueJ event types
+
+    public static final int CREATE_VM           = 0;
+    public static final int CREATE_VM_FAILED    = CREATE_VM + 1;
+    public static final int CREATE_VM_DONE      = CREATE_VM_FAILED + 1;
+    public static final int METHOD_CALL         = CREATE_VM_DONE + 1;
+    public static final int METHOD_CALL_FAILED  = METHOD_CALL + 1;
+    public static final int EXECUTION_RESULT    = METHOD_CALL_FAILED + 1;
+    public static final int GENERATING_DOCU     = EXECUTION_RESULT + 1;
+    public static final int DOCU_GENERATED      = GENERATING_DOCU + 1;
+    public static final int DOCU_ABORTED        = DOCU_GENERATED + 1;
+    
+    // other variables
+
+    private static List<BlueJEventListener> listeners =
+        Collections.synchronizedList(new ArrayList<BlueJEventListener>());
+
+    /**
+     * Raise a BlueJ event with an argument. All registered listeners
+     * will be informed of this event.
+     */
+    public static void raiseEvent(int eventId, Object arg)
+    {
+        Object[] listenersCopy = listeners.toArray();
+        for (int i = listenersCopy.length - 1; i >= 0; i--) {
+            BlueJEventListener listener = (BlueJEventListener) listenersCopy[i];
+            listener.blueJEvent(eventId, arg);
+        }
+    }
+    
+    /**
+     * Add a listener object. The object must implement the
+     * BlueJEventListener interface.
+     */
+    public static void addListener(BlueJEventListener listener)
+    {
+        listeners.add(listener);
+    }
+    
+    /**
+     * Remove a listener object from the known listener set.
+     */
+    public static void removeListener(BlueJEventListener listener)
+    {
+        listeners.remove(listener);
+    }
+    
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJEventListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJEventListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3ddf0645295c3160d83831088fc2cb6f123f4e8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJEventListener.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+/**
+ ** Interface for listeners to BlueJ events (see class BlueJEvent).
+ **
+ ** @author Michael Kolling
+ **/
+public interface BlueJEventListener
+{
+    /**
+     * Called when a BlueJ event is raised. The event can be any BlueJEvent
+     * type. The implementation of this method should check first whether
+     * the event type is of interest an return immediately if it isn't.
+     *
+     * @param eventId  A constant identifying the event. One of the event id
+     *                 constants defined in BlueJEvent.
+     * @param arg      An event specific parameter. See BlueJEvent for 
+     *                 definition.
+     */
+    void blueJEvent(int eventId, Object arg);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJLabel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJLabel.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee98c5eff427832324b63fd2657d6e70b147c126
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJLabel.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+
+/**
+ * Label used for the SplashWindow for BlueJ.
+ * 
+ * @author Poul Henriksen
+ */
+class BlueJLabel extends SplashLabel
+{
+    public BlueJLabel()
+    {
+        super("splash.jpg");
+    }
+
+    public void paintComponent(Graphics g)
+    {
+        BufferedImage image = getImage();
+        g.drawImage(image, 0, 0, null);
+        g.setColor(new Color(255,255,255));
+        g.setFont(new Font("SansSerif", Font.BOLD, 16));
+        if (g instanceof Graphics2D) {
+            Graphics2D g2d = (Graphics2D)g;
+            RenderingHints hints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING,
+                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+            g2d.addRenderingHints(hints);
+        }
+        g.drawString("Version " + Boot.BLUEJ_VERSION, 225, 48 /*image.getHeight()-28*/ );
+  }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJPropStringSource.java b/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJPropStringSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..4dce23fde5a1d24967226072dc5d883e1b64b100
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJPropStringSource.java
@@ -0,0 +1,37 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+
+/**
+ * Interface for a class which supports retrieving BlueJ property strings.
+ * 
+ * @author Davin McCall
+ */
+public interface BlueJPropStringSource
+{
+    public String getBlueJPropertyString(String property, String def);
+
+    public String getLabel(String key);
+    
+    public void setUserProperty(String property, String value);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJTheme.java b/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJTheme.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f24ea73f936304388d26106f89c0f1f85a388e3
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/BlueJTheme.java
@@ -0,0 +1,282 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+import java.awt.Dimension;
+import java.awt.Image;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.border.Border;
+import javax.swing.plaf.FontUIResource;
+import javax.swing.plaf.metal.DefaultMetalTheme;
+
+import bluej.prefmgr.PrefMgr;
+
+/**
+ * Class to provide simple UI customisations such as colours and fonts.
+ * Specifically created to allow access to default Fonts for user interface
+ * components for i18n purposes.
+ *
+ * @author  Bruce Quig
+ */
+public class BlueJTheme extends DefaultMetalTheme
+{
+    private final FontUIResource controlFont = 
+        new FontUIResource(PrefMgr.getStandardFont());
+    private final FontUIResource systemFont = 
+        new FontUIResource(controlFont);
+    private final FontUIResource userFont = 
+        new FontUIResource(controlFont);  
+    private final FontUIResource menuFont = 
+        new FontUIResource(PrefMgr.getStandardMenuFont());
+
+    private static final String SMALL_ICON_SUFFIX = "-icon-32.png";
+    private static final String MEDIUM_ICON_SUFFIX = "-icon-48.png";
+    private static final String LARGE_ICON_SUFFIX = "-icon-256.png";
+
+    // icon to be used for BlueJ windows
+    private static Image iconImage = null;
+
+    // common strings - must be accessed through getOkLabel()
+    private static String okayLabel;
+    private static String cancelLabel;
+    private static String closeLabel;
+    private static String continueLabel;
+
+    // a dimension for ok and cancel buttons that is as large as
+    // needed to display either
+    private static Dimension okCancelDimension;
+
+    // JSplitPane divider width constant
+    public static final int splitPaneDividerWidth = 3;
+
+    // Other general spacing constants. We should try to use these for consistency
+    public static final int generalSpacingWidth = 5;
+
+    public static final Border generalBorder =
+        BorderFactory.createEmptyBorder(10,10,10,10);
+
+    public static final Border generalBorderWithStatusBar =
+        BorderFactory.createEmptyBorder(10,10,0,10);
+
+    public static final Border dialogBorder =
+        BorderFactory.createEmptyBorder(12,12,12,12);
+
+    public static final int commandButtonSpacing = 5;
+    public static final int commandButtonPadding = 12;
+
+    public static final int componentSpacingSmall = 5;
+    public static final int componentSpacingLarge = 11;
+
+    public static final int dialogCommandButtonsVertical = 17;
+
+    /**
+     * Name of theme
+     */
+    public String getName() 
+    {  
+        return "BlueJTheme"; 
+    } 
+
+    public FontUIResource getControlTextFont() 
+    {  
+        return controlFont;
+    }
+
+    public FontUIResource getSystemTextFont() 
+    {  
+        return systemFont;
+    }
+
+    public FontUIResource getUserTextFont() 
+    {  
+        return userFont;
+    }
+
+    public FontUIResource getMenuTextFont() 
+    {  
+        return menuFont;
+    }
+
+    /**
+     * Get the icon for most BlueJ frames.
+     *
+     * @return	an icon to be used as the frame icon for most BlueJ windows
+     */
+    public static Image getIconImage()
+    {
+        String appName = Config.getApplicationName().toLowerCase();
+        return getApplicationIcon (appName);
+    }
+
+    /**
+     * Get the icon for most BlueJ frames.
+     *
+     * @return	an icon to be used as the frame icon for most BlueJ windows
+     */
+    public static Image getApplicationIcon(String baseName)
+    {
+        if (Config.isMacOS())
+            return null;        // don't set window icon on Mac - Mac OS generates dynamic icons
+
+        if (iconImage == null) {
+            if (Config.isModernWinOS()) {
+                // Win Vista, 7, or newer
+                iconImage = Config.getFixedImageAsIcon(baseName + LARGE_ICON_SUFFIX).getImage();
+            }
+            else if (Config.isWinOS()) {
+                // for Win XP
+                iconImage = Config.getFixedImageAsIcon(baseName + SMALL_ICON_SUFFIX).getImage();
+            }
+            else {
+                // Linux, etc.
+                iconImage = Config.getFixedImageAsIcon(baseName + MEDIUM_ICON_SUFFIX).getImage();
+            }
+        }
+
+        return iconImage;
+    }
+
+    /**
+     * Needed for Greenfoot
+     */
+    public static void setIconImage(Image newIconImage)
+    {
+        iconImage = newIconImage;
+    }
+
+    public static String getOkLabel()
+    {
+        if (okayLabel == null) {
+            okayLabel = Config.getString("okay");
+        }
+        return okayLabel;
+    }
+
+    public static String getCancelLabel()
+    {
+        if (cancelLabel == null) {
+            cancelLabel = Config.getString("cancel");
+        }
+        return cancelLabel;
+    }
+
+    public static String getCloseLabel()
+    {
+        if (closeLabel == null) {
+            closeLabel = Config.getString("close");
+        }
+        return closeLabel;
+    }
+
+
+    public static String getContinueLabel()
+    {
+        if (continueLabel == null) {
+            continueLabel = Config.getString("continue");
+        }
+        return continueLabel;
+    }
+
+    /**
+     * Get a standard BlueJ "ok" button.
+     * 
+     * @return	A JButton that says "ok"
+     */
+    public static JButton getOkButton()
+    {
+        computeButtonWidths();
+
+        JButton okButton = new JButton(getOkLabel());
+        // try to make the OK, cancel and continue buttons have equal size
+        okButton.setPreferredSize(okCancelDimension);
+        return okButton;
+    }
+
+    /**
+     * Get a standard BlueJ "cancel" button.
+     * 
+     * @return	A JButton that says "cancel"
+     */
+    public static JButton getCancelButton()
+    {
+        computeButtonWidths();
+
+        JButton cancelButton = new JButton(getCancelLabel());
+        // try to make the OK, cancel and continue  buttons have equal size
+        cancelButton.setPreferredSize(okCancelDimension);
+        return cancelButton;	
+    }
+
+    /**
+     * Get a standard BlueJ "close" button.
+     * 
+     * @return	A JButton that says "cancel"
+     */
+    public static JButton getCloseButton()
+    {
+        computeButtonWidths();
+
+        JButton closeButton = new JButton(getCloseLabel());
+        // try to make the OK, cancel and continue  buttons have equal size
+        closeButton.setPreferredSize(okCancelDimension);
+        return closeButton;	
+    }
+
+
+    /**
+     * Get a standard BlueJ "continue" button.
+     * 
+     * @return	A JButton that says "Continue"
+     */
+    public static JButton getContinueButton()
+    {
+        computeButtonWidths();
+
+        JButton continueButton = new JButton(getContinueLabel());
+        // try to make the OK, cancel and continue  buttons have equal size
+        continueButton.setPreferredSize(okCancelDimension);
+        return continueButton;	
+    }
+
+    /**
+     * Computer the maximum width of the ok, cancel and continue buttons
+     * and set the okCancelDimension to be representative of that size.
+     */
+    private static void computeButtonWidths()
+    {
+        if (okCancelDimension != null)
+            return;
+
+        JButton okButton = new JButton(getOkLabel());
+        JButton cancelButton = new JButton(getCancelLabel());
+        JButton continueButton = new JButton(getContinueLabel());
+
+        int maxWidth = Math.max(cancelButton.getPreferredSize().width,
+                okButton.getPreferredSize().width);
+        maxWidth = Math.max(maxWidth,
+                continueButton.getPreferredSize().width);
+
+        okCancelDimension = new Dimension(maxWidth, okButton.getPreferredSize().height);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/Boot.java b/Sd1/P/Maven/bluej/src/main/java/bluej/Boot.java
new file mode 100644
index 0000000000000000000000000000000000000000..65b07fe03ae2db96b2002f4150873a271dbe5705
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/Boot.java
@@ -0,0 +1,539 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Properties;
+
+/**
+ * This class is the BlueJ boot loader. bluej.Boot is the class that should be 
+ * started to execute BlueJ. No other external classpath settings are necessary. 
+ *
+ * This loader finds and loads the known BlueJ classes and sets up the classpath.
+ * While doing this, it displays a splash screen.
+ *
+ * @author  Andrew Patterson
+ * @author  Damiano Bolla
+ * @author  Michael Kolling
+ * @author  Bruce Quig
+ */
+public class Boot
+{
+
+    // The version numbers for BlueJ are changed in the BlueJ build.xml
+    // and then the update-version target should be executed.
+    public static final int BLUEJ_VERSION_MAJOR = 3;
+    public static final int BLUEJ_VERSION_MINOR = 0;
+    public static final int BLUEJ_VERSION_RELEASE = 9;
+    public static final String BLUEJ_VERSION_SUFFIX = "";
+
+    // public static final int BLUEJ_VERSION_NUMBER = BLUEJ_VERSION_MAJOR * 1000 +
+    //                                                BLUEJ_VERSION_MINOR * 100 +
+    //                                                BLUEJ_VERSION_RELEASE;
+
+    public static final String BLUEJ_VERSION = BLUEJ_VERSION_MAJOR
+                                         + "." + BLUEJ_VERSION_MINOR
+                                         + "." + BLUEJ_VERSION_RELEASE
+                                         + BLUEJ_VERSION_SUFFIX;
+
+    public static final String BLUEJ_VERSION_TITLE = "BlueJ " + BLUEJ_VERSION;
+    
+    // The version numbers for Greenfoot are changed in the Greenfoot build.xml
+    // and then the update-version target should be executed.
+    public static String GREENFOOT_VERSION = "2.3.0";
+    public static String GREENFOOT_API_VERSION = "2.5.0";
+    
+    // A singleton boot object so the rest of BlueJ can pick up args etc.
+    private static Boot instance;
+        
+    // The jar files we expect in the BlueJ lib directory
+    // The first lot are the ones to run BlueJ itself
+    private static String[] bluejJars = { "bluejcore.jar", "bluejeditor.jar", "bluejext.jar",
+                                          "AppleJavaExtensions.jar", "org-netbeans-lib-cvsclient.jar",
+                                          "svnkit-javahl.jar", "svnkit.jar", "trilead.jar"};
+
+    // Number of jars in above list generated by the BlueJ build process.
+    // These can be ignored during development runs (they must be the first
+    // jar files  listed in the array).
+    private static final int bluejBuildJars = 3;
+
+    // The second group are available to user code (and to bluej)
+    // bluejcore.jar is necessary as it contains the support runtime
+    // (bluej.runtime.* classes).
+    private static final String[] bluejUserJars = { "bluejcore.jar", "junit-4.8.2.jar" };
+
+    // The number of jar files in the user jars which are built from the
+    // BlueJ classes directory
+    private static final int bluejUserBuildJars = 1;
+    
+    // In greenfoot we need access to the BlueJ classes.
+    // When running from eclipse, the first jar files will be excluded as explained above at the bluejBuildJars field.
+    private static final String JLAYER_MP3_JAR = "jl1.0.1.jar";
+    private static final String[] greenfootUserJars = {"extensions" + File.separatorChar + "greenfoot.jar", 
+        "bluejcore.jar", "bluejeditor.jar", "bluejext.jar",
+        "AppleJavaExtensions.jar", "junit-4.8.2.jar", "bluej.jar",
+        "diffutils-1.2.1.jar", 
+        "commons-httpclient-3.1.jar", "commons-logging-api-1.1.2.jar",
+        "commons-codec-1.3.jar", JLAYER_MP3_JAR, "opencsv-2.3.jar"};
+
+    // Jars that should be included with exported scenarios
+    public static final String[] GREENFOOT_EXPORT_JARS = {JLAYER_MP3_JAR};
+    
+    private static final int greenfootUserBuildJars = 4;
+    
+    // The variable form of the above
+    private static String [] runtimeJars = bluejJars;
+    private static String [] userJars = bluejUserJars;
+    private static int numBuildJars = bluejBuildJars;
+    private static int numUserBuildJars = bluejUserBuildJars;
+    
+    private static boolean isGreenfoot = false;
+    private static File bluejLibDir; 
+
+    private SplashWindow splashWindow;
+    
+    /**
+     * Entry point for booting BlueJ
+     *
+     * @param  args  The command line arguments
+     */
+    public static void main(String[] args)
+    {
+        if((args.length >= 1) && "-version".equals(args[0])) {
+            System.out.println("BlueJ version " + BLUEJ_VERSION
+                               + " (Java version "
+                               + System.getProperty("java.version")
+                               + ")");
+            System.out.println("--");
+
+            System.out.println("virtual machine: "
+                               + System.getProperty("java.vm.name")
+                               + " "
+                               + System.getProperty("java.vm.version")
+                               + " ("
+                               + System.getProperty("java.vm.vendor")
+                               + ")");
+
+            System.out.println("running on: "
+                               + System.getProperty("os.name")
+                               + " "
+                               + System.getProperty("os.version")
+                               + " ("
+                               + System.getProperty("os.arch")
+                               + ")");
+            System.exit(-1);
+        }
+
+        Properties commandLineProps = processCommandLineProperties(args);
+        isGreenfoot = commandLineProps.getProperty("greenfoot", "false").equals("true");
+        
+        SplashLabel image = null;
+        if(isGreenfoot) {
+            image = new GreenfootLabel();
+            runtimeJars = greenfootUserJars;
+            userJars = greenfootUserJars;
+            numBuildJars = greenfootUserBuildJars;
+            numUserBuildJars = greenfootUserBuildJars;
+        } else {
+            image = new BlueJLabel();
+        }
+
+        try {
+            instance = new Boot(args, commandLineProps, image);
+            instance.bootBluej();
+        }
+        catch (Throwable t) {
+            t.printStackTrace();
+            System.exit(1);
+        }
+        
+        // Make sure we don't return until the VM is exited
+        synchronized (instance) {
+            while (true) {
+                try {
+                    instance.wait();
+                }
+                catch (InterruptedException ie) {}
+            }
+        }
+    }
+
+
+    /**
+     * Returns the singleton Boot instance, so the rest of BlueJ can find paths, args, etc.
+     *
+     * @return    the singleton Boot object instance
+     */
+    public static Boot getInstance()
+    {
+        return instance;
+    }
+
+
+    // ---- instance part ----
+    private Properties commandLineProps; //Properties specified a the command line (-....)
+    private String[] args;      // Command line arguments
+    private File javaHomeDir;   // The value returned by System.getProperty
+  
+    private ClassLoader bootLoader; // The loader this class is loaded with
+
+    private URL[] runtimeUserClassPath; // The initial class path used to run code within BlueJ
+    private URL[] runtimeClassPath;     // The class path containing all the BlueJ classes
+
+
+    /**
+     * Constructor for the singleton Boot object.
+     * 
+     * @param args the arguments with which main() was invoked
+     * @param props the properties (created from the args)
+     */
+    private Boot(String[] args, Properties props, SplashLabel image)
+    {
+        // Display the splash window, and wait until it's been painted before
+        // proceeding. Otherwise, the event thread may be occupied by BlueJ
+        // starting up and the window might *never* be painted.
+        splashWindow = new SplashWindow(image);
+        splashWindow.repaint(); // avoid delay before painting
+        splashWindow.waitUntilPainted();
+
+        this.args = args;
+        this.commandLineProps = props;
+    }
+
+    /**
+     * Hide (and dispose) the splash window
+     */
+    public void disposeSplashWindow()
+    {
+        splashWindow.dispose();
+    }
+
+    /**
+     * Retuns the args list passed to the starting program.
+     *
+     * @return    The args value
+     */
+    public String[] getArgs()
+    {
+        return args;
+    }
+
+
+    /**
+     * Return true if we are booting Greenfoot.
+     */
+    public boolean isGreenfoot()
+    {
+        return isGreenfoot;
+    }
+
+
+    /**
+     * Returns the home directory of the java we have been started with
+     *
+     * @return    The javaHome value
+     */
+    public File getJavaHome()
+    {
+        return javaHomeDir;
+    }
+
+    /**
+     * Returns the BlueJ library directory.
+     *
+     * @return    The bluejLibDir value
+     */
+    public static File getBluejLibDir()
+    {
+        if(bluejLibDir == null) {
+            bluejLibDir = calculateBluejLibDir();
+        }
+        return bluejLibDir;
+    }
+
+    /**
+     * Returns the runtime classpath. This contains all the classes for BlueJ.
+     *
+     * @return    The runtimeClassPath value.
+     */
+    public URL[] getRuntimeClassPath()
+    {
+        return runtimeClassPath;
+    }
+    
+    /**
+     * Returns the runtime user classpath. This is available to code within BlueJ.
+     *
+     * @return    The runtimeUserClassPath value.
+     */
+    public URL[] getRuntimeUserClassPath()
+    {
+        return runtimeUserClassPath;
+    }
+
+    /**
+     * Returns the boot class loader, the one that is used to load this class.
+     *
+     * @return The bootClassLoader value.
+     */
+    public ClassLoader getBootClassLoader ()
+    {
+        return bootLoader;
+    }
+
+    /**
+     * Calculate the various path values, create a new classloader and
+     * construct a bluej.Main. This needs to be outside the constructor to
+     * ensure that the singleton instance is valid by the time
+     * bluej.Main is run.
+     */
+    private void bootBluej()
+    {
+        initializeBoot();
+        try {
+            URLClassLoader runtimeLoader = new URLClassLoader(runtimeClassPath, bootLoader);
+ 
+            // Construct a bluej.Main object. This starts BlueJ "proper".
+            Class<?> mainClass = Class.forName("bluej.Main", true, runtimeLoader);
+            mainClass.newInstance();
+            
+        } catch (Exception exc) {
+            throw new RuntimeException(exc);
+        }
+    }
+    
+    private void initializeBoot()
+    {
+        // Retrieve the current classLoader, this is the boot loader.
+        bootLoader = getClass().getClassLoader();
+
+        // Get the home directory of the Java implementation we're being run by
+        javaHomeDir = new File(System.getProperty("java.home"));
+
+        try {
+            runtimeClassPath = getKnownJars(getBluejLibDir(), runtimeJars, true, numBuildJars);
+            runtimeUserClassPath = getKnownJars(getBluejLibDir(), userJars, false, numUserBuildJars);
+        }
+        catch (Exception exc) {
+            exc.printStackTrace();
+        }
+    }
+
+    /**
+     * Calculate the bluejLibDir value by doing some reasoning on a resource 
+     * we know we have: the .class file for the Boot class.
+     * For example:
+     * bootUrl=jar:file:/C:/home/bluej/bluej/lib/bluej.jar!/bluej/Boot.class
+     * bootFullName=file:/C:/home/bluej/bluej/lib/bluej.jar!/bluej/Boot.class
+     * bootName=file:/C:/home/bluej/bluej/lib/bluej.jar
+     * finalName=/C:/home/bluej/bluej/lib/bluej.jar
+     * Parent=C:\home\bluej\bluej\lib
+     *
+     * @return    the path of the BlueJ lib directory
+     */
+    private static File calculateBluejLibDir()
+    {
+        File bluejDir = null;
+        String bootFullName = Boot.class.getResource("Boot.class").toString();
+
+        try {
+            if (! bootFullName.startsWith("jar:")) {
+                // Boot.class is not in a jar-file. Find a lib directory somewhere
+                // above us to use
+                File startingDir = (new File(new URI(bootFullName)).getParentFile());
+                while((startingDir != null) &&
+                        !(new File(startingDir.getParentFile(), "lib").isDirectory())) {
+                    startingDir = startingDir.getParentFile();
+                }
+                
+                if (startingDir == null) {
+                    bluejDir = null;
+                }
+                else {
+                    bluejDir = new File(startingDir.getParentFile(), "lib");
+                }
+            }
+            else {
+                // The class is in a jar file, '!' separates the jar file name
+                // from the class name. Cut off the class name and the "jar:" prefix.
+                int classIndex = bootFullName.indexOf("!");
+                String bootName = bootFullName.substring(4, classIndex);
+                
+                File finalFile = new File(new URI(bootName));
+                bluejDir = finalFile.getParentFile();
+            }   
+        } 
+        catch (URISyntaxException use) { }
+        
+        return bluejDir;
+    }
+
+    /**
+     * Returns an array of URLs for all the required BlueJ jars
+     *
+     * @param libDir  the BlueJ "lib" dir (where the jars are stored)
+     * @param jars    the names of the jar files whose urls to add in the
+     *                returned list
+     * @param isSystem  True if tools.jar should be included in the returned
+     *                  list, on systems that need it
+     * @param numBuildJars  The number of jar files in the jars array which
+     *                  are built from the BlueJ source. If running from eclipse
+     *                  these can be replaced with a single entry - the classes
+     *                  directory.
+     * 
+     * @return  URLs of the required JAR files
+     * @exception  MalformedURLException  for any problems with the URLs
+     */
+    private URL[] getKnownJars(File libDir, String[] jars, boolean isSystem, int numBuildJars) 
+        throws MalformedURLException
+    {
+        boolean useClassesDir = commandLineProps.getProperty("useclassesdir", "false").equals("true");
+        
+        // by default, we require all our known jars to be present
+        int startJar = 0;
+        ArrayList<URL> urlList = new ArrayList<URL>();
+
+        // a hack to let BlueJ run from within Eclipse.
+        // If specified on command line, lets add a ../classes
+        // directory to the classpath (where Eclipse stores the
+        // .class files)
+        if (numBuildJars != 0 && useClassesDir) {
+            File classesDir = new File(libDir.getParentFile(), "classes");
+            
+            if (classesDir.isDirectory()) {
+                urlList.add(classesDir.toURI().toURL());
+                if (isGreenfoot) {
+                    String gfClassesDir = commandLineProps.getProperty("greenfootclassesdir");
+                    if (gfClassesDir != null) {
+                        classesDir = new File(gfClassesDir);
+                        urlList.add(classesDir.toURI().toURL());
+                    }
+                }
+                
+                // skip over requiring bluejcore.jar, bluejeditor.jar etc.
+                startJar = numBuildJars;
+            }
+        }
+
+        for (int i=startJar; i < jars.length; i++) {
+            File toAdd = new File(libDir, jars[i]);
+            
+            // No need to throw exception at this point; we will get
+            // a ClassNotFoundException or similar if there is really a
+            // problem.
+            //if (!toAdd.canRead())
+            //    throw new IllegalStateException("required jar is missing or unreadable: " + toAdd);
+
+            if (toAdd.canRead())
+                urlList.add(toAdd.toURI().toURL());
+        }
+    
+        if (isSystem) {
+            // We also need to add tools.jar on some systems
+            URL toolsURL = getToolsURL();
+            if(toolsURL != null)
+                urlList.add(toolsURL);
+        }
+        return (URL[]) urlList.toArray(new URL[0]);
+    }
+
+    /**
+     * Get the URL of the  current tools.jar file
+     * Looks for lib/tools.jar in the current javaHome
+     * and in the parent of it.
+     * tools.jar is needed on many (but not all!) systems. Currently, 
+     * MacOS is the only system known to us without a tools URL, but 
+     * there may be others in the furure. This method returns null
+     * if tools.jar does not exist.
+     *
+     * @return   The URL of the tools.jar file for the current Java implementation, or null.
+     * @exception  MalformedURLException  for any problems with the URL
+     */
+    private URL getToolsURL() 
+        throws MalformedURLException
+    {
+        String osname = System.getProperty("os.name", "");
+        if(osname.startsWith("Mac"))     // we know it does not exist on a Mac...
+            return null;
+
+        File toolsFile = new File(javaHomeDir, "lib/tools.jar");
+        if (toolsFile.canRead())
+            return toolsFile.toURI().toURL();
+
+        File parentDir = javaHomeDir.getParentFile();
+        toolsFile = new File(parentDir, "lib/tools.jar");
+        if (toolsFile.canRead())
+            return toolsFile.toURI().toURL();
+        else {
+            // on other systems where we don't find it, we just warn. We don't expect it
+            // to happen, but you never know...
+            System.err.println("class Boot: tools.jar not found. Potential problem for execution.");
+            return null;
+        }
+    }
+    
+    /**
+     * Analyse and process command line specified properties.
+     * Properties can be specified with -... command line options. For example: -bluej.debug=true
+     * 
+     * @param args The command line parameters
+     * @return The property object
+     */
+    private static Properties processCommandLineProperties(String[] args)
+    {
+        Properties props = new Properties();
+
+        for(int i = 0; i < args.length; i++) {
+            if (!args[i].startsWith("-"))
+                continue;
+            
+            String definition = args[i].substring(1);
+            int definitionEquals = definition.indexOf('=');
+            
+            if (definitionEquals < 0)
+                continue;
+            
+            String propName = definition.substring(0, definitionEquals); 
+            String propValue = definition.substring(definitionEquals+1);
+            
+            if (!propName.equals("") && !propValue.equals(""))
+                props.put(propName, propValue);
+        }
+        return props;
+    }
+
+    /**
+     * Returns command line specified properties. <br>
+     * 
+     * Properties can be specified with -... command line options. For example: -bluej.debug=true
+     */
+    public Properties getCommandLineProperties()
+    {
+        return commandLineProps;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/Config.java b/Sd1/P/Maven/bluej/src/main/java/bluej/Config.java
new file mode 100644
index 0000000000000000000000000000000000000000..7166ebadfe781228a20f2e3b79c8130df537e6a6
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/Config.java
@@ -0,0 +1,1614 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+
+import javax.swing.ImageIcon;
+import javax.swing.KeyStroke;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+import javax.swing.UIManager.LookAndFeelInfo;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.Border;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.LineBorder;
+import javax.swing.plaf.metal.MetalLookAndFeel;
+
+import bluej.utility.Debug;
+import bluej.utility.Utility;
+
+/**
+ * Class to handle application configuration for BlueJ.
+ * The configuration information is spread over several files: <BR>
+ * <BR>
+ *  &lt;bluej_home>/lib/bluej.defs <BR>
+ *  &lt;user_home>/.bluej/bluej.properties <BR>
+ *  command line arguments in form -D&lt;prop>=&lt;val> <BR>
+ * <BR>
+ * bluej.defs - contains system definitions which are not user specific<BR>
+ * bluej.properties - contains user specific settings.
+ *    Settings here override settings in bluej.defs <BR>
+ * command line arguments - contains per-launch specific settings.
+ *    Settings here override settings in bluej.properties <BR>
+ * <BR>
+ * There is also a set of language specific labels 
+ * in a directory named after the language
+ *  &lt;bluej_home>/lib/&lt;language>/labels
+ *
+ * @author Michael Cahill
+ * @author Michael Kolling
+ * @author Andrew Patterson
+ */
+public final class Config
+{
+    public static final String nl = System.getProperty("line.separator");
+
+    public static Properties moeSystemProps;  // moe (editor) properties
+    public static Properties moeUserProps;    // moe (editor) properties
+
+    public static String compilertype = "javac";  // current compiler (javac, jikes)
+    public static String language;      // message language (english, ...)
+
+    public static Rectangle screenBounds; // maximum dimensions of screen
+
+    public static final String osname = System.getProperty("os.name", "");
+    public static final String DEFAULT_LANGUAGE = "english";
+    public static final String BLUEJ_OPENPACKAGE = "bluej.openPackage";
+    public static final String bluejDebugLogName = "bluej-debuglog.txt";
+    public static final String greenfootDebugLogName = "greenfoot-debuglog.txt";
+    public static String debugLogName = bluejDebugLogName;
+
+    public static final Color ENV_COLOUR = new Color(152,32,32);
+
+
+    // a border for components with keyboard focus
+    public static final Border focusBorder = new CompoundBorder(new LineBorder(Color.BLACK),
+            new BevelBorder(BevelBorder.LOWERED,
+                    new Color(195, 195, 195),
+                    new Color(240, 240, 240),
+                    new Color(195, 195, 195),
+                    new Color(124, 124, 124)));
+
+    // a border for components without keyboard focus
+    public static final Border normalBorder = new CompoundBorder(new EmptyBorder(1,1,1,1),
+            new BevelBorder(BevelBorder.LOWERED,
+                    new Color(195, 195, 195),
+                    new Color(240, 240, 240),
+                    new Color(124, 124, 124),
+                    new Color(195, 195, 195)));
+
+
+    // bluej configuration properties hierarchy
+    // (command overrides user which overrides system)
+    
+    private static Properties systemProps;      // bluej.defs
+    private static Properties userProps;        // <user home>/bluej.properties
+    private static Properties greenfootProps;   // greenfoot.defs
+    private static Properties commandProps;     // specified on the command line
+
+    private static Properties initialCommandLineProps; // The properties
+                                                       // specified on the
+                                                       // command line
+    private static Properties langProps;        // international labels
+    private static Properties langVarProps;     // language label variables (APPNAME)
+
+    private static BlueJPropStringSource propSource; // source for properties
+
+    private static File bluejLibDir;
+    private static File userPrefDir;
+    /** The greenfoot subdirectory of the "lib"-directory*/ 
+    private static File greenfootLibDir;
+    
+    private static boolean usingMacOSScreenMenubar;
+
+    private static boolean initialised = false;
+    private static boolean isGreenfoot = false;
+    
+    /** name of the icons file for the VM on Mac */
+    private static final String BLUEJ_DEBUG_DOCK_ICON = "vm.icns";
+    private static final String GREENFOOT_DEBUG_DOCK_ICON = "greenfootvm.icns";
+    
+    /** name of the VM in the dock on Mac */
+    private static final String BLUEJ_DEBUG_DOCK_NAME = "BlueJ Virtual Machine";
+    private static final String GREENFOOT_DEBUG_DOCK_NAME = "Greenfoot";
+    
+    protected static final int SHORTCUT_MASK =
+        Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+    
+    // Bit ugly having it here, but it's needed by MiscPrefPanel (which may just be in BlueJ)
+    // and by Greenfoot
+    public static final KeyStroke GREENFOOT_SET_PLAYER_NAME_SHORTCUT =
+        KeyStroke.getKeyStroke(KeyEvent.VK_P, SHORTCUT_MASK | InputEvent.SHIFT_DOWN_MASK);
+    
+    private static Color selectionColour;
+    private static Color selectionColour2;
+    private static Color highlightColour;
+    private static Color highlightColour2;
+    private static List<String> debugVMArgs = new ArrayList<String>();
+    
+    /** whether this is the debug vm or not. */
+    private static boolean isDebugVm = true; // Default to true, will be corrected on main VM
+
+    /**
+     * Initialisation of BlueJ configuration. Must be called at startup.
+     * This method finds and opens the configuration files.<p>
+     * 
+     * See also initializeVMside().
+     */
+    public static void initialise(File bluejLibDir, Properties tempCommandLineProps,
+                                  boolean bootingGreenfoot)
+    {
+        initialise(bluejLibDir, tempCommandLineProps, bootingGreenfoot, true);
+    }
+    
+    /**
+     * Initialisation of BlueJ configuration. Must be called at startup.
+     * This method finds and opens the configuration files.<p>
+     * 
+     * See also initializeVMside().
+     */
+    private static void initialise(File bluejLibDir, Properties tempCommandLineProps,
+                                  boolean bootingGreenfoot, boolean createUserhome)
+    {
+        if(initialised)
+            return;
+
+        initialised = true;
+        
+        initialCommandLineProps = tempCommandLineProps;
+        
+        isGreenfoot = bootingGreenfoot;
+
+        screenBounds = calculateScreenBounds();
+
+        // construct paths for the configuration directories
+        Config.bluejLibDir = bluejLibDir;
+        Config.greenfootLibDir = new File(bluejLibDir, "greenfoot");
+        
+        // setup our heirarchy of property objects if it is not done yet:
+        if(systemProps == null)
+        {
+            isDebugVm = false;
+            
+            // top level is the system properties loaded from bluej.defs
+            systemProps = loadDefs("bluej.defs", System.getProperties());
+            
+            // next level is the greenfoot propeties (if we are running greenfoot)
+            // and then the user propeties (not loaded yet)
+            if(isGreenfoot()) {
+                greenfootProps = loadDefs("greenfoot.defs", systemProps);
+                userProps = new Properties(greenfootProps);
+            }
+            else {
+                userProps = new Properties(systemProps);
+            }
+        }
+        
+        // then there is the command line properties
+        commandProps = new Properties(userProps);
+        
+        // copy in all our command line properties (done first
+        // incase the bluej.userHome property is one specified)
+        commandProps.putAll(tempCommandLineProps);
+        commandProps.setProperty("bluej.libdir", bluejLibDir.getAbsolutePath());
+        
+        if (createUserhome) {
+
+            // get user home directory
+            initUserHome();
+
+            // add user specific definitions (bluej.properties or greenfoot.properties)
+            loadProperties(getApplicationName().toLowerCase(), userProps);
+
+            // set a new name for the log file if we are running in greenfoot mode
+            if(isGreenfoot) {
+                debugLogName = greenfootDebugLogName;
+            }
+
+            checkDebug(userPrefDir);
+        }
+        
+        // find our language (but default to english if none found)
+        language = commandProps.getProperty("bluej.language", DEFAULT_LANGUAGE);
+        langProps = loadLanguageLabels(language);
+
+        moeSystemProps = loadDefs("moe.defs", System.getProperties());
+        moeUserProps = new Properties(moeSystemProps);
+        loadProperties("moe", moeUserProps);  // add user specific editor definitions
+
+        // Whether or not to use the screen menu bar on a Mac
+        String macOSscreenMenuBar = Config.getPropString("bluej.macos.screenmenubar", "true");
+        // The value of the BlueJ property overrides the system setting
+        System.setProperty("apple.laf.useScreenMenuBar", macOSscreenMenuBar);      
+
+        usingMacOSScreenMenubar = (isMacOS() && macOSscreenMenuBar.equals("true"));
+        
+        boolean themed = Config.getPropBoolean("bluej.useTheme");
+        if(themed) {    
+            MetalLookAndFeel.setCurrentTheme(new BlueJTheme());
+        }
+
+        String laf = Config.getPropString("bluej.lookAndFeel", "bluejdefault");
+        setLookAndFeel(laf);
+        
+        //read any debug vm args
+        initDebugVMArgs();
+        Config.setVMLocale();
+        
+        // Create a property containing the BlueJ version string
+        // put it in command_props so it won't be saved to a file
+        commandProps.setProperty("bluej.version", Boot.BLUEJ_VERSION);
+    }
+
+    /**
+     * Initialise the user home (try and create directories if necessary).
+     * <p>
+     * We try the bluej.userHome property, or default to the system user.home
+     * property if that is not set. If the result is not writable we try
+     * bluej.userHome1, bluej.userHome2, etc.
+     */
+    private static void initUserHome()
+    {
+        File userHome;
+        String homeDir = getPropString("bluej.userHome", "$user.home");
+        userHome = new File(homeDir);
+
+        String prefDirName = getBlueJPrefDirName();
+        
+        // get user specific bluej property directory (in user home)
+        userPrefDir = new File(userHome, prefDirName);
+
+        int nameCounter = 1;
+        do {
+            if (! userPrefDir.isDirectory()) {
+                if (userPrefDir.mkdirs()) {
+                    // successfully created the preferences directory
+                    break;
+                }
+            }
+            else if (userPrefDir.canWrite()) {
+                break;
+            }
+            
+            nameCounter++;
+            String propertyName = "bluej.userHome" + nameCounter;
+            homeDir = getPropString(propertyName, null);
+            if (homeDir == null) {
+                break;
+            }
+            userHome = new File(homeDir);
+            userPrefDir = new File(userHome, prefDirName);
+        }
+        while (true);
+        
+        if (homeDir == null) {
+            // Now we're in trouble... just user user.home, and hope it's writable.
+            homeDir = System.getProperty("user.home");
+            userHome = new File(homeDir);
+            userPrefDir = new File(userHome, prefDirName);
+        }
+    }
+    
+    /**
+     * Alternative to "initialise", to be used in the debugee-VM by
+     * applications which require it (ie. greenfoot).
+     */    
+    public static void initializeVMside(File bluejLibDir, Properties tempCommandLineProps, boolean bootingGreenfoot, BlueJPropStringSource propSource)
+    {
+        isDebugVm = true;
+        Config.propSource = propSource;
+
+        // Set up the properties so that they use the properties from the
+        // BlueJVM
+        systemProps = new Properties() {
+            public String getProperty(String key)
+            {
+                return Config.propSource.getBlueJPropertyString(key, null);
+            }
+
+            public String getProperty(String key, String def)
+            {
+                return Config.propSource.getBlueJPropertyString(key, def);
+            }
+        };
+        userProps = new Properties(systemProps) {
+            public Object setProperty(String key, String val)
+            {
+                String rval = getProperty(key);
+                Config.propSource.setUserProperty(key, val);
+                return rval;
+            }
+            
+            public String getProperty(String key)
+            {
+                return Config.propSource.getBlueJPropertyString(key, null);
+            }
+
+            public String getProperty(String key, String def)
+            {
+                return Config.propSource.getBlueJPropertyString(key, def);
+            }
+        };
+        initialise(bluejLibDir, tempCommandLineProps, bootingGreenfoot, false);
+    }
+
+    /**
+     * Get the properties that were given on the command line and used 
+     * to initialise bluej.Config.
+     */
+    public static Properties getInitialCommandLineProperties()
+    {
+        return initialCommandLineProps;
+    }    
+    
+    /**
+     * Initializer for use in Greenfoot's standalone scenario viewer if you 
+     * export a scenario as an app or applet.
+     */
+    public static void initializeStandalone(BlueJPropStringSource propSource)
+    {
+        if(initialised)
+            return;
+    
+        initialised = true;
+        Config.isGreenfoot = true;
+        Config.propSource = propSource;
+        
+        langProps =  new Properties() {
+            public String getProperty(String key)
+            {
+                return Config.propSource.getLabel(key);
+            }
+            
+            public String getProperty(String key, String def)
+            {
+                return Config.propSource.getLabel(key);
+            }
+        };
+        commandProps = langProps;
+    }
+    
+    public static boolean isInitialised() 
+    {
+        return initialised;
+    }
+    
+    /**
+     * Get the name of icons file for the debug VM (Mac).
+     */
+    public static String getVMIconsName()
+    {
+        if(isGreenfoot()) {
+            return GREENFOOT_DEBUG_DOCK_ICON;
+        }
+        else {
+            return BLUEJ_DEBUG_DOCK_ICON;
+        }
+    }
+    
+    /**
+     * Get the name of the debug VM to appear in the dock (Mac).
+     */
+    public static String getVMDockName()
+    {
+        if(isGreenfoot()) {
+            return GREENFOOT_DEBUG_DOCK_NAME;
+        }
+        else {
+            return BLUEJ_DEBUG_DOCK_NAME;
+        }
+    }
+    
+    /**
+     * True if this is the debugVM or false if not.
+     */
+    public static boolean isDebugVM() 
+    {
+        return isDebugVm;
+    }
+    
+    /**
+     * Tell us whether we are running on MacOS
+     */
+    public static boolean isMacOS()
+    {
+        return osname.startsWith("Mac");
+    }
+
+    /**
+     * Tell us whether we are running on MacOS 10.5 (Leopard) or later
+     */
+    public static boolean isMacOSLeopard()
+    {
+        return osname.startsWith("Mac") &&
+                System.getProperty("os.version").compareTo("10.5") >= 0;
+    }
+    
+    /**
+     * Tell use whether we are running on MacOS 10.6 (Snow Leopard) or later
+     */
+    public static boolean isMacOSSnowLeopard()
+    {
+        return osname.startsWith("Mac") &&
+                System.getProperty("os.version").compareTo("10.6") >= 0;
+    }
+    
+    /**
+     * Tell us whether we are running on MS Windows
+     */
+    public static boolean isWinOS()
+    {
+        return osname.startsWith("Windows");
+    }
+    
+    /**
+     * True if OS is Windows Vista or newer.
+     */
+    public static boolean isModernWinOS()
+    {
+        return isWinOS()
+                && System.getProperty("os.version").compareTo("6.0") >= 0;
+    }
+    
+    /**
+     * Tell us whether we are running on Linux
+     */
+    public static boolean isLinux()
+    {
+        return osname.startsWith("Linux");
+    }
+    
+    /**
+     * Tell us whether we are running on Solaris
+     */
+    public static boolean isSolaris()
+    {
+        return osname.startsWith("Solaris");
+    }
+    
+    /**
+     * Tell us whether we are running on a Java VM that supports 1.5 features.
+     */
+    public static boolean isJava15()
+    {
+        return System.getProperty("java.specification.version").compareTo("1.5") >= 0;
+    }
+    
+    /**
+     * Tell us whether we are running on a Java VM that supports Java 6 features.
+     */
+    public static boolean isJava16()
+    {
+        return System.getProperty("java.specification.version").compareTo("1.6") >= 0;
+    }
+    
+    /**
+     * Tell us whether we are running on a Java VM that supports Java 7 features.
+     */
+    public static boolean isJava17()
+    {
+        return System.getProperty("java.specification.version").compareTo("1.7") >= 0;
+    }
+    
+    /**
+     * Tell us whether we are running OpenJDK.
+     */
+    public static boolean isOpenJDK()
+    {
+        return System.getProperty("java.runtime.name").startsWith("OpenJDK");
+    }
+    
+    /**
+     * Tell use whether java 1.5 features are to be used. This allows
+     * suppressing 1.5 features when running on a 1.5 VM (for instance to
+     * suppress the "unchecked" warnings which occur when compiling legacy
+     * code). 
+     */
+    public static boolean usingJava15()
+    {
+        // for now, always use 1.5 features where available
+        return isJava15();
+    }
+    
+    /**
+     * Return the name of a directory within the user's home directory
+     * that should be used for storing BlueJ user preferences.
+     * 
+     * @return The path of the preference directory relative to the user's home
+     */
+    private static String getBlueJPrefDirName()
+    {
+        String programName = "bluej";
+        if(isGreenfoot) {
+            programName = "greenfoot";
+        }
+        if(isMacOS()) {
+            return "Library/Preferences/org." + programName;
+        }
+        else if(isWinOS()) {
+            return programName;
+        }
+        else {
+            return "." + programName;
+        }
+    }
+    
+    /**
+     * Get the name of this application.
+     */
+    public static String getApplicationName()
+    {
+        if(isGreenfoot) {
+            return "Greenfoot";
+        }
+        else {
+            return "BlueJ";
+        }
+    }
+    
+    /**
+     * Tell us whether we are using a Mac screen menubar
+     */
+    public static boolean usingMacScreenMenubar()
+    {
+        return usingMacOSScreenMenubar;
+    }
+    
+    /**
+     * Get the screen size information
+     */
+    private static Rectangle calculateScreenBounds()
+    {
+        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+        return new Rectangle(d);
+    }
+
+    /**
+     * Check whether we want to see debug information. If not, redirect it to
+     * a file.
+     */
+    private static void checkDebug(File userdir)
+    {
+        if (!isDebugVM()) {
+            if (!"true".equals(commandProps.getProperty("bluej.debug"))) {
+                File debugLogFile = new File(userdir, debugLogName);
+                // simple diversion of output stream to a log file
+                try {
+                    PrintStream outStream =
+                        new PrintStream(new FileOutputStream(debugLogFile));
+                    System.setOut(outStream);
+                    System.setErr(outStream);
+                    Debug.setDebugStream(new OutputStreamWriter(outStream));
+
+                    Debug.message(getApplicationName() + " run started: " + new Date());
+                    if(isGreenfoot())
+                        Debug.message("Greenfoot version: " + Boot.GREENFOOT_VERSION);
+                    else
+                        Debug.message("BlueJ version " + Boot.BLUEJ_VERSION);
+                    Debug.message("Java version " + System.getProperty("java.version"));
+                    Debug.message("Virtual machine: " +
+                            System.getProperty("java.vm.name") + " " +
+                            System.getProperty("java.vm.version") +
+                            " (" + System.getProperty("java.vm.vendor") + ")");
+                    Debug.message("Running on: " + System.getProperty("os.name") +
+                            " " + System.getProperty("os.version") +
+                            " (" + System.getProperty("os.arch") + ")");
+                    Debug.message("Java Home: " + System.getProperty("java.home"));            
+                    Debug.message("----");    
+                    return;
+                }
+                catch (IOException e) {
+                    Debug.reportError("Warning: Unable to create debug log file.");
+                }
+            }
+        }
+        
+        // We get here if:
+        // - we are on the debug VM (and in Greenfoot) or
+        // - bluej.debug=true or
+        // - creating the debug log failed
+        Debug.setDebugStream(new OutputStreamWriter(System.out));
+    }
+    
+    /**
+     * Called on system exit. Do whatever there is to do before exiting.
+     */
+    public static void handleExit()
+    {
+        final String name = getApplicationName().toLowerCase();
+        saveProperties(name, "properties.heading." + name, userProps);     
+        saveProperties("moe", "properties.heading.moe", moeUserProps);    
+    }
+
+    /**
+     * Load a BlueJ definition file. This creates a new properties object.
+     * The new properties object can be returned directly, or an empty
+     * properties object can be returned that has the named definitions as
+     * defaults.
+     *
+     * @param filename  the properties file
+     */
+    private static Properties loadDefs(String filename, Properties parentProperties)
+    {
+        File propsFile = new File(bluejLibDir, filename);
+        Properties defs = new Properties(parentProperties);
+
+        try {
+            defs.load(new FileInputStream(propsFile));
+        }
+        catch(Exception e) {
+            Debug.reportError("Unable to load definitions file: " + propsFile);
+        }
+
+        return defs;
+    }
+    
+    /**
+     * Load the label property file for the currently defined language.
+     * Install the default language (English) as the default properties
+     * as a fallback.
+     */
+    private static Properties loadLanguageLabels(String language)
+    {
+        // add the defaults (English)
+        Properties labels = loadDefs(DEFAULT_LANGUAGE + File.separator + "labels", System.getProperties());
+        // if greenfoot, add specific additional labels
+        if(isGreenfoot())
+        {
+            // load greenfoot labels to default lanbels
+            String greenfootLabels = DEFAULT_LANGUAGE + File.separator + "greenfoot/greenfoot-labels";
+            File greenfootLabelFile = new File(bluejLibDir, greenfootLabels);
+            try{
+                labels.load(new FileInputStream(greenfootLabelFile));
+            }
+            catch(Exception e){
+                Debug.reportError("Unable to load greenfoot labels file: " + greenfootLabelFile);
+            }
+        }
+        // add localised labels if necessary...
+        if(!DEFAULT_LANGUAGE.equals(language)) {
+            String languageFileName = language + File.separator + "labels";
+            File languageFile = new File(bluejLibDir, languageFileName);
+            try{
+                labels.load(new FileInputStream(languageFile));
+            }
+            catch(Exception e){
+                Debug.reportError("Unable to load definitions file: " + languageFile);
+            }
+            if(isGreenfoot()) {
+                File greenfootLabels = new File(bluejLibDir, language + File.separator + "greenfoot/greenfoot-labels");
+                try{
+                    labels.load(new FileInputStream(greenfootLabels));
+                }
+                catch(Exception e){
+                    Debug.reportError("Unable to load greenfoot labels file: " + greenfootLabels);
+                }
+            }
+        }
+        return labels;
+    }
+
+    /**
+     * Load local BlueJ properties. The properties definitions override
+     * the defaults found in the definitions file.
+     */
+    private static void loadProperties(String filename, Properties props)
+    {
+        File propsFile = new File(userPrefDir, filename + ".properties");
+
+        try {
+            props.load(new FileInputStream(propsFile));
+        }
+        catch(IOException e) {
+            // ignore exception - this will hapen on first run of BlueJ
+        }
+    }
+
+    /**
+     * Save user specific (local) BlueJ properties.
+     */
+    private static void saveProperties(String filename, String comment, Properties props)
+    {
+        File propsFile = new File(userPrefDir, filename + ".properties");
+
+        try {
+            props.store(new FileOutputStream(propsFile), getString(comment));
+        }
+        catch(IOException e) {
+            Debug.reportError("could not save properties file " + propsFile);
+        }
+    }
+
+    /**
+     * Find and return the moe help definitions
+     */
+    public static Properties getMoeHelp()
+    {
+        return loadDefs(language + File.separator + "moe.help", System.getProperties());
+    }
+    
+    /**
+     * Get a string from the language dependent definitions file
+     * (eg. "english/labels").
+     */
+    public static String getString(String strname)
+    {
+        return getString(strname, strname);
+    }
+
+    /**
+     * Get a string from the language dependent definitions file
+     * (eg. "english/labels"). If not found, return default.
+     */
+    public static String getString(String strname, String def)
+    {
+        if (langVarProps == null) {
+            langVarProps = new Properties();
+            langVarProps.put("APPNAME", getApplicationName());
+        }
+        
+        int index;
+        String str = langProps.getProperty(strname, def);
+        // remove all underscores
+        while( (index = str.indexOf('_')) != -1){
+            str = str.substring(0, index) + str.substring(index+1);
+        }
+        if ((index = str.indexOf('@')) != -1){ 
+            //remove everything from @
+            str = str.substring(0, index);
+        }
+        
+        str = PropParser.parsePropString(str, langVarProps);
+        
+        return str;
+    }
+    
+    
+    /**
+     * Get the mnemonic key for a particular label by looking for an underscore
+     * and using the character right after the underscore as the mnemonic key.
+     * 
+     * @param strname The label name
+     * @return Mnemonic or KeyEvent.VK_UNDEFINED if none found.
+     */
+    public static int getMnemonicKey(String strname)
+    {
+        int mnemonic;
+        String str = langProps.getProperty(strname, strname);
+        int index = str.indexOf('_');
+        if (index == -1 || (index + 1) >= str.length()) {
+            mnemonic = KeyEvent.VK_UNDEFINED;
+        }
+        else {
+            mnemonic = str.codePointAt(index + 1);
+        }
+        return mnemonic;
+    }
+    
+    
+    /**
+     * Check whether a particular label has an accelerator key defined.
+     * @param strname  The label name to check
+     * @return     True if an accelerator key is defined
+     */
+    public static boolean hasAcceleratorKey(String strname)
+    {
+        return langProps.getProperty(strname, strname).indexOf('@') != -1;
+    }    
+    
+    /**
+     * parses the labels file and creates a KeyStroke with the right accelerator
+     * key and modifiers
+     * @param strname
+     * @return a KeyStroke
+     */
+    public static KeyStroke getAcceleratorKey(String strname)
+    {
+        int index;
+        int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+        String str = langProps.getProperty(strname, strname);
+        String keyString;
+        index = str.indexOf('@');
+        index++;
+        if(str.charAt(index) == '^') { //then the modifiers is CTRL + SHIFT
+            index++;
+            modifiers |= KeyEvent.SHIFT_MASK;
+        }
+        keyString = str.substring(index).toUpperCase();
+        if(keyString.length() == 1) {
+            return KeyStroke.getKeyStroke(keyString.codePointAt(0), modifiers);
+        }
+        else {
+            KeyStroke k1= KeyStroke.getKeyStroke(keyString);
+            return KeyStroke.getKeyStroke(k1.getKeyCode(), modifiers);
+        }
+    }
+    
+    /**
+     * Get a system-dependent string from the BlueJ properties
+     * System-dependent strings are properties that can
+     * start with an OS ID prefix (though it will default to
+     * finding just the plain property name in the case where the
+     * system id'ed version does not exist).
+     * Returns null if the property does not exist
+     */
+    public static String getSystemPropString(String propName)
+    {
+        String sysID;
+
+        if (osname != null && osname.startsWith("Windows 9")) {    // win95/98
+            sysID = "win9x";
+        }
+        else if (osname != null && osname.equals("Windows Me")) { // winME (same as 95/98)
+            sysID = "win9x";
+        }
+        else if (osname != null && osname.startsWith("Windows")) { // NT/2000/XP
+            sysID = "win";
+        }
+        else if (osname != null && osname.startsWith("Linux")) {    // Linux
+            sysID = "linux";
+        }
+        else if (osname != null && osname.startsWith("SunOS")) {   // Solaris
+            sysID = "solaris";
+        }
+        else if (osname != null && osname.startsWith("Mac")) {     // MacOS
+            sysID = "macos";
+        }
+        else {
+            sysID = "";
+        }
+
+        // try to find it using the sysId prefix
+        String value = commandProps.getProperty(sysID + propName);
+
+        // if that failed, just look for the plain property value
+        if(value == null) {
+            value = commandProps.getProperty(propName);
+        }
+
+        return value;
+    }
+
+    /**
+     * Get a non-language-dependent string from the BlueJ properties
+     * ("bluej.defs" or "bluej.properties"). If not defined, the property
+     * name is returned unchanged.
+     */
+    public static String getPropString(String strname)
+    {
+        // Don't pass strname as the second parameter to getPropString, or
+        // variable substitution will be performed.
+        String rval = getPropString(strname, null);
+        if (rval == null) {
+            rval = strname;
+        }
+        return rval;
+    }
+
+    /**
+     * Get a non-language-dependent string from the BlueJ properties
+     * ("bluej.defs" or "bluej.properties") with a default value. Variable
+     * substitution ($varname) is performed on the value (and will be
+     * performed on the default value if that is used).
+     */
+    public static String getPropString(String strname, String def)
+    {
+        return getPropString(strname, def, commandProps);
+    }
+    
+    /**
+     * Get a property string from the given properties map, using variable substitution.
+     * If the variable is not defined the given default value is used (and variable
+     * substitution is performed on it).
+     * 
+     * @param strname  The name of the property thats value is to be retrieved
+     * @param def      The default value to use if the value is not defined
+     * @param props    The properties to retrieve the value from
+     * @return  The property value after variable substitution
+     */
+    public static String getPropString(String strname, String def, Properties props)
+    {
+        String propVal = props.getProperty(strname, def);
+        if (propVal == null) {
+            propVal = def;
+        }
+        if (propVal != null) {
+            return PropParser.parsePropString(propVal, props);
+        }
+        else {
+            return null;
+        }
+    }
+    
+    /**
+     * Get a non-language-dependent string from the BlueJ properties
+     * "bluej.defs" with a default value. No variable substitution is
+     * performed.
+     */
+    public static String getDefaultPropString(String strname, String def)
+    {
+        return systemProps.getProperty(strname, def);
+    }
+
+    /**
+     * Get a non-language dependant integer from the BlueJ properties
+     * ("bluej.defs" or "bluej.properties") with a default value
+     */
+    public static int getPropInteger(String intname, int def)
+    {
+        int value;
+        try {
+            value = Integer.parseInt(getPropString(intname, String.valueOf(def)));
+        }
+        catch(NumberFormatException nfe) {
+            return def;
+        }
+        return value;
+    }
+
+    /**
+     * Get a boolean value from the BlueJ properties. The default value is false.
+     */
+    public static boolean getPropBoolean(String propname)
+    {
+        return parseBoolean(getPropString(propname, null));
+    }    
+    
+    /**
+     * Get a boolean value from the BlueJ properties, with the specified default.
+     */
+    public static boolean getPropBoolean(String propname, boolean def)
+    {
+        String propval = getPropString(propname);
+        if (propval == null) {
+            return def;
+        }
+        else {
+            return parseBoolean(propval);
+        }
+    }
+    
+    /**
+     * Parses the string argument as a boolean.  The <code>boolean</code> 
+     * returned represents the value <code>true</code> if the string argument 
+     * is not <code>null</code> and is equal, ignoring case, to the string 
+     * <code>"true"</code>.
+     *
+     * @param      s   the <code>String</code> containing the boolean
+     *                 representation to be parsed
+     * @return     the boolean represented by the string argument
+     */
+    private static boolean parseBoolean(String s) {
+        return ((s != null) && s.equalsIgnoreCase("true"));
+    }
+    
+    /**
+     * remove a property value from the BlueJ properties.
+     */
+    public static String removeProperty(String propertyName)
+    {
+        return (String)(userProps.remove(propertyName));
+    }
+
+    /**
+     * Find and return the file name for an image.
+     */
+    private static File getImageFile(String propname)
+    {
+        String filename = getPropString(propname, null);
+
+        if (filename != null) {
+            return new File(bluejLibDir, "images" + File.separator + filename);
+        }
+
+        return null;
+    }
+
+    /**
+     * Find and return the icon for an image, using the definitions in the 
+     * properties files to find the actual image.
+     */
+    public static ImageIcon getImageAsIcon(String propname)
+    {
+        try {
+            java.net.URL u = getImageFile(propname).toURI().toURL();
+            return new ImageIcon(u);
+        }
+        catch (java.net.MalformedURLException mue) { }
+        catch (NullPointerException npe) { }
+        return null;
+    }
+    
+    /**
+     * Return an icon for an image file name, without going through bluej.defs.
+     * The parameter specifies the final image name, not a property.
+     */
+    public static ImageIcon getFixedImageAsIcon(String filename)
+    {
+        File image = new File(bluejLibDir, "images" + File.separator + filename);
+        try {
+            return new ImageIcon(image.toURI().toURL());
+        }
+        catch (java.net.MalformedURLException mue) { }
+        catch (NullPointerException npe) { }
+        return null;
+    }
+
+    /**
+     * Find and return the icon for an image, without using the properties
+     * (the name provided is the actual file name in ../lib/images).
+     */
+    public static ImageIcon getHardImageAsIcon(String filename)
+    {
+        try {
+            File imgFile = new File(bluejLibDir, "images" + File.separator + filename);
+            java.net.URL u = imgFile.toURI().toURL();
+
+            return new ImageIcon(u);
+        }
+        catch (java.net.MalformedURLException mue) { }
+        catch (NullPointerException npe) { }
+        return null;
+    }
+    
+    /**
+     * Find and return an image. The image will have to be tracked. 
+     */
+    public static Image getImage(String propname)
+    {
+        try {
+            java.net.URL u = getImageFile(propname).toURI().toURL();
+            return Toolkit.getDefaultToolkit().createImage(u);
+        }
+        catch (java.net.MalformedURLException mue) { }
+        catch (NullPointerException npe) { }        
+        return null;
+    }
+
+    /**
+     * Find the path to an executable command that may be located
+     * in the JDK bin directory, and whose location may optionally
+     * be explicitly specified in the properties.
+     *
+     * The logic goes like this: some tools such as javac, appletviewer
+     * etc should be run from the same bin directory as the JDK that
+     * launched bluej (rather than the first one in the path which may
+     * be of a different version). So for all these properties, if the
+     * property DOES NOT exist, we try to locate the executable in the
+     * JDK directory and if we can't find it we use just the command
+     * name.
+     * 
+     * If the property DOES exist we return it and it will be resolved
+     * by the Runtime.exec call (ie looked for in the current path if
+     * the command name is not an absolute path). The specified property
+     * may be null, in which case the property is assumed not to exist.
+     *
+     * This method never returns null (at the very least it returns the
+     * executableName)
+     */
+    public static String getJDKExecutablePath(String propName, String executableName)
+    {
+        if (executableName == null)
+            throw new IllegalArgumentException("must provide an executable name");
+
+        String p = propName == null ? null : getSystemPropString(propName);
+
+        if (p == null) {
+            // look for it in the JDK bin directory
+            String jdkPathName = System.getProperty("java.home");
+
+            if (jdkPathName != null) {
+                // first check the closest bin directory
+                File jdkPath = new File(jdkPathName);
+                File binPath = new File(jdkPath, "bin");
+
+                // try to find normal (unix??) executable
+                File potentialExe = new File(binPath, executableName);
+                if(potentialExe.exists())
+                    return potentialExe.getAbsolutePath();
+                
+                // try to find windows executable
+                potentialExe = new File(binPath, executableName + ".exe");
+                if(potentialExe.exists())
+                    return potentialExe.getAbsolutePath();
+
+                // we could be in a JRE directory INSIDE a JDK directory
+                // so lets go up one level and try again
+                jdkPath = jdkPath.getParentFile();
+                if (jdkPath != null) {
+                    binPath = new File(jdkPath, "bin");
+
+                    // try to find normal (unix??) executable
+                    potentialExe = new File(binPath, executableName);
+                    if(potentialExe.exists())
+                        return potentialExe.getAbsolutePath();
+                        // try to find windows executable
+                        potentialExe = new File(binPath, executableName + ".exe");
+                        if(potentialExe.exists())
+                            return potentialExe.getAbsolutePath();
+                }
+            }
+
+            return executableName;
+        }
+
+        return p;
+    }
+
+    /**
+     * Return the template directory.
+     */
+    public static File getTemplateDir()
+    {
+        return getLanguageFile("templates");
+    }
+
+    /**
+     * Find and return the file name for a class template file
+     * Format: <template-dir>/<base>.tmpl
+     */
+    public static File getTemplateFile(String base)
+    {
+        return new File(getTemplateDir(), base + ".tmpl");
+    }
+
+    /**
+     * Return the template directory.
+     */
+    public static File getClassTemplateDir()
+    {
+        String path = commandProps.getProperty("bluej.templatePath" , "");
+        if(path.length() == 0)
+            return getLanguageFile("templates/newclass");
+        else
+            return new File(path);
+    }
+
+    /**
+     * Find and return the file name for a class template file
+     * Format: <template-dir>/<base>.tmpl
+     */
+    public static File getClassTemplateFile(String base)
+    {
+        return new File(getClassTemplateDir(), base + ".tmpl");
+    }
+
+    /**
+     * Return the file with language specific text. 
+     * For example,
+     * <CODE>bluej/lib/english/dialogs</CODE> if base is <CODE>dialogs</CODE>
+     * and the current language is <CODE>english</CODE>.
+     */
+    public static File getLanguageFile(String base)
+    {
+        return new File(bluejLibDir, language + File.separator + base);
+    }
+    
+    /**
+     * return the default language version of a language resource file
+     */
+    public static File getDefaultLanguageFile(String base)
+    {
+        return new File(bluejLibDir, DEFAULT_LANGUAGE + File.separator + base);
+    }
+
+    /**
+     * Return the file name for a file in the user config directory
+     * (<user_home>/.bluej/<base>)
+     */
+    public static File getUserConfigFile(String base)
+    {
+        return new File(userPrefDir, base);
+    }
+
+    /**
+     * Return the user config directory
+     * (<user_home>/.bluej)
+     */
+    public static File getUserConfigDir()
+    {
+        return userPrefDir;
+    }
+
+    /**
+     * Return a color value from the bluej properties.
+     */
+    public static Color getItemColour(String itemname)
+    {
+        try {
+            String rgbStr = getPropString(itemname, "255,0,255");
+            String rgbVal[] = Utility.split(rgbStr, ",");
+
+            if (rgbVal.length < 3)
+                Debug.reportError("Error reading colour ["+itemname+"]");
+            else {
+                int r = Integer.parseInt(rgbVal[0].trim());
+                int g = Integer.parseInt(rgbVal[1].trim());
+                int b = Integer.parseInt(rgbVal[2].trim());
+
+                return new Color(r, g, b);
+            }
+        }
+        catch(Exception e) {
+            Debug.reportError("Could not get colour for " + itemname);
+        }
+
+        return null;
+    }
+    
+    /**
+     * Return a color value from the bluej properties.
+     * 
+     * If the value is not present, return null
+     */
+    public static Color getOptionalItemColour(String itemname)
+    {
+        try {
+            String rgbStr = getPropString(itemname, null);
+            if (rgbStr == null) {
+                return null;
+            } else {
+                String rgbVal[] = Utility.split(rgbStr, ",");
+
+                if (rgbVal.length < 3)
+                    Debug.reportError("Error reading colour ["+itemname+"]");
+                else {
+                    int r = Integer.parseInt(rgbVal[0].trim());
+                    int g = Integer.parseInt(rgbVal[1].trim());
+                    int b = Integer.parseInt(rgbVal[2].trim());
+
+                    return new Color(r, g, b);
+                }
+            }
+        }
+        catch(Exception e) {
+            Debug.reportError("Could not get colour for " + itemname);
+        }
+
+        return null;
+    }
+    
+    /**
+     * Return a color value for selections.
+     */
+    public static Color getSelectionColour()
+    {
+        if(selectionColour == null) {
+            selectionColour = Config.getItemColour("colour.selection");
+        }
+        return selectionColour;
+    }
+
+    /**
+     * Return the second (gradient) color value for selections.
+     */
+    public static Color getSelectionColour2()
+    {
+        if(selectionColour2 == null) {
+            selectionColour2 = Config.getItemColour("colour.selection2");
+        }
+        return selectionColour2;
+    }
+
+    /**
+     * Return a color value for selections.
+     */
+    public static Color getHighlightColour()
+    {
+        if(highlightColour == null) {
+            highlightColour = Config.getItemColour("colour.highlight");
+        }
+        return highlightColour;
+    }
+
+    /**
+     * Return the second (gradient) color value for selections.
+     */
+    public static Color getHighlightColour2()
+    {
+        if(highlightColour2 == null) {
+            highlightColour2 = Config.getItemColour("colour.highlight2");
+        }
+        return highlightColour2;
+    }
+
+    /**
+     * Get a font from a specified property, using the given default font name and
+     * the given size. Font name can end with "-bold" to indicate bold style.
+     */
+    public static Font getFont(String propertyName, String defaultFontName, int size)
+    {
+        String fontName = getPropString(propertyName, defaultFontName);
+        
+        int style;
+        if(fontName.endsWith("-bold")) {
+            style = Font.BOLD;
+            fontName = fontName.substring(0, fontName.length()-5);
+        }
+        else {
+            style = Font.PLAIN;
+        }
+        
+        return new Font(fontName, style, size);
+    }
+    
+    /**
+     * Store a point in the config files. The config properties
+     * are formed by adding ".x" and ".y" to the itemPrefix.
+     */
+    public static void putLocation(String itemPrefix, Point p)
+    {
+        putPropInteger(itemPrefix + ".x", p.x);
+        putPropInteger(itemPrefix + ".y", p.y);
+    }
+
+    /**
+     * Return a point, read from the config files. The config properties
+     * are formed by adding ".x" and ".y" to the itemPrefix.
+     */
+    public static Point getLocation(String itemPrefix)
+    {
+        try {
+            int x = getPropInteger(itemPrefix + ".x", 16);
+            int y = getPropInteger(itemPrefix + ".y", 16);
+
+            if (x > (screenBounds.width - 16))
+                x = screenBounds.width - 16;
+
+            if (y > (screenBounds.height - 16))
+                y = screenBounds.height - 16;
+
+            return new Point(x,y);
+        }
+        catch(Exception e) {
+            Debug.reportError("Could not get screen location for " + itemPrefix);
+        }
+
+        return new Point(16,16);
+    }
+
+    /**
+     * Set a non-language dependant integer for the BlueJ properties
+     */
+    public static void putPropInteger(String intname, int value)
+    {
+        String defVal = systemProps.getProperty(intname);
+        if (defVal != null) {
+            try {
+                if (value == Integer.valueOf(defVal).intValue()) {
+                    userProps.remove(intname);
+                }
+            }
+            catch (NumberFormatException nfe) { }
+        }
+        userProps.setProperty(intname, Integer.toString(value));
+    }
+
+    /**
+     * Set a non-language dependant string for the BlueJ properties.
+     * If the supplied value is null, the property is removed.
+     */
+    public static void putPropString(String strname, String value)
+    {
+        String defVal = systemProps.getProperty(strname);
+        if (value != null && (defVal == null || ! defVal.equals(value))) {
+            userProps.setProperty(strname, value);
+        }
+        else {
+            userProps.remove(strname);
+        }
+    }
+    
+    /**
+     * Set a non-language dependent boolean value for the BlueJ properties
+     */
+    public static void putPropBoolean(String propname, boolean value)
+    {
+        String sysval = systemProps.getProperty(propname);
+        if (Boolean.valueOf(sysval).booleanValue() == value) {
+            userProps.remove(propname);
+        }
+        else {
+            userProps.setProperty(propname, String.valueOf(value));
+        }
+    }
+    
+    /**
+     * Returns the blueJLibDir
+     */
+    public static File getBlueJLibDir()
+    {
+        return bluejLibDir;
+    }
+    
+    /**
+     * Returns the greenfoot directory in blueJLibDir
+     */
+    public static File getGreenfootLibDir()
+    {
+        return greenfootLibDir;
+    }
+
+    /**
+     * Returns the blueJLibDir
+     */
+    public static String getBlueJIconPath()
+    {
+        return bluejLibDir.getPath() + "/images";
+    }
+    
+    /**
+     * Checks for optional bluej.defs settings for vm language and
+     * country. If either are specified, a Locale object is created
+     * and it becomes the default locale for BlueJ. 
+     */
+    private static void setVMLocale()
+    {
+        String lang = Config.getPropString("vm.language", null);
+        String region = Config.getPropString("vm.country", null);
+        
+        // nothing specified, its either commented out or no value 
+        if((lang == null || "".equals(lang)) && (region == null || "".equals(region)))
+            return;
+        
+        // something has been specified...
+        // if only one of region or language is specified only, make the other
+        // use the existing default to create the Locale object
+        // This gets rid of any dependencies in bluej.defs between the two
+        // which is a possible cause of config errors for users
+        if(lang == null || lang.equals(""))
+            lang = System.getProperty("user.language");
+        if(region == null || region.equals(""))
+            region = System.getProperty("user.country");
+        debugVMArgs.add("-Duser.language=" + lang);
+        debugVMArgs.add("-Duser.country=" + region);
+        Locale loc = new Locale(lang, region);
+        Locale.setDefault(loc);
+    }
+    
+    /**
+     * Set Look and Feel for BlueJ interface
+     * @param laf the l&f specified. Should be one of 3 options:
+     * "system", "crossplatform" or "default"
+     */
+    private static void setLookAndFeel(String laf)
+    {
+        try {
+            if (laf.equals("default")) {
+                return;
+            }
+            
+            // if system specified
+            if(laf.equals("system")) {
+                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+                return;
+            }
+            else if(laf.equals("crossplatform")) {
+                UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
+                usingMacOSScreenMenubar = false; // Screen menu bar requires aqua look-and-feel
+                return;
+            }
+            
+            if (! laf.equals("bluejdefault")) {
+                LookAndFeelInfo [] lafi = UIManager.getInstalledLookAndFeels();
+                for (int i = 0; i < lafi.length; i++) {
+                    if (lafi[i].getName().equals(laf)) {
+                        UIManager.setLookAndFeel(lafi[i].getClassName());
+                        return;
+                    }
+                }
+                
+                // Try as a class name
+                UIManager.setLookAndFeel(laf);
+                return;
+            }
+            
+            // do the "default, ie. let BlueJ decide
+            // Windows - System l&F, Linux & Solaris - cross-platform
+            if (isWinOS()){
+                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+            }
+            // treat Linux and Solaris the same at the moment
+            else if(isLinux() || isSolaris()) {
+                LookAndFeelInfo [] lafi = UIManager.getInstalledLookAndFeels();
+                LookAndFeelInfo nimbus = null;
+                for (LookAndFeelInfo lafInstance : lafi) {
+                    if (lafInstance.getName().equals("Nimbus")) {
+                        nimbus = lafInstance;
+                        break;
+                    }
+                }
+                
+                if (nimbus != null) {
+                    UIManager.setLookAndFeel(nimbus.getClassName());
+                }
+                else {
+                    UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
+                }
+            }
+        } catch (ClassNotFoundException e) {
+            Debug.log("Could not find look-and-feel class: " + e.getMessage());
+        } catch (InstantiationException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (UnsupportedLookAndFeelException e) {
+            Debug.log("Unsupported look-and-feel: " + e.getMessage());
+        }
+    }
+    
+    /**
+     * Initialise debug VM args from bluej config file
+     * Should only be called once in Config.initialise(...)
+     */
+    private static void initDebugVMArgs()
+    {
+        String args = getPropString("bluej.vm.args");
+        if(args != null && !args.equals("bluej.vm.args")) {
+            // if there is more than one arg set
+            List<String> splitArgs = Utility.dequoteCommandLine(args);
+            debugVMArgs.addAll(splitArgs);
+        }        
+    }
+    
+    /**
+     * debug vm args used for launch of debug vm
+     */
+    public static List<String> getDebugVMArgs()
+    {
+        return debugVMArgs;
+    }
+    
+    /**
+     * Method to determine if BlueJ is running in greenfoot mode. Greenfoot mode
+     * is used when we are launching BlueJ to be used for greenfoot.
+     * 
+     * To switch on greenfoot mode the property greenfoot should be set to true.
+     * This can be done by starting BlueJ with this command line argument
+     * -greenfoot=true
+     */
+    public static final boolean isGreenfoot()
+    {
+        return isGreenfoot;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/GreenfootLabel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/GreenfootLabel.java
new file mode 100644
index 0000000000000000000000000000000000000000..4410e7d191e090b537bc113d73929be3c28211d5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/GreenfootLabel.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+
+/**
+ * Label used for the SplashWindow for greenfoot.
+ * 
+ * @author Poul Henriksen
+ */
+public class GreenfootLabel extends SplashLabel
+{
+    public GreenfootLabel()
+    {
+        super("greenfootsplash.jpg");
+    }
+
+    public void paintComponent(Graphics g)
+    {
+        BufferedImage image = getImage();
+        g.drawImage(image, 0, 0, null);
+        g.setColor(new Color(164, 198, 102));
+        g.setFont(new Font("SansSerif", Font.PLAIN, 14));
+        if (g instanceof Graphics2D) {
+            Graphics2D g2d = (Graphics2D)g;
+            RenderingHints hints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING,
+                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+            g2d.addRenderingHints(hints);
+        }
+        g.drawString("Version " + Boot.GREENFOOT_VERSION, 50, 192);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/Main.java b/Sd1/P/Maven/bluej/src/main/java/bluej/Main.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3d7acf8a09e89a5fb4967cb28c4f098dd070893
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/Main.java
@@ -0,0 +1,441 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+import java.awt.EventQueue;
+import java.io.File;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Properties;
+import java.util.UUID;
+
+import com.apple.eawt.Application;
+import com.apple.eawt.AppEvent;
+import com.apple.eawt.QuitResponse;
+
+import bluej.extensions.event.ApplicationEvent;
+import bluej.extmgr.ExtensionsManager;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.actions.HelpAboutAction;
+import bluej.pkgmgr.actions.PreferencesAction;
+import bluej.pkgmgr.actions.QuitAction;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import java.util.List;
+
+/**
+ * BlueJ starts here. The Boot class, which is responsible for dealing with
+ * specialised class loaders, constructs an object of this class to initiate the
+ * "real" BlueJ.
+ * 
+ * @author Michael Kolling
+ */
+public class Main
+{
+    private static final int FIRST_X_LOCATION = 20;
+    private static final int FIRST_Y_LOCATION = 20;
+    
+    /** 
+     * Whether we've officially launched yet. While false "open file" requests only
+     * set initialProject.
+     */
+    private static boolean launched = false;
+    
+    /** On MacOS X, this will be set to the project we should open (if any) */ 
+    private static List<File> initialProjects;
+
+    private static QuitResponse macEventResponse = null;  // used to respond to external quit events on MacOS
+
+    /**
+     * Entry point to starting up the system. Initialise the system and start
+     * the first package manager frame.
+     */
+    public Main()
+    {
+        Boot boot = Boot.getInstance();
+        final String[] args = boot.getArgs();
+        Properties commandLineProps = boot.getCommandLineProperties();
+        File bluejLibDir = Boot.getBluejLibDir();
+
+        Config.initialise(bluejLibDir, commandLineProps, boot.isGreenfoot());
+        
+        // Note we must do this OFF the AWT dispatch thread. On MacOS X, if the
+        // application was started by double-clicking a project file, an "open file"
+        // event will be generated once we add a listener and will be delivered on
+        // the dispatch thread. It will then be processed before the call to
+        // processArgs() (just below) is called.
+        if (Config.isMacOS())
+            prepareMacOSApp();
+        
+        // process command line arguments, start BlueJ!
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run()
+            {
+                processArgs(args);
+            }
+        });
+        
+        // Send usage data back to bluej.org
+        new Thread() {
+            @Override
+            public void run()
+            {
+                updateStats();
+            }
+        }.start();
+    }
+
+    /**
+     * Start everything off. This is used to open the projects specified on the
+     * command line when starting BlueJ. Any parameters starting with '-' are
+     * ignored for now.
+     */
+    private static void processArgs(String[] args)
+    {
+        if (Config.isGreenfoot()) {
+            // Avoid having to put the Greenfoot classes on the system classpath:
+            // (only an issue with JDK 7u21, 6u45, and later).
+            System.setProperty("java.rmi.server.useCodebaseOnly", "false");
+        }
+        
+        launched = true;
+        
+        boolean oneOpened = false;
+
+        // Open any projects specified on the command line
+        if (args.length > 0) {
+            for (int i = 0; i < args.length; i++) {
+                if (!args[i].startsWith("-")) {
+                    if(PkgMgrFrame.doOpen(new File(args[i]), null)) {
+                        oneOpened = true;                        
+                    }
+                }
+            }
+        }
+        
+        // Open a project if requested by the OS (Mac OS)
+        if (initialProjects != null) {
+            for (File initialProject : initialProjects) {
+                oneOpened |= (PkgMgrFrame.doOpen(initialProject, null));
+            }
+        }
+
+        // if we have orphaned packages, these are re-opened
+        if (!oneOpened) {
+            // check for orphans...
+            boolean openOrphans = "true".equals(Config.getPropString("bluej.autoOpenLastProject"));
+            if (openOrphans && hadOrphanPackages()) {
+                String exists = "";
+                // iterate through unknown number of orphans
+                for (int i = 1; exists != null; i++) {
+                    exists = Config.getPropString(Config.BLUEJ_OPENPACKAGE + i, null);
+                    if (exists != null) {
+                        Project openProj;
+                        // checking all is well (project exists)
+                        if ((openProj = Project.openProject(exists, null)) != null) {
+                            Package pkg = openProj.getPackage(openProj.getInitialPackageName());
+                            PkgMgrFrame.createFrame(pkg);
+                            oneOpened = true;
+                        }
+                    }
+                }
+            }
+        }
+
+        // Make sure at least one frame exists
+        if (!oneOpened) {
+            if (Config.isGreenfoot()) {
+                // Handled by Greenfoot
+            }
+            else {
+                openEmptyFrame();
+            }
+        }
+
+        Boot.getInstance().disposeSplashWindow();
+        ExtensionsManager.getInstance().delegateEvent(new ApplicationEvent(ApplicationEvent.APP_READY_EVENT));
+    }
+
+    /**
+     * Prepare MacOS specific behaviour (About menu, Preferences menu, Quit
+     * menu)
+     */ 
+    private static void prepareMacOSApp()
+    {
+        Application macApp = Application.getApplication();
+
+        if (macApp != null) {
+
+            macApp.setAboutHandler(new com.apple.eawt.AboutHandler() {
+                @Override
+                public void handleAbout(AppEvent.AboutEvent e)
+                {
+                    HelpAboutAction.getInstance().actionPerformed(PkgMgrFrame.getMostRecent());
+                }
+            });
+
+            macApp.setPreferencesHandler(new com.apple.eawt.PreferencesHandler() {
+                @Override
+                public void handlePreferences(AppEvent.PreferencesEvent e)
+                {
+                    PreferencesAction.getInstance().actionPerformed(PkgMgrFrame.getMostRecent());
+                }
+            });
+
+            macApp.setQuitHandler(new com.apple.eawt.QuitHandler() {
+                @Override
+                public void handleQuitRequestWith(AppEvent.QuitEvent e, QuitResponse response)
+                {
+                    macEventResponse = response;
+                    QuitAction.getInstance().actionPerformed(PkgMgrFrame.getMostRecent());
+                    // response.confirmQuit() does not need to be called, since System.exit(0) is called explcitly
+                    // response.cancelQuit() is called to cancel (in wantToQuit())
+                }
+            });
+
+            macApp.setOpenFileHandler(new com.apple.eawt.OpenFilesHandler() {
+                @Override
+                public void openFiles(AppEvent.OpenFilesEvent e)
+                {
+                    if (launched) {
+                        List<File> files = e.getFiles();
+                        for(File file : files) {
+                            PkgMgrFrame.doOpen(file, null);
+                        }
+                    }
+                    else {
+                        initialProjects = e.getFiles();
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * Quit menu item was chosen.
+     */
+    public static void wantToQuit()
+    {
+        int answer = 0;
+        if (Project.getOpenProjectCount() > 1)
+            answer = DialogManager.askQuestion(PkgMgrFrame.getMostRecent(), "quit-all");
+        if (answer == 0) {
+            doQuit();
+        }
+        else {
+            if(macEventResponse != null) {
+                macEventResponse.cancelQuit();
+                macEventResponse = null;
+            }
+        }
+    }
+
+
+    /**
+     * perform the closing down and quitting of BlueJ. Note that the order of
+     * the events is relevant - Extensions should be unloaded after package
+     * close
+     */
+    public static void doQuit()
+    {
+        PkgMgrFrame[] pkgFrames = PkgMgrFrame.getAllFrames();
+
+        // handle open packages so they are re-opened on startup
+        handleOrphanPackages(pkgFrames);
+
+        // We replicate some of the behaviour of doClose() here
+        // rather than call it to avoid a nasty recursion
+        for (int i = pkgFrames.length - 1; i >= 0; i--) {
+            PkgMgrFrame aFrame = pkgFrames[i];
+            aFrame.doSave();
+            aFrame.closePackage();
+            PkgMgrFrame.closeFrame(aFrame);
+        }
+
+        ExtensionsManager extMgr = ExtensionsManager.getInstance();
+        extMgr.unloadExtensions();
+        bluej.Main.exit();
+    }
+
+    /**
+     * When bluej is exited with open packages we want it to open these the next
+     * time that is started (this is default action, can be changed by setting
+     *
+     * @param openFrames
+     */
+    private static void handleOrphanPackages(PkgMgrFrame[] openFrames)
+    {
+        // if there was a previous list, delete it
+        if (hadOrphanPackages())
+            removeOrphanPackageList();
+        // add an entry for each open package
+        for (int i = 0; i < openFrames.length; i++) {
+            PkgMgrFrame aFrame = openFrames[i];
+            if (!aFrame.isEmptyFrame()) {
+                Config.putPropString(Config.BLUEJ_OPENPACKAGE + (i + 1), aFrame.getPackage().getPath().toString());
+            }
+        }
+    }
+
+    /**
+     * Checks if there were orphan packages on last exit by looking for
+     * existence of a valid BlueJ project among the saved values for the
+     * orphaned packages.
+     *
+     * @return whether a valid orphaned package exist.
+     */
+    public static boolean hadOrphanPackages()
+    {
+        String dir = "";
+        // iterate through unknown number of orphans
+        for (int i = 1; dir != null; i++) {
+            dir = Config.getPropString(Config.BLUEJ_OPENPACKAGE + i, null);
+            if (dir != null) {
+                if(Project.isProject(dir)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * removes previously listed orphan packages from bluej properties
+     */
+    private static void removeOrphanPackageList()
+    {
+        String exists = "";
+        for (int i = 1; exists != null; i++) {
+            exists = Config.removeProperty(Config.BLUEJ_OPENPACKAGE + i);
+        }
+    }
+
+    /**
+     * Open a single empty bluej window.
+     */
+    private static void openEmptyFrame()
+    {
+        PkgMgrFrame frame = PkgMgrFrame.createFrame();
+        frame.setLocation(FIRST_X_LOCATION, FIRST_Y_LOCATION);
+        frame.setVisible(true);
+    }
+    
+    /**
+     * Send statistics of use back to bluej.org
+     */
+    private static void updateStats() 
+    {
+        // Platform details, first the ones which vary between BlueJ/Greenfoot
+        String uidPropName;
+        String baseURL;
+        String appVersion;
+        if (Config.isGreenfoot()) {
+            uidPropName = "greenfoot.uid";
+            baseURL = "http://stats.greenfoot.org/updateGreenfoot.php";
+            appVersion = Boot.GREENFOOT_VERSION;
+        } else {
+            uidPropName = "bluej.uid";
+            baseURL = "http://stats.bluej.org/updateBlueJ.php";
+            // baseURL = "http://localhost:8080/BlueJStats/index.php";
+            appVersion = getBlueJVersion();
+        }
+
+        // Then the common ones.
+        String language = getInterfaceLanguage();
+        String javaVersion = getJavaVersion();
+        String systemID = getOperatingSystem();
+        
+        // User uid. Use the one already stored in the Property if it exists,
+        // otherwise generate one and store it for next time.
+        String uid = Config.getPropString(uidPropName, null);
+        if (uid == null) {
+            uid = UUID.randomUUID().toString();
+            Config.putPropString(uidPropName, uid);
+        } else if (uid.equalsIgnoreCase("private")) {
+            // Allow opt-out
+            return;
+        }
+        
+        try {
+            URL url = new URL(baseURL +
+                "?uid=" + URLEncoder.encode(uid, "UTF-8") +
+                "&osname=" + URLEncoder.encode(systemID, "UTF-8") +
+                "&appversion=" + URLEncoder.encode(appVersion, "UTF-8") +
+                "&javaversion=" + URLEncoder.encode(javaVersion, "UTF-8") +
+                "&language=" + URLEncoder.encode(language, "UTF-8")
+            );
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            conn.connect();
+            int rc = conn.getResponseCode();
+            conn.disconnect();
+
+            if(rc != 200) Debug.reportError("Update stats failed, HTTP response code: " + rc);
+
+        } catch (Exception ex) {
+            Debug.reportError("Update stats failed: " + ex.getClass().getName() + ": " + ex.getMessage());
+        }
+    }
+
+    private static String getBlueJVersion()
+    {
+        return Boot.BLUEJ_VERSION;
+    }
+
+    private static String getOperatingSystem()
+    {
+        return System.getProperty("os.name") +
+                "/" + System.getProperty("os.arch") +
+                "/" + System.getProperty("os.version");
+    }
+
+    private static String getJavaVersion()
+    {
+        return System.getProperty("java.version");
+    }
+
+    private static String getInterfaceLanguage()
+    {
+        return Config.language;
+    }
+
+    /**
+     * Exit BlueJ.
+     * <p>
+     * The open frame count should be zero by this point as PkgMgrFrame is
+     * responsible for cleaning itself up before getting here.
+     */
+    private static void exit()
+    {
+        if (PkgMgrFrame.frameCount() > 0) {
+            Debug.reportError("Frame count was not zero when exiting. Work may not have been saved");
+        }
+
+        // save configuration properties
+        Config.handleExit();
+        // exit with success status
+        System.exit(0);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/PropParser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/PropParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ba57f8cc3749526b0c052e697a36dc13348d24c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/PropParser.java
@@ -0,0 +1,320 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.util.Properties;
+
+/**
+ * Handling of property value parsing - substitution of variable values etc.
+ * 
+ * <p>Variable substitution is performed for ${variableName} and $variableName -
+ * the variable name is terminated by any non-name character, but in either case a
+ * '$' escapes the next character. In the first form anything after the variable
+ * name is ignored (up to the closing '}').
+ * 
+ * <p>The double dollar sign '$$' is an escaped '$'. If a variable name begins with
+ * a dollar sign, the variable must be written as '${$$name}' where name is the part
+ * of the name after the initial dollar sign.
+ * 
+ * <p>The following functions are also supported:
+ * 
+ * <ul>
+ * <li>${filepath x y} - concatenates file paths x and y to form a complete path
+ * <li>${fileUrl x} - returns the given file path x as a file:// URL.
+ * </ul>
+ * 
+ * <p>Function arguments can contain variable/function substitutions.
+ * 
+ * @author Davin McCall
+ */
+public class PropParser
+{
+    /** The maximum depth of recursion when substituting variables */
+    private final static int MAX_DEPTH = 10;
+    
+    /**
+     * Process variable/function substitution on a property value.
+     * @param value  The property value to process
+     * @param subvars  The collection of variable-to-value mappings
+     * @return   The value after substitution
+     */
+    public static String parsePropString(String value, Properties subvars)
+    {
+        StringBuffer outBuffer = new StringBuffer();
+        parsePropString(value, outBuffer, subvars, 0);
+        return outBuffer.toString();
+    }
+    
+    private static void parsePropString(String value, StringBuffer outBuffer, Properties subvars, int depth)
+    {
+        if (depth > MAX_DEPTH) {
+            outBuffer.append(value);
+            return;
+        }
+        
+        StringIter iter = new StringIter(value);
+        
+        while (iter.hasNext()) {
+            char cc = iter.next();
+            if (cc == '$') {
+                if (iter.hasNext()) {
+                    cc = iter.next();
+                    if (cc == '$') {
+                        // double-dollar collapses to single dollar
+                        outBuffer.append('$');
+                    }
+                    else if (cc == '{') {
+                        // variable name surrounded by curly brackets
+                        processVar(iter, outBuffer, subvars, depth);
+                        while (iter.hasNext()) {
+                            cc = iter.next();
+                            if (cc == '}') {
+                                break;
+                            }
+                        }
+                    }
+                    else if (isNameChar(cc)) {
+                        // a variable name on its own
+                        iter.backup();
+                        processVar(iter, outBuffer, subvars, depth);
+                    }
+                    else {
+                        outBuffer.append('$');
+                        outBuffer.append(cc);
+                    }
+                }
+                else {
+                    outBuffer.append('$');
+                }
+            }
+            else {
+                outBuffer.append(cc);
+            }
+        }
+    }
+    
+    /**
+     * Check whether the given character is likely to be part of a property
+     * name. (Most punctuation marks are excluded).
+     */
+    private static boolean isNameChar(char cc)
+    {
+        if (Character.isWhitespace(cc)) {
+            return false;
+        }
+        if (cc == '/' || cc == '\\' || cc == '{' || cc == '}' || cc == '\"'
+            || cc == '$' || cc == '(' || cc == ')' || cc == ' ' || cc == ':') {
+            return false;
+        }
+        if (cc == ',') {
+            return false;
+        }
+        return true;
+    }
+    
+    private static void processVar(StringIter iter, StringBuffer outBuffer, Properties subvars, int depth)
+    {
+        // Get the variable or function name
+        StringBuffer varNameBuf = new StringBuffer();
+        while (iter.hasNext()) {
+            char cc = iter.next();
+            if (isNameChar(cc)) {
+                varNameBuf.append(cc);
+            }
+            else if (cc == '$' && iter.hasNext()) {
+                // '$' can be used to escape non-name characters, so that they can
+                // be used in a property name.
+                cc = iter.next();
+                varNameBuf.append(cc);
+            }
+            else {
+                iter.backup();
+                break;
+            }
+        }
+        
+        String varName = varNameBuf.toString();
+        if (varName.equals("filePath")) {
+            // File path function - concatenates directory names/paths to yield a path
+            String arg = processStringArg(iter, subvars, depth);
+            if (arg != null) {
+                File f = new File(arg);
+                do {
+                    arg = processStringArg(iter, subvars, depth);
+                    if (arg != null) {
+                        f = new File(f, arg);
+                    }
+                } while (arg != null);
+                outBuffer.append(f.getAbsolutePath());
+            }
+        }
+        else if (varName.equals("fileUrl")) {
+            // File url function - takes a file path as an argument, and converts it
+            // into a URL.
+            String arg = processStringArg(iter, subvars, depth);
+            if (arg != null) {
+                File f = new File(arg);
+                try {
+                    String fileUrl = f.toURI().toURL().toString();
+                    outBuffer.append(fileUrl);
+                }
+                catch (MalformedURLException mfue) {}
+            }
+        }
+        else {
+            // regular variable
+            String nval = subvars.getProperty(varName);
+            if (nval != null) {
+                parsePropString(nval, outBuffer, subvars, depth + 1);
+            }
+        }
+    }
+    
+    /**
+     * Process a string argument to a substitution function. Any initial leading whitespace
+     * is skipped. 
+     * 
+     * String arguments can include double-quote-enclosed literal strings, as well as
+     * unquoted characters, $-marked variable substitutions, and $-quoted special characters.
+     * They are terminated by (unquoted) whitespace or the (unquoted) '}' character.
+     * 
+     * Return is null if no argument is present ('}' is first non-whitespace character).
+     * 
+     * @param iter
+     * @return
+     */
+    private static String processStringArg(StringIter iter, Properties subvars, int depth)
+    {
+        // Skip any whitespace
+        char cc;
+        do {
+            if (! iter.hasNext()) {
+                return null;
+            }
+            cc = iter.next();
+        } while (Character.isWhitespace(cc));
+        if (cc == '}') {
+            return null;
+        }
+        
+        if (cc == '\"') {
+            // string literal, quote-enclosed
+            StringBuffer result = new StringBuffer();
+            while (iter.hasNext()) {
+                cc = iter.next();
+                if (cc == '\"') {
+                    break;
+                }
+                result.append(cc);
+            }
+            return result.toString();
+        }
+        else {
+            // String literal, not quote-enclosed, may incorporate variable names.
+            // Terminated by any unquoted whitespace character or '}'.
+            StringBuffer outBuffer = new StringBuffer();
+            iter.backup();
+            
+            do {
+                cc = iter.next();
+                if (cc == '$' && iter.hasNext()) {
+                    cc = iter.next();
+                    if (Character.isWhitespace(cc) || cc == '}' || cc == '\"') {
+                        outBuffer.append(cc);
+                    }
+                    else if (cc == '{') {
+                        // variable name surrounded by curly brackets
+                        processVar(iter, outBuffer, subvars, depth);
+                        while (iter.hasNext()) {
+                            cc = iter.next();
+                            if (cc == '}') {
+                                break;
+                            }
+                        }
+                    }
+                    else {
+                        // a variable name on its own
+                        iter.backup();
+                        processVar(iter, outBuffer, subvars, depth);
+                    }
+                }
+                else {
+                    if (Character.isWhitespace(cc) || cc == '}') {
+                        iter.backup();
+                        break;
+                    }
+                    else if (cc == '\"') {
+                        // string literal, quote-enclosed
+                        while (iter.hasNext()) {
+                            cc = iter.next();
+                            if (cc == '\"') {
+                                break;
+                            }
+                            outBuffer.append(cc);
+                        }
+                    }
+                    else {
+                        outBuffer.append(cc);
+                    }
+                }
+            }
+            while (iter.hasNext());
+            
+            return outBuffer.toString();
+        }
+    }
+    
+    /**
+     * A class for iterating through a string
+     * 
+     * @author Davin McCall
+     */
+    private static class StringIter
+    {
+        private String string;
+        private int curpos;
+        private int limit;
+        
+        StringIter(String string)
+        {
+            this.string = string;
+            limit = string.length();
+        }
+        
+        public boolean hasNext()
+        {
+            return curpos < limit;
+        }
+        
+        public char next()
+        {
+            return string.charAt(curpos++);
+        }
+        
+        public void backup()
+        {
+            curpos--;
+        }        
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/SplashLabel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/SplashLabel.java
new file mode 100644
index 0000000000000000000000000000000000000000..497d7b125a229e8c870528cd65df5e966f9e9ba1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/SplashLabel.java
@@ -0,0 +1,86 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.imageio.ImageIO;
+import javax.swing.JComponent;
+
+
+/**
+ * Super class for splash images.
+ *
+ * @author Poul Henriksen
+ * @version $Id$
+ */
+public abstract class SplashLabel extends JComponent
+{
+    private BufferedImage image;
+    
+    public SplashLabel(String imageName)
+    {
+        loadImage(imageName);
+        //setBorder(BorderFactory.createLineBorder(Color.black, 1));
+    }
+    
+    public BufferedImage getImage() {
+        return image;
+    }
+   
+    public Dimension getMinimumSize()
+    {
+        return getPreferredSize();
+    }
+
+    public Dimension getMaximumSize()
+    {
+        return getPreferredSize();
+    }
+
+    public Dimension getPreferredSize()
+    {
+        Dimension prefSize = new Dimension();
+        if(image != null) {
+            prefSize.setSize(image.getWidth(), image.getHeight());
+        }
+        return prefSize;
+    }
+    
+    private void loadImage(String imageName) {
+        URL splashURL = getClass().getResource(imageName); 
+      
+        if (splashURL == null) {
+            System.out.println("cannot find splash image: " + imageName);
+            return;
+        }
+        try {
+            image = ImageIO.read(splashURL);
+        }
+        catch (IOException exc) { // ignore
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/SplashWindow.java b/Sd1/P/Maven/bluej/src/main/java/bluej/SplashWindow.java
new file mode 100644
index 0000000000000000000000000000000000000000..6cf49d3aba34a0372ae731b644d00392829c1ae9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/SplashWindow.java
@@ -0,0 +1,76 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej;
+
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Toolkit;
+
+/**
+ * This class implements a splash window that can be displayed while BlueJ is
+ * starting up.
+ *
+ * @author  Michael Kolling
+ * @version $Id: SplashWindow.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+public class SplashWindow extends Frame
+{
+    private boolean painted = false;
+    
+    public SplashWindow(SplashLabel image)
+    {
+        setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
+    	setUndecorated(true);
+
+        add(image);
+        pack();
+
+        // centre on screen
+        Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
+        setLocation((screenDim.width - getSize().width) / 2, (screenDim.height - getSize().height) / 2);
+        setVisible(true);
+        //try { Thread.sleep(11000);} catch(Exception e) {}  // for testing: show longer
+    }
+    
+    public synchronized void paint(Graphics g)
+    {
+        painted = true;
+        super.paint(g);
+        notify();
+    }
+    
+    public synchronized void waitUntilPainted()
+    {
+        while (!painted) {
+            try {
+                wait();
+            }
+            catch (InterruptedException ie) {
+                painted = true;
+            }
+        }
+    }
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/BPClassLoader.java b/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/BPClassLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6815bf7a8cf9e80034653c0170c9fc99dede680
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/BPClassLoader.java
@@ -0,0 +1,162 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.classmgr;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+
+import bluej.utility.Utility;
+
+/**
+ * A Bluej Project ClassLoader that can be used to load or obtain information about classes loadable in a bluej project.
+ * Different projects have different class loaders since they shoule each have a well defined and unique namespace.
+ * Every time a project is compiled, even when the compilation is started from the GUI, a new ProjectLoader is created and
+ * if the Extension currently have a copy of the old one it should discard it.
+ * Note: There is a name clash with ProjectClassLoader that should be deleted at the end of refactornig,
+ * unfortunately ProjectClassLoader has different semantic and it would be unvise to break the current behaviour before
+ * having a correct working version. This is the reason for this class being named BPClassLoader.
+ * it will be renamed when the new classloading is refactored and tested.
+ *
+ * @author  Damiano Bolla
+ */
+public final class BPClassLoader extends URLClassLoader
+{
+    private boolean loadsForJavaMEproject;
+    
+    //We store the Java ME libraries in fields of the class loader--even though
+    //these libraries are in the search path of URLs of the loader--because
+    //we need them in the compiler's bootclasspath and in the classpath of the
+    //preverify command.
+    private List<URL> javaMEcoreLibs;  // Java ME core libraries
+    private List<URL> javaMEoptLibs;   // Java ME optional libraries
+    
+    /**
+     * Constructructor.
+     * @param parent the parent loader that is searched first to resolve classes.
+     * @param urls the list of jars and directory that are searched next.
+     */
+    public BPClassLoader(URL[] urls, ClassLoader parent) {
+        this(urls, parent, false);
+    }  
+ 
+    /**
+     * Constructor.
+     * @param parent   the parent loader that is searched first to resolve classes.
+     * @param urls     the list of jars and directory that are searched next.
+     * @param meFlag   whether this classloader is for a Java ME project
+     */
+    public BPClassLoader( URL[] urls, ClassLoader parent, boolean meFlag ) {
+        super( urls, parent );
+        loadsForJavaMEproject = meFlag;        
+    }      
+    
+    /**
+     * Returns flag indicating whether this class loads for a JavaME project.
+     */
+    public boolean loadsForJavaMEproject( ) {
+        return loadsForJavaMEproject;
+    }    
+
+    /**
+     * Compare the current array of URLS with the given one.
+     * Note that is the order of the array is different then the two are considered different.
+     * @param compare URLs to compare with the original.
+     * @return true if the two arrays are the same.
+     */
+    public final boolean sameUrls(URL[] compare) {
+        URL[] original = getURLs();
+
+        if (original == null) {
+            return false;
+        }
+
+        if (original.length != compare.length) {
+            return false;
+        }
+
+        for (int index = 0; index < original.length; index++)
+            if (!original[index].equals(compare[index])) {
+                return false;
+            }
+
+        return true;
+    }
+
+    /**
+     * Create a string with this class path as a separated list of strings.
+     * Note that a classpath to be used to start another local JVM cannot refer to a URL but to a local file.
+     * It is therefore advisable to move as much as possible from a Classpath oriented vew to a ClassLoader.
+     *
+     * @return  The classpath as string.
+     */
+    public String getClassPathAsString()
+    {
+        return Utility.toClasspathString(getClassPathAsFiles());
+    }
+
+    /**
+     * Return the class path as an array of files.
+     * Note that there is no guarantee that all files are indeed local files althout this is true for the
+     * current BlueJ.
+     * @return a non null array of Files, may be empty if no library at all is defined.
+     */
+    public final File[] getClassPathAsFiles()
+    {
+        return Utility.urlsToFiles(getURLs());
+    }
+
+    public String toString()
+    {
+        return "BPClassLoader path=" + getClassPathAsString();
+    }
+    
+    public void setJavaMEcoreLibs( List<URL> list ) { javaMEcoreLibs = list; }
+    public void setJavaMEoptLibs ( List<URL> list ) { javaMEoptLibs  = list; }
+    
+    public List<URL> getJavaMEcoreLibs( ) { return javaMEcoreLibs; }
+    public List<URL> getJavaMEoptLibs ( ) { return javaMEoptLibs;  }
+    
+    /**
+     * Concatenates the Java ME libraries, both core and optional, into a single
+     * array of Files.
+     * @return all the Java ME libraries as an array of Files
+     */
+    public File [] getJavaMElibsAsFiles()
+    {
+        ArrayList<URL> urls = new ArrayList<URL>(javaMEcoreLibs);
+        urls.addAll(javaMEoptLibs);
+        return Utility.urlsToFiles(urls.toArray(new URL[urls.size()]));
+    }
+
+    /**
+     * Concatenates the Java ME libraries, both core and optional, into a single
+     * colon/semicolon-separated String.
+     * @return all the Java ME libraries in a String
+     */
+    public String getJavaMElibsAsPath( ) 
+    {
+        return Utility.toClasspathString(getJavaMElibsAsFiles());
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassMgrPrefPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassMgrPrefPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..a44e44cf628e3c752850a921adc88c6040c3ab2b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassMgrPrefPanel.java
@@ -0,0 +1,380 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.classmgr;
+
+import bluej.pkgmgr.Project;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.MissingResourceException;
+import javax.swing.*;
+import javax.swing.table.*;
+import javax.swing.filechooser.FileFilter;
+import java.awt.*;
+import java.awt.event.*;
+
+import java.io.*;
+import java.util.List;
+import java.util.ArrayList;
+
+import bluej.*;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+import bluej.prefmgr.*;
+
+/**
+ * A PrefPanel subclass to allow the user to interactively add a new library
+ * to the browser.  The new library can be specified as a file (ZIP or JAR
+ * archive) with an associated description.
+ *
+ * @author  Andrew Patterson
+ * @version $Id: ClassMgrPrefPanel.java 7051 2010-01-25 15:31:24Z nccb $
+ */
+public class ClassMgrPrefPanel extends JPanel
+    implements PrefPanelListener
+{
+    private static final String userlibPrefix = "bluej.userlibrary";
+
+    private JTable userLibrariesTable = null;
+    private ClassPathTableModel userLibrariesModel = null;
+
+    private ClassPath userLibraries;
+    
+    private boolean classPathModified = false;
+
+    /**
+     * Setup the UI for the dialog and event handlers for the dialog's buttons.
+     */
+    public ClassMgrPrefPanel()
+    {
+        // Get the list of user libraries from the configuration.
+        // This list os the one that is saved into the config file.
+        userLibraries = new ClassPath();
+        addConfigEntries(userLibraries, userlibPrefix);
+
+        // TODO: There a re a few historical issues here, the first one is that this list is calculated
+        // here but in reality now it is much more dynamic, there is no need to restart BlueJ to have
+        // the new value applied, so this list should also be dynamic.
+        // The second point is that it does not make much sense to say loaded or unloaded since
+        // if it is a valid jar the it is in the project classloader.
+        // Somthing to fix in the future.
+        // It may have more meaning to show what is the project classloader, that would include all
+        // libraries, and paths, including +libs 
+        ArrayList<URL> userlibList = Project.getUserlibContent();
+        ClassPath cp = new ClassPath(userlibList.toArray(new URL[userlibList.size()]));
+        List<ClassPathEntry> userlibExtLibrariesList = cp.getEntries();
+
+        // Construct a user editable table of user libraries and add/remove buttons
+
+        JLabel userLibrariesTag = new JLabel(Config.getString("classmgr.userlibraries"));
+        {
+            userLibrariesTag.setAlignmentX(LEFT_ALIGNMENT);
+        }
+
+        // hold the scrolling table and the column of add/remove buttons in a row
+        JPanel userLibPane = new JPanel(new BorderLayout());
+        {
+            JScrollPane scrollPane = new JScrollPane();
+            {
+				// table of user library classpath entries
+                userLibrariesModel = new ClassPathTableModel(userLibraries);
+                userLibrariesTable = new JTable(userLibrariesModel);
+                {
+                    userLibrariesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+                    userLibrariesTable.setPreferredScrollableViewportSize(new Dimension(400, 80));
+                }
+
+                TableColumn notfoundColumn = 
+					userLibrariesTable.getColumn(userLibrariesTable.getColumnName(0));
+                {
+                    notfoundColumn.setPreferredWidth(20);
+                }
+
+                TableColumn locationColumn = 
+					userLibrariesTable.getColumn(userLibrariesTable.getColumnName(1));
+                {
+                    locationColumn.setPreferredWidth(280);
+                }
+
+                scrollPane.setAlignmentY(TOP_ALIGNMENT);
+                scrollPane.setViewportView(userLibrariesTable);
+            }
+
+            // hold the two Add and Delete buttons in a column
+            JPanel buttonPane = new JPanel();
+            {
+                buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.Y_AXIS));
+                buttonPane.setAlignmentY(TOP_ALIGNMENT);
+                buttonPane.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
+
+                JButton addButton = new JButton(Config.getString("classmgr.add"));
+                {
+                    addButton.addActionListener(new ActionListener() {
+                            public void actionPerformed(ActionEvent e) {
+                                addUserLibrary();
+                            }
+                        });
+                }
+                JButton deleteButton = new JButton(Config.getString("classmgr.delete"));
+                {
+                    deleteButton.addActionListener(new ActionListener() {
+                            public void actionPerformed(ActionEvent e) {
+                                deleteUserLibrary();
+                            }
+                        });
+                }
+
+		// allow the Add and Delete buttons to be resized to equal width
+		addButton.setMaximumSize(new Dimension(Integer.MAX_VALUE,
+						addButton.getPreferredSize().height));
+		deleteButton.setMaximumSize(new Dimension(Integer.MAX_VALUE,
+						deleteButton.getPreferredSize().height));
+
+                buttonPane.add(addButton);
+                buttonPane.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+                buttonPane.add(deleteButton);
+            }
+
+            userLibPane.setAlignmentX(LEFT_ALIGNMENT);
+
+            userLibPane.add(scrollPane, BorderLayout.CENTER);
+            userLibPane.add(buttonPane, BorderLayout.EAST);
+        }
+
+        // Construct a list of system libraries
+
+        JScrollPane userlibExtLibrariesScrollPane = new JScrollPane();
+        {
+            JList list = new JList();
+            {
+                list.setListData(userlibExtLibrariesList.toArray());
+                list.setCellRenderer(new ClassMgrCellRenderer());
+                list.setEnabled(false);
+                list.setVisibleRowCount(6);
+            }
+
+            userlibExtLibrariesScrollPane.setViewportView(list);
+            userlibExtLibrariesScrollPane.setAlignmentX(LEFT_ALIGNMENT);
+        }
+        
+        String userlibLocation = Config.getString("classmgr.userliblibraries") 
+            + " (" + Config.getBlueJLibDir() + File.separator + "userlib)";
+        JLabel userlibExtLibrariesTag = new JLabel(userlibLocation);
+        {
+            userlibExtLibrariesTag.setAlignmentX(LEFT_ALIGNMENT);
+            userlibExtLibrariesTag.setLabelFor(userlibExtLibrariesScrollPane);
+        }
+
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+        setBorder(BlueJTheme.generalBorder);
+
+        add(userLibrariesTag);
+        add(userLibPane);
+        add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        add(userlibExtLibrariesTag);
+        add(userlibExtLibrariesScrollPane);
+    }
+
+    /**
+     * Returns an ArrayList of URLS holding jars that the user wish to be added to 
+     * the Project classloader.
+     * @return a non null but possibly empty arrayList of URL.
+     */
+    public ArrayList<URL> getUserConfigContent ()
+    {
+        return userLibraries.getURLs();
+    }
+    
+    
+    /**
+     * Retrieve from the system wide Config entries corresponding to classpath
+     * entries. The entries to retrieve start with prefix and have 1.location,
+     * 2.location etc appended to them until an entry is not found.
+     *
+     * @param   prefix    the prefix of the property names to look up
+     */
+    private void addConfigEntries(ClassPath cp, String prefix)
+    {
+        int resourceID = 1;
+        try {
+            while (true) {
+                String location = Config.getPropString(prefix + resourceID + ".location", null);
+
+                if (location == null)
+                    break;
+
+                cp.addClassPath(location, "");
+
+                resourceID++;
+            }
+        } catch (MissingResourceException mre) {
+            // it is normal that this is exception is thrown, it just means we've come
+            // to the end of the file
+        }
+    }
+
+    public void beginEditing()
+    {
+    }
+
+    public void revertEditing()
+    {
+        userLibrariesModel.revertEntries();
+    }
+
+    public void commitEditing()
+    {
+        if (classPathModified) {
+            DialogManager.showMessage(null, "classmgr-changes-no-effect");
+            classPathModified = false;
+        }
+        
+        userLibrariesModel.commitEntries();
+        saveUserLibraries();
+    }
+
+
+    /**
+     * Save user classpath entries into the system wide Config properties object.
+     * The entries stored start with prefix and have 1.location,
+     * 2.location etc appended to them.
+     */
+    private void saveUserLibraries()
+    {
+        String r1;
+        int resourceID = 1;
+
+        while(true) {
+            r1 = Config.removeProperty(userlibPrefix + resourceID + ".location");
+
+            if(r1 == null)
+                break;
+
+            resourceID++;
+        }
+
+        Iterator<ClassPathEntry> it = userLibraries.getEntries().iterator();
+        resourceID = 1;
+
+        while (it.hasNext()) {
+            ClassPathEntry nextEntry = it.next();
+            Config.putPropString(userlibPrefix + resourceID + ".location",
+                                    nextEntry.getPath());
+            resourceID++;
+        }
+    }
+
+
+
+    /**
+     * Pop up a dialog to allow the user to add a library
+     * to their user library classpath.
+     **/
+    private void addUserLibrary()
+    {
+    	File file = FileUtility.getFile(getParent(), Config.getString("prefmgr.misc.addLibTitle"),
+    			null, new LibraryFileFilter(), false);
+    	
+    	if (file != null) {
+    		String librarylocation = file.getAbsolutePath();
+
+            userLibrariesModel.addEntry(new ClassPathEntry(librarylocation,"", true));
+            
+            classPathModified = true;
+    	}
+    }
+
+    /**
+     * Delete the currently selected row (if there is one)
+     * of the user library table from the user library
+     * classpath.
+     */
+    private void deleteUserLibrary()
+    {
+        int which = userLibrariesTable.getSelectedRow();
+
+        if(which != -1) {
+            classPathModified = true;
+            userLibrariesModel.deleteEntry(which);
+        }
+    }
+}
+
+/**
+ * A private class to render class path entries into a list box
+ * in the format of
+ * location (description)
+ */
+class ClassMgrCellRenderer implements ListCellRenderer
+{
+	// This is the only method defined by ListCellRenderer.  We just
+	// reconfigure the Jlabel each time we're called.
+
+	public Component getListCellRendererComponent(
+		JList list,
+		Object value,            // value to display
+		int index,               // cell index
+		boolean isSelected,      // is the cell selected
+		boolean cellHasFocus)    // the list and the cell have the focus
+	{
+		Component sup =
+			new DefaultListCellRenderer().getListCellRendererComponent(list,
+							value,index,isSelected,cellHasFocus);
+
+		ClassPathEntry cpe = (ClassPathEntry)value;
+
+		String s = cpe.getCanonicalPathNoException() + " (" + cpe.getStatusString() + ")";
+
+		((JLabel)sup).setText(s);
+
+   		return sup;
+	}
+}
+
+/**
+ * A simple FileFilter subclass to accept on valid library files (i.e., ZIP or JAR extension)
+ * Used by the addUserLibrary method to only allow selection of valid library archive files.
+ */
+class LibraryFileFilter extends FileFilter
+{
+	/**
+	 * Check if it is a valid library archive file.
+	 *
+	 * @param	f the file to be check.
+	 * @return	true if the file was accepted.
+	 */
+	public boolean accept(File f) {
+		return (f.isDirectory() ||
+			f.getName().toLowerCase().endsWith(".jar") ||
+			f.getName().toLowerCase().endsWith(".zip"));
+	}
+
+	/**
+	 * Return a description of the files accepted by this filter.  Used
+	 * in the "file types" drop down list in file chooser dialogs.
+	 *
+	 * @return	a description of the files accepted by this filter.
+	 */
+	public String getDescription() {
+		return Config.getString("prefmgr.misc.libFileFilter");
+	}
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassPath.java b/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassPath.java
new file mode 100644
index 0000000000000000000000000000000000000000..12b08dac4d8428727ee3e8a551ca242e7ae24ffa
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassPath.java
@@ -0,0 +1,335 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.classmgr;
+
+import bluej.utility.Debug;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Class to maintain a list of ClassPathEntry's.
+ *
+ * @author  Andrew Patterson
+ */
+public class ClassPath
+{
+    /**
+     * The actual list of class path entries
+     */
+    private ArrayList<ClassPathEntry> entries = new ArrayList<ClassPathEntry>();
+
+    /**
+     * Construct an empty ClassPath
+     */
+    public ClassPath()
+    {
+    }
+
+    /**
+     * Construct a ClassPath which is a copy of an existing ClassPath
+     */
+    public ClassPath(ClassPath classpath)
+    {
+        addClassPath(classpath);
+    }
+
+    /**
+     * Construct a ClassPath from a delimitered String of entries
+     *
+     * @param   classpath   A ; or : seperated String with entries
+     * @param   genericdescription  A String which can be used to
+     *          generically describe these entries
+     */
+    public ClassPath(String classpath, String genericdescription)
+    {
+        addClassPath(classpath, genericdescription);
+    }
+
+    /**
+     * Construct a Classpath from an array of URLs
+     * 
+     * @param urls
+     *            an array of File URLs
+     */
+    public ClassPath(URL urls[])
+    {
+        for(int i=0; i<urls.length; i++) {
+            try {
+            ClassPathEntry cpe = new ClassPathEntry(new File(new URI(urls[i].toString())), "");
+
+            if(!entries.contains(cpe))
+                entries.add(cpe);
+            }
+            catch(URISyntaxException use) { }
+        }
+    }
+
+
+    /**
+     * Construct a Classpath from an array of Files.
+     * @param files an array of File
+     */
+    public ClassPath(File files[])
+    {
+        for(int index=0; index<files.length; index++) {
+            entries.add( new ClassPathEntry(files[index], ""));
+        }
+    }
+
+
+    /**
+     * Return the list of entries (mutable, so only for close friends)
+     */
+    protected List<ClassPathEntry> getEntries()
+    {
+        return entries;
+    }
+
+    /**
+     * Return the list of entries (immutable)
+     */
+    public List<ClassPathEntry> getPathEntries()
+    {
+        return Collections.unmodifiableList(entries);
+    }
+
+
+    /**
+     * Remove elements from the classpath
+     *
+     * @param   classpath   A ; or : separated String of class path entries to
+     *                      remove
+     */
+    public void removeClassPath(String classpath)
+    {
+        try {
+            StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator);
+
+            while(st.hasMoreTokens()) {
+                String entry = st.nextToken();
+
+                entries.remove(entry);
+            }
+        } catch(Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Remove all entries from the class path
+     */
+    public void removeAll()
+    {
+        entries.clear();
+    }
+
+    /**
+     * Add a copy of an existing ClassPath
+     *
+     * @param   classpath   A ClassPath object to add a copy of
+     */
+    public void addClassPath(ClassPath classpath)
+    {
+        // make a copy of the entries.. don't just add the entries to the
+        // new class path
+
+        Iterator<ClassPathEntry> it = classpath.entries.iterator();
+
+        while (it.hasNext()) {
+
+            ClassPathEntry nextEntry = it.next();
+
+            try {
+                ClassPathEntry cpentry = (ClassPathEntry)nextEntry.clone();
+
+                if(!entries.contains(cpentry)) {
+                    entries.add(cpentry);
+                }
+            } catch(CloneNotSupportedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Add from a classpath string all the libraries which it references
+     *
+     * @param   classpath   a string containing a sequence of filenames
+     *              separated by a path separator character
+     * @param   genericdescription  a string which will be used as the
+     *                  description for all entries created for
+     *                  this classpath
+     */
+    public void addClassPath(String classpath, String genericdescription)
+    {
+        if (classpath == null)
+            return;
+
+        try {
+            StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator);
+
+            while(st.hasMoreTokens()) {
+                String entry = st.nextToken();
+                ClassPathEntry cpentry = new ClassPathEntry(entry, genericdescription);
+
+                if(!entries.contains(cpentry))
+                    entries.add(cpentry);
+            }
+        }
+        catch(Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+
+    /**
+     * Return the class path entries as an ArrayList of URL.
+     * @return a non null but possibly empty ArrayList of URL.
+     */
+    public ArrayList<URL> getURLs()
+    {
+        Iterator<ClassPathEntry> it = entries.iterator();
+        ArrayList<URL> risul = new ArrayList<URL>();
+
+        while (it.hasNext()) {
+            ClassPathEntry path = it.next();
+
+            try {
+                risul.add(path.getURL());
+            } catch(MalformedURLException mue) {
+                Debug.reportError("ClassPath.getURLs() bad path="+path);
+            }
+        }
+
+        return risul;
+    }
+
+    /**
+     * Find a file in the classpath
+     *
+     * @param   filename    a string which specifies a file to look
+     *              for throughout the class path
+     *          this filename is in native slash seperated form
+     *          ie foo/bar for UNIX and foo\bar for Windows
+     */
+    public InputStream getFile(String filename) throws IOException
+    {
+        Iterator<ClassPathEntry> it = entries.iterator();
+
+        while (it.hasNext()) {
+            ClassPathEntry nextEntry = it.next();
+
+            // each entry can be either a jar/zip file or a directory
+            // or neither in which case we ignore it
+
+            if(nextEntry.isJar()) {
+                InputStream ret = readJar(nextEntry.getFile(), filename);
+
+                if (ret != null)
+                    return ret;
+            } else if (nextEntry.isClassRoot()) {
+                File fd = new File(nextEntry.getFile(), filename);
+
+                if(fd.exists())
+                    return new FileInputStream(fd);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Retrieve an entry out of a jar file
+     *
+     * @param   classjar    a file representing the jar to look in
+     * @param   filename    a string which specifies a file to look
+     *              for in the jar
+     */
+    private InputStream readJar(File classjar, String filename) throws IOException
+    {
+        JarFile jarf = new JarFile(classjar);
+
+        // filenames are passed into us in native slash separated form.
+        // jar files require us to always use the forward slash when looking
+        // for files so if we are on a system where / is not the actual
+        // separator character we have to first fix the filename up
+
+        if(File.separatorChar != '/')
+            filename = filename.replace(File.separatorChar, '/');
+
+        JarEntry entry = jarf.getJarEntry(filename);
+
+        if(entry == null) {
+            return null;
+        }
+
+        InputStream is = jarf.getInputStream(entry);
+
+        return is;
+    }
+
+    /**
+     * Create a string with this class path as a separated list of strings.
+     * The separator character is system dependent (see File.pathSeparatorChar).
+     * 
+     * @return  The classpath as string.
+     */
+    public String toString()
+    {
+        return asList(File.pathSeparatorChar, false);
+    }
+    
+    /**
+     * Create a string with this class path as a separated list of strings.
+     * The separator character can be specified.
+     * 
+     * @param separator  The character to be used to separate entries.
+     * @param useURL    
+     * @return  The classpath as string.
+     */
+    public String asList(char separator, boolean useURL)
+    {
+        StringBuffer buf = new StringBuffer();
+
+        Iterator<ClassPathEntry> it = entries.iterator();
+
+        while (it.hasNext()) {
+            ClassPathEntry nextEntry = it.next();
+
+            if(useURL) {
+                try {
+                    buf.append(nextEntry.getURL());
+                }
+                catch (MalformedURLException e) {}
+            } else
+                buf.append(nextEntry.getPath());
+            // we want to append a separator to all but the last entry
+            if(it.hasNext())
+                buf.append(separator);
+        }
+
+        return buf.toString();        
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassPathEntry.java b/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassPathEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..252ceafc7ba5b68a1538d35382e85033891f4093
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassPathEntry.java
@@ -0,0 +1,269 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.classmgr;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.*;
+
+import bluej.Config;
+
+/**
+ * Class to maintain a single file/directory location in a classpath
+ *
+ * @author  Andrew Patterson
+ * @version $Id: ClassPathEntry.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class ClassPathEntry implements Cloneable
+{
+    private static final String statusGood = Config.getString("classmgr.statusgood");
+    private static final String statusBad = Config.getString("classmgr.statusbad");
+    private static final String statusNew = Config.getString("classmgr.statusnew");
+
+    /**
+     * Hold the class path entry location.
+     */
+    private File file;
+
+    /**
+     * Hold the class path entry description.
+     */
+    private String description;
+
+    /**
+     * Flag to mark entries added after system start (unloaded).
+     */
+    private boolean justAdded = false;
+    
+    /**
+     * Holds a file/directory location in a classpath entry along with a
+     * description.
+     *
+     * @param location  the directory path or filename or a jar/zip file
+     * @param description a short description of the classes represented
+     *                    by this classpath entry
+     */
+    public ClassPathEntry(String location, String description)
+    {
+        // we take the decision that all ClassPathEntries should
+        // be absolute (the behaviour of BlueJ should not change
+        // dependant upon what directory the user was in when they
+        // launched it). There may be a good reason why relative
+        // ClassPathEntries are needed.. if so this code will have
+        // to be rethought
+        this.file = new File(location).getAbsoluteFile();
+        this.description = description;
+    }
+
+
+    /**
+     * Holds a file/directory location in a classpath entry along with a description.
+     *
+     * @param file the file holding one path entry.
+     * @param description a short description of the classes represented by this classpath entry
+     */
+    public ClassPathEntry(File file, String description)
+    {
+        this.file = file;
+        this.description = description;
+    }
+
+    public ClassPathEntry(String location, String description, boolean isNew)
+    {
+        this(location, description);
+        justAdded = isNew;
+    }
+
+    /**
+     * Gets the description for this class path entry.
+     *
+     * @returns a string describing the contents of this classpath entry
+     */
+    public String getDescription()
+    {
+        if (description == null)
+            return Config.getString("classmgr.error.nodescription") +
+                    " (" + file.getPath() + ")";
+        else
+            return description;
+    }
+
+    /**
+     * Set the description for this class path entry.
+     *
+     * @param description a short description of the classes represented
+     *                    by this classpath entry
+     */
+    protected void setDescription(String d)
+    {
+        this.description = d;
+    }
+
+    /**
+     * Gets the File for this class path entry.
+     *
+     * @returns a File identifying the file or directory that this class
+     *          path entry represents
+     */
+    public File getFile()
+    {
+        return file;
+    }
+
+    /**
+     * Gets the path for this class path entry.
+     *
+     * @returns a File identifying the file or directory that this class
+     * @note    this path is always absolute because of our constructor
+     */
+    public String getPath()
+    {
+        return file.getPath();
+    }
+
+    /**
+     * Gets the canonical path for this entry, or a String describing an error
+     * if the canonical path could not be found.
+     *
+     * @returns a String representing the canonical path of the file or
+     *          directory that this class path entry represents
+     * @note    the Config.getString in this method was changed from a
+     *          static class string to a local variable because we need to instantiate
+     *          ClassPathEntries on the remote VM, and it has no access to the Config
+     *          files and was therefore generating error message when the class was
+     *          loaded (even though we don't use getCanonicalPathNoException() on
+     *          the remote VM).
+     */
+    public String getCanonicalPathNoException()
+    {
+        String path;
+        try {
+            path = file.getCanonicalPath();
+        } catch (IOException ioe) {
+            path = Config.getString("classmgr.error.unresolvable") +
+                    " (" + file.getPath() + ")";
+        }
+        return path;
+    }
+
+    /**
+     * Gets a URL representing this class path entry.
+     *
+     * @returns a URL representing this classpath entry
+     */
+    public URL getURL() throws MalformedURLException
+    {
+        return file.toURI().toURL();
+    }
+
+    /**
+     * Determine if this class path entry has been added after
+     * BlueJ was started (and thus isn't loaded).
+     */
+    public boolean isNew()
+    {
+        return justAdded;
+    }
+    
+    /**
+     * Determine if this class path entry represents a valid entry
+     * on the current VM (ie file/dir exists and is readable)
+     */
+    public boolean isValid()
+    {
+        /* If its a directory then it exists and we wont try to
+           work out any more about it.. its valid as far as we are
+           concerned */
+        if (file.isDirectory())
+            return true;
+
+        /* If it satisfies our conditions for a Jar file we still may
+           not be able to read it, so use that as a test for validity */
+        if (isJar())
+            return file.canRead();
+
+        /* we don't know what it is.. mark it as invalid */
+        return false;
+    }
+
+    /**
+     * Return the current status as a string (Loaded/Not Loaded/Error).
+     */
+    public String getStatusString()
+    {
+        if (!isValid())
+            return statusBad;
+        else if(isNew())
+            return statusNew;
+        else
+            return statusGood;
+    }
+    
+    /**
+     * Determine if this class path entry represents a Jar file.
+     *
+     * @returns a boolean indicating if this entry is a jar or
+     *          zip file.
+     */
+    public boolean isJar()
+    {
+        String name = file.getName().toLowerCase();
+
+        return file.isFile() &&
+            (name.endsWith(".zip") || name.endsWith(".jar"));
+    }
+
+    /**
+     * Determine if this class path entry represents the root of
+     * a class directory.
+     *
+     * @returns a boolean indicating if this entry is a class
+     *          directory.
+     */
+    public boolean isClassRoot()
+    {
+        return file.isDirectory();
+    }
+
+    public String toString()
+    {
+        return getPath();
+    }
+
+    /* we want to appear the same as another ClassPathEntry if our
+       location is identical - we ignore the description */
+
+    public boolean equals(Object o)
+    {
+        return this.file.equals(((ClassPathEntry)o).file);
+    }
+
+    public int hashCode()
+    {
+        return file.hashCode();
+    }
+
+    protected Object clone() throws CloneNotSupportedException
+    {
+        return super.clone();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassPathTableModel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassPathTableModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff87b9c9542f94a17fa0754314516b755b19c26b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/classmgr/ClassPathTableModel.java
@@ -0,0 +1,167 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.classmgr;
+
+import javax.swing.table.*;
+import bluej.Config;
+
+/**
+ * Given a list of ClassPathEntry returns a table model which allows them to
+ * be edited in a JTable.
+ *
+ * The model implements a form of rollback which allows the table to be
+ * edited and then changes can be reverted or committed.
+ *
+ * @author  Andrew Patterson
+ * @cvs     $Id: ClassPathTableModel.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class ClassPathTableModel extends AbstractTableModel
+{
+    static final String statusLabel = Config.getString("classmgr.statuscolumn");
+    static final String locationLabel = Config.getString("classmgr.locationcolumn");
+
+    private ClassPath origcp;
+    private ClassPath cp;
+
+    /**
+     * Construct a table model of a class path
+     *
+     * @param origcp    the class path to model
+     */
+    public ClassPathTableModel(ClassPath origcp)
+    {
+        this.origcp = origcp;
+        this.cp = new ClassPath(origcp);
+    }
+    
+    /**
+     * Return the name of a particular column
+     *
+     * @param col   the column we are naming
+     * @return      a string of the columns name
+     */
+    public String getColumnName(int col)
+    {
+        if (col == 0)
+            return statusLabel;
+        else if (col == 1)
+            return locationLabel;
+
+        throw new IllegalArgumentException("bad column number in ClassPathTableModel::getColumnName()");
+    }
+
+    /**
+     * Return the number of rows in the table
+     *
+     * @return      the number of rows in the table
+     */
+    public int getRowCount()
+    {
+        return cp.getEntries().size();
+    }
+    
+    /**
+     * Return the number of columns in the table
+     *
+     * @return      the number of columns in the table
+     */
+    public int getColumnCount()
+    {
+        return 2;
+    }
+    
+    /**
+     * Find the table entry at a particular row and column
+     *
+     * @param   row     the table row
+     * @param   col     the table column
+     * @return          the Object at that location in the table
+     */
+    public Object getValueAt(int row, int col)
+    {
+        ClassPathEntry entry = (ClassPathEntry)cp.getEntries().get(row);
+
+        if (col == 0)
+            return entry.getStatusString();
+        else if (col == 1)
+            return entry.getCanonicalPathNoException();
+        else if (col == 2)
+            return entry.getDescription(); 
+
+        throw new IllegalArgumentException("bad column number in ClassPathTableModel::getValueAt()");
+    }
+
+    /**
+     * Indicate that only our location column is edititable
+     */
+    public boolean isCellEditable(int row, int col)
+    {
+        return (col == 2);
+    }
+
+    /**
+     * Set the table entry at a particular row and column (only
+     * valid for the location column)
+     *
+     * @param   value   the Object at that location in the table
+     * @param   row     the table row
+     * @param   col     the table column
+     */
+    public void setValueAt(Object value, int row, int col)
+    {
+        if (col == 2) {
+            ClassPathEntry entry = (ClassPathEntry)cp.getEntries().get(row);
+
+            entry.setDescription((String)value);
+
+            fireTableCellUpdated(row, col);
+        }
+    }
+
+    public void addEntry(ClassPathEntry cpe)
+    {
+        int s = cp.getEntries().size();
+        cp.getEntries().add(cpe);
+        fireTableRowsInserted(s,s);
+    }
+
+    public void deleteEntry(int index)
+    {
+        if(index < cp.getEntries().size() && index >= 0) {
+            cp.getEntries().remove(index);
+            fireTableRowsDeleted(index, index);
+        }
+    }
+
+    public void commitEntries()
+    {
+        origcp.removeAll();
+        origcp.addClassPath(cp);
+    }
+
+    public void revertEntries()
+    {
+        cp = new ClassPath(origcp);
+
+        fireTableDataChanged();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompileObserver.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompileObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..a5f3572d5c3954ed42d5844415d3d4c5f0db22b3
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompileObserver.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+import java.io.File;
+
+/**
+ * Observer interface for classes that are interested in compilation.
+ *
+ * All events are generated on the compiler thread.
+ *
+ * @author  Michael Cahill
+ */
+public interface CompileObserver
+{
+    /**
+     * A compilation job has started.
+     */
+    void startCompile(File[] sources);
+    
+    /**
+     * An error or warning message occurred during compilation
+     * 
+     * Returns whether or not the error was shown to the user (for data collection purposes)
+     */
+    boolean compilerMessage(Diagnostic diagnostic);
+    
+    /**
+     * A Compilation job finished.
+     */
+    void endCompile(File[] sources, boolean succesful);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/Compiler.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/Compiler.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef1548a6ed00a70b77598b9e5e9d542940e9e80c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/Compiler.java
@@ -0,0 +1,131 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.List;
+
+/**
+ * Compiler class - an abstract interface to a source-to-bytecode compiler. This
+ * can be implemented by different compiler implementations.
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ * @author Poul Henriksen
+ */
+abstract class Compiler
+{
+    public static final String COMPILER_OPTIONS = "bluej.compiler.options";
+    public static final String JAVAME_COMPILER_OPTIONS = "bluej.javame.compiler.options";
+    
+    private File destDir;
+    private File[] classPath;
+    /** "boot" class path - may be null if not specified */
+    private File[] bootClassPath;
+    private boolean debug;
+    private boolean deprecation;
+    
+    /**
+     * Set the destination directory - the base directory for where the compiled class files
+     * are output to. (The final folder for a given class depends on the class' package).
+     * This currently also specifies the source path.
+     * 
+     * @param destDir  The destination directory
+     */
+    public void setDestDir(File destDir)
+    {
+        this.destDir = destDir;
+    }
+
+    public void setClasspath(File [] classPath)
+    {
+        this.classPath = classPath;
+    }
+    
+    /**
+     * Specify the "boot classpath".
+     * 
+     * @param bootClassPath  The boot classpath, or null to use the default.
+     */
+    public void setBootClassPath(File[] bootClassPath)
+    {
+        this.bootClassPath = bootClassPath;
+    }
+    
+    public void setDebug(boolean debug)
+    {
+        this.debug = debug;
+    }
+
+    public void setDeprecation(boolean deprecation)
+    {
+        this.deprecation = deprecation;
+    }
+
+    public boolean isDebug()
+    {
+        return debug;
+    }
+
+    public boolean isDeprecation()
+    {
+        return deprecation;
+    }
+
+    public File getDestDir()
+    {
+        return destDir;
+    }
+    
+    public File[] getClassPath()
+    {
+        return classPath;
+    }
+    
+    public File[] getBootClassPath()
+    {
+        return bootClassPath;
+    }
+
+    /**
+     * Compile some source files.
+     * 
+     * @param sources
+     *            The files to compile
+     * @param observer
+     *            The compilation observer
+     * @param internal
+     *            True if compiling BlueJ-generated code (shell files); false if
+     *            compiling user code
+     * @param options
+     *            Option strings to pass to the compiler
+     * @param fileCharset
+     *            The character set in which source files are encoded 
+     * 
+     * @return  true if the compilation was successful
+     */
+    public abstract boolean compile(File[] sources, CompileObserver observer,
+            boolean internal, List<String> options, Charset fileCharset);
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompilerAPICompiler.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompilerAPICompiler.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b76d43c000a473d86a971ea065c961241d183bc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompilerAPICompiler.java
@@ -0,0 +1,262 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import bluej.Config;
+
+/**
+ * A compiler implementation using the Compiler API introduced in Java 6.
+ * 
+ * @author Marion Zalk
+ */
+public class CompilerAPICompiler extends Compiler
+{
+    public CompilerAPICompiler()
+    {
+        setDebug(true);
+        setDeprecation(true);
+    }
+    
+    /**
+     * Compile some source files by using the JavaCompiler API. Allows for the addition of user
+     * options
+     * 
+     * @param sources
+     *            The files to compile
+     * @param observer
+     *            The compilation observer
+     * @param internal
+     *            True if compiling BlueJ-generated code (shell files); false if
+     *            compiling user code
+     * 
+     * @return  true if successful
+     */
+    @Override
+    public boolean compile(final File[] sources, final CompileObserver observer,
+            final boolean internal, List<String> userOptions, Charset fileCharset) 
+    {
+        boolean result = true;
+        JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
+        List<String> optionsList = new ArrayList<String>();
+        
+        DiagnosticListener<JavaFileObject> diagListener = new DiagnosticListener<JavaFileObject>() {
+            @Override
+            public void report(Diagnostic<? extends JavaFileObject> diag)
+            {
+                String src = null;
+                if (diag.getSource() != null)
+                {
+                    // With JDK 6, diag.getSource().getName()  apparently just returns the base
+                    // name without a path. To get the path we need to ask for the URI.
+                    //     However:
+                    // With JDK 7, the diag.getSource().toURI() returns an unusable URI if the
+                    // path is a UNC path (\\server\sharename\projdir\somefile.java).
+                    
+                    if (Config.isJava17()) {
+                        src = diag.getSource().getName();
+                    }
+                    else {
+                        // See bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6419926
+                        // JDK6 returns URIs without a scheme in some cases, so always resolve against a
+                        // known "file:/" URI:
+                        URI srcUri = sources[0].toURI().resolve(diag.getSource().toUri());
+                        src = new File(srcUri).getPath();
+                    }
+                }
+                
+                int diagType;
+                bluej.compiler.Diagnostic bjDiagnostic;
+                String message = diag.getMessage(null);
+                
+                if (diag.getKind() == Diagnostic.Kind.ERROR) {
+                    diagType = bluej.compiler.Diagnostic.ERROR;
+                    message = processMessage(src, (int) diag.getLineNumber(), message);
+                    long beginCol = diag.getColumnNumber();
+                    long endCol = diag.getEndPosition() - diag.getPosition() + beginCol;
+                    // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7158654
+                    // getEndPosition() shouldn't return NOPOS (-1) if getStartPosition()
+                    //    doesn't - but sometimes it does.
+                    if (diag.getEndPosition() == Diagnostic.NOPOS) {
+                        endCol = beginCol;
+                    }
+                    bjDiagnostic = new bluej.compiler.Diagnostic(diagType,
+                            message, src, diag.getLineNumber(), beginCol,
+                            diag.getLineNumber(), endCol);
+                }
+                else if (diag.getKind() == Diagnostic.Kind.WARNING) {
+                    if (message.startsWith("bootstrap class path not set in conjunction with -source ")) {
+                        // Java 7 produces this warning if "-source 1.6" is specified
+                        return;
+                    }
+                    diagType = bluej.compiler.Diagnostic.WARNING;
+                    long beginCol = diag.getColumnNumber();
+                    long endCol = diag.getEndPosition() - diag.getPosition() + beginCol;
+                    bjDiagnostic = new bluej.compiler.Diagnostic(diagType,
+                            message, src, diag.getLineNumber(), beginCol,
+                            diag.getLineNumber(), endCol);
+                }
+                else {
+                    diagType = bluej.compiler.Diagnostic.NOTE;
+                    bjDiagnostic = new bluej.compiler.Diagnostic(diagType, message);
+                    // Two variants of the warning message:
+                    // - for a single file, "xyz.java uses unchecked or unsafe operations"
+                    // - for multiple, "Some input files use unchecked or unsafe operations"
+                    if (internal &&
+                            (message.endsWith(" uses unchecked or unsafe operations.") ||
+                            message.endsWith("Some input files use unchecked or unsafe operations.") ||
+                            message.endsWith("Recompile with -Xlint:unchecked for details."))) {
+                        return;
+                    }
+                }
+                
+                observer.compilerMessage(bjDiagnostic);
+            }
+        };
+        
+        try
+        {  
+            //setup the filemanager
+            StandardJavaFileManager sjfm = jc.getStandardFileManager(diagListener, null, fileCharset);
+            List<File> pathList = new ArrayList<File>();
+            List<File> outputList = new ArrayList<File>();
+            outputList.add(getDestDir());
+            Collections.addAll(pathList, getClassPath());
+            
+            // In BlueJ, the destination directory and the source path are
+            // always the same
+            sjfm.setLocation(StandardLocation.SOURCE_PATH, outputList);
+            sjfm.setLocation(StandardLocation.CLASS_PATH, pathList);
+            sjfm.setLocation(StandardLocation.CLASS_OUTPUT, outputList);
+            
+            //get the source files for compilation  
+            Iterable<? extends JavaFileObject> compilationUnits1 =
+                sjfm.getJavaFileObjectsFromFiles(Arrays.asList(sources));
+            //add any options
+            if(isDebug()) {
+                optionsList.add("-g");
+            }
+            if(isDeprecation()) {
+                optionsList.add("-deprecation");
+            }
+            
+            File[] bootClassPath = getBootClassPath();
+            if (bootClassPath != null && bootClassPath.length != 0) {
+                sjfm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, Arrays.asList(bootClassPath));
+            }
+            
+            optionsList.addAll(userOptions);
+            
+            //compile
+            result = jc.getTask(null, sjfm, diagListener, optionsList, null, compilationUnits1).call();
+            sjfm.close();            
+        }
+        catch(IOException e)
+        {
+            e.printStackTrace(System.out);
+            return false;
+        }
+
+        return result;
+    }
+
+    /**
+     * Processes messages returned from the compiler. This just slightly adjusts the format of some
+     * messages.
+     * 
+     * @param src  The source file path
+     * @param pos  The line number at which the error occurrs
+     * @param message  The error message
+     */
+    protected String processMessage(String src, int pos, String message)
+    {
+        // For JDK 6, the message is in this format: 
+        //   path and filename:line number:message
+        // i.e includes the path and line number; so we need to strip that off.
+        String expected = src + ":" + pos + ": ";
+        if (message.startsWith(expected)) 
+        {
+            message = message.substring(expected.length());
+        }
+        
+        if (message.contains("cannot resolve symbol")
+                || message.contains("cannot find symbol")
+                || message.contains("incompatible types")) 
+        {
+            // divide the message into lines so we can retrieve necessary values
+            int index1, index2;
+            String line2, line3;
+            index1 = message.indexOf('\n');
+            if (index1 == -1) 
+            {
+                // We don't know how to handle this.
+                return message;
+            }
+            index2 = message.indexOf('\n',index1+1);
+            //i.e there are only 2 lines not 3
+            if (index2 < index1) 
+            {
+                line2 = message.substring(index1).trim();
+                line3 = "";
+            }
+            else {
+                line2 = message.substring(index1, index2).trim();
+                line3 = message.substring(index2).trim();
+            }
+            message = message.substring(0, index1);
+
+            //e.g incompatible types
+            //found   : int
+            //required: java.lang.String
+            if (line2.startsWith("found") && line2.indexOf(':') != -1) 
+            {
+                message = message +" - found " + line2.substring(line2.indexOf(':') + 2, line2.length());
+            }
+            if (line3.startsWith("required") && line3.indexOf(':') != -1) {
+                message = message +" but expected " + line3.substring(line3.indexOf(':') + 2, line3.length());
+            }
+            //e.g cannot find symbol
+            //symbol: class Persons
+            if (line2.startsWith("symbol") && line2.indexOf(':') != -1) 
+            {
+                message = message + " - " + line2.substring(line2.indexOf(':') + 2, line2.length());
+            }
+        }
+        return message;
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompilerThread.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompilerThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..44b6da0fc472bbfff488d7c4188860e9f14f7752
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompilerThread.java
@@ -0,0 +1,90 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+import bluej.Config;
+import bluej.utility.Queue;
+
+/**
+ * The compiler thread. BlueJ uses exactly one thread for compilation. Jobs are
+ * queued, and this thread processes tham one by one. If there is no job, this
+ * thread just sleeps.
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ */
+class CompilerThread extends Thread
+{
+    private Queue jobs;
+    private boolean busy = true;
+
+    /**
+     * Create a new compiler thread that holds its own job queue.
+     */
+    public CompilerThread()
+    {
+        super(Config.getString("compiler.thread.title"));
+        jobs = new Queue();
+    }
+
+    /**
+     * Start running this thread. The compiler thread will run infinitely in a
+     * loop. It will compile jobs as long as there are any jobs pending, and
+     * then wait for new jobs to be scheduled. New jobs are scheduled using the
+     * addJob method.
+     */
+    public void run()
+    {
+        Job job;
+        while (true) {
+            synchronized (this) {
+                while ((job = (Job) jobs.dequeue()) == null) {
+                    busy = false;
+                    notifyAll();
+                    try {
+                        wait();
+                    }
+                    catch (InterruptedException e) {}
+                }
+            }
+
+            job.compile();
+        }
+    }
+
+    /**
+     * Add a new job to this thread's job queue. The job will be processed by
+     * this thread some tim ein the near future. This method returns
+     * immediately.
+     */
+    public synchronized void addJob(Job job)
+    {
+        jobs.enqueue(job);
+        busy = true;
+        notifyAll();
+    }
+
+    public boolean isBusy()
+    {
+        return busy;
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompilerWarningDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompilerWarningDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..052c9b0aa47c461efdced2fd428174880a00a5ad
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/CompilerWarningDialog.java
@@ -0,0 +1,163 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+import bluej.*;
+import bluej.Config;
+
+import bluej.utility.MultiLineLabel;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+
+/**
+ * Dialog for Compiler Warning messages.  Should be used as a Singleton.  
+ * The dialog is non-modal, allowing minimisation to ignore further warnings.
+ * 
+ * @version $Id: CompilerWarningDialog.java 6215 2009-03-30 13:28:25Z polle $
+ * @author Bruce Quig
+ */
+public class CompilerWarningDialog extends JFrame implements ActionListener
+{
+    // Internationalisation
+    static final String close = Config.getString("close");
+    static final String dialogTitle = Config.getString("compiler.warningDialog.title");
+    static final String subTitle = Config.getString("compiler.warningDialog.label");
+    static final String noWarnings = Config.getString("compiler.warningDialog.noWarnings");
+    
+    private MultiLineLabel warningLabel;
+    private boolean isEmpty;  // true if there's is (logically) no text in the dialog box
+    
+    // singleton
+    private static CompilerWarningDialog dialog;
+    
+    /**
+     * Creates a new CompilerWarningDialog object.  Needs to be accessed through
+     *  static factory method, getDialog()
+     * 
+     * @param parent the frame that called the print dialog
+     */
+    private CompilerWarningDialog()
+    {
+        super(dialogTitle);
+        
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent E)
+            {
+                doClose();
+            }
+        });
+
+        JPanel mainPanel = new JPanel();
+
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+        mainPanel.setBorder(BorderFactory.createEmptyBorder(5,12,12,40));
+        mainPanel.add(Box.createVerticalStrut(
+                              BlueJTheme.dialogCommandButtonsVertical));
+
+        JLabel subTitleLabel = new JLabel(subTitle);
+        mainPanel.add(subTitleLabel);
+        mainPanel.add(Box.createVerticalStrut(10));
+                
+        warningLabel = new MultiLineLabel();
+        mainPanel.add(warningLabel);
+     
+        mainPanel.add(Box.createVerticalStrut(5));
+
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+        buttonPanel.setAlignmentX(CENTER_ALIGNMENT);
+
+        JButton closeButton = new JButton(close);
+        closeButton.addActionListener(this);
+        buttonPanel.add(closeButton);
+        getRootPane().setDefaultButton(closeButton);
+
+        mainPanel.add(buttonPanel);
+
+        getContentPane().add(mainPanel);
+        reset();
+
+    }
+    
+    public static CompilerWarningDialog getDialog()
+    {
+        if(dialog==null)
+            dialog = new CompilerWarningDialog();
+        return dialog;
+    }
+
+
+    /**
+     * ActionListener for buttons
+     * 
+     * @param evt button event (Cancel or OK)
+     */
+    public void actionPerformed(ActionEvent evt)
+    {
+        String cmd = evt.getActionCommand();
+
+        if (close.equals(cmd)) {
+            doClose();
+        }
+      
+    }
+
+  
+    /**
+     * Close action when Cancel is pressed.
+     */
+    public void doClose()
+    {
+        reset();   // clear-down any outstanding messages
+        setVisible(false);
+    }
+    
+    /**
+     * add a warning message component to the dialog
+     * If it's the first such component, overwrite any text associated
+     * with the dialog's "empty" state, otherwise, just append
+     */
+    public void addWarningMessage(String warning)
+    {
+        if(isEmpty) {
+            warningLabel.setText(warning);
+            isEmpty = false;
+        } else {
+            warningLabel.addText(warning);
+        }
+        pack();
+        if(!isVisible()) {
+            setVisible(true);            
+        }
+    }
+    
+    public void reset()
+    {
+        warningLabel.setText(noWarnings);
+        isEmpty = true;
+        pack();    
+    }
+    
+}
+  
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/Diagnostic.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/Diagnostic.java
new file mode 100644
index 0000000000000000000000000000000000000000..5263d46c5cf509c92abc2c371d9f6335660ffd0a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/Diagnostic.java
@@ -0,0 +1,151 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+import java.io.Serializable;
+
+/**
+ * A compiler diagostic (error, warning, or other note)
+ * 
+ * @author Davin McCall
+ */
+public class Diagnostic implements Serializable
+{
+    public static int ERROR = 0;
+    public static int WARNING = 1;
+    public static int NOTE = 2;
+    
+    private int type;
+    private String message;
+    private String fileName;
+    private long startLine;
+    private long startColumn;
+    private long endLine;
+    private long endColumn;
+    
+    /**
+     * Constructor for Diagnostic objects representing notes. 
+     */
+    public Diagnostic(int type, String message)
+    {
+        this.type = type;
+        this.message = message;
+    }
+    
+    /**
+     * Constructor for error and warning diagnostics associated with
+     * a particular position in the source code.
+     * 
+     * @param type  ERROR, WARNING or NOTE.
+     * @param message  The diagnostic message
+     * @param fileName The file associated with the diagnostic (might be null).
+     * @param startLine  The line where the error/problem begins (less than 1 == unknown)
+     * @param startColumn The column where the error/problem begins; must be valid if
+     *                    {@code startLine} is greater than 0. Tab stops are every 8 spaces.
+     * @param endLine    The line where the error/problem ends; must be valid if
+     *                    {@code startLine} is greater than 0
+     * @param endColumn  The column where the error/problem ends; must be valid if
+     *                    {@code startLine} is greater than 0. Tab stops are every 8 spaces.
+     */
+    public Diagnostic(int type, String message, String fileName,
+            long startLine, long startColumn, long endLine, long endColumn)
+    {
+        this.type = type;
+        this.message = message;
+        this.fileName = fileName;
+        this.startLine = startLine;
+        this.startColumn = startColumn;
+        this.endLine = endLine;
+        this.endColumn = endColumn;
+    }
+    
+    /**
+     * Get the type of the diagnostic - ERROR, WARNING or NOTE.
+     */
+    public int getType()
+    {
+        return type;
+    }
+    
+    /**
+     * Get the end column of the error. Return is valid only if {@code getStartLine()} returns
+     * a valid line number (greater than 0). Caller should be prepared for this value to be slightly
+     * inaccurate (it might extend past the actual end of the line). Tab stops are every
+     * 8 spaces.
+     */
+    public long getEndColumn()
+    {
+        return endColumn;
+    }
+    
+    /**
+     * Get the end line of the error. Return is valid only if {@code getStartLine()} returns
+     * a valid line number (greater than 0).
+     */
+    public long getEndLine()
+    {
+        return endLine;
+    }
+    
+    /**
+     * Set the diagnostic message (the message to be presented to the end user).
+     */
+    public void setMessage(String message)
+    {
+        this.message = message;
+    }
+    
+    /**
+     * Get the diagnostic message which can be presented to the end user.
+     */
+    public String getMessage()
+    {
+        return message;
+    }
+    
+    /**
+     * Get the starting column of the error/problem. Return is only valid if
+     * {@code getStartLine()} returns a valid line (greater than 0). Tab stops
+     * are every 8 spaces.
+     */
+    public long getStartColumn()
+    {
+        return startColumn;
+    }
+    
+    /**
+     * Get the starting line of the error/problem, if known. Return is valid if
+     * it is greater than 0.
+     */
+    public long getStartLine()
+    {
+        return startLine;
+    }
+    
+    /**
+     * Get the filename associated with the error/problem. May be null.
+     */
+    public String getFileName()
+    {
+        return fileName;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/EventqueueCompileObserver.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/EventqueueCompileObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..3686b264d2782161bdc1f09712cc94bb76fa2cf9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/EventqueueCompileObserver.java
@@ -0,0 +1,118 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+import java.awt.EventQueue;
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * This class adapts CompileObserver messages to run on the GUI thread.
+ * 
+ * @author Davin McCall
+ */
+final public class EventqueueCompileObserver
+    implements CompileObserver, Runnable
+{
+    private CompileObserver link;
+    private int command;
+    
+    private static final int COMMAND_START = 0;
+    private static final int COMMAND_DIAG = 1;
+    private static final int COMMAND_END = 2;
+    
+    // parameters for COMMAND_START/COMMAND_END
+    private File [] sources;
+    private boolean successful;  // COMMAND_END only
+    
+    // parameters for COMMAND_DIAG
+    private Diagnostic diagnostic;
+    // return value for COMMAND_DIAG:
+    private boolean wasShown;
+    
+    /**
+     * Constructor for EventqueueCompileObserver. The link parameter is a compiler
+     * observer; all messages will be passed on to it, but on the GUI thread.
+     */
+    public EventqueueCompileObserver(CompileObserver link)
+    {
+        this.link = link;
+    }
+    
+    /**
+     * This method switches execution to the GUI thread.
+     */
+    private void runOnEventQueue()
+    {
+        try {
+            EventQueue.invokeAndWait(this);
+        }
+        catch (InterruptedException ie) {}
+        catch (InvocationTargetException ite) { throw new RuntimeException(ite); }
+    }
+    
+    // ---------------- CompileObserver interface ---------------------
+    
+    public synchronized boolean compilerMessage(Diagnostic diagnostic)
+    {
+        command = COMMAND_DIAG;
+        this.diagnostic = diagnostic;
+        runOnEventQueue();
+        return wasShown;
+    }
+    
+    public synchronized void startCompile(File[] csources)
+    {
+        command = COMMAND_START;
+        this.sources = csources;
+        runOnEventQueue();
+    }
+
+    public synchronized void endCompile(File[] sources, boolean successful)
+    {
+        command = COMMAND_END;
+        this.sources = sources;
+        this.successful = successful;
+        runOnEventQueue();
+
+    }
+    
+    // ------------------ Runnable interface ---------------------
+    
+    public void run()
+    {
+        // We're now running on the GUI thread. Call the chained compile observer.
+        
+        switch (command) {
+            case COMMAND_START:
+                link.startCompile(sources);
+                break;
+            case COMMAND_DIAG:
+                wasShown = link.compilerMessage(diagnostic);
+                break;
+            case COMMAND_END:
+                link.endCompile(sources, successful);
+                break;
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/JavacErrorWriter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/JavacErrorWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb1f82b1b40a3ff9e20888c7126495a3adc50fbf
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/JavacErrorWriter.java
@@ -0,0 +1,249 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import bluej.utility.DialogManager;
+
+public class JavacErrorWriter extends Writer
+{
+    private boolean haserror = false, hasfollowup = false, hasWarnings = false;
+    private int ignoreCount = 0;    // when > 0, indicates number of lines to ignore
+
+    private String filename, message;
+    private String warning = "";
+    private int lineno;
+    
+    private boolean internal;
+    
+    private String lineBuf;
+    private String newLineSequence = System.getProperty("line.separator");
+    
+    public JavacErrorWriter(boolean internal)
+    {
+        this.internal = internal;
+        lineBuf = "";
+    }
+    
+    public void reset()
+    {
+        haserror = false;
+        hasfollowup = false;
+        hasWarnings = false;
+        ignoreCount = 0;
+        warning = "";
+    }
+
+    public boolean hasError()
+    {
+        return haserror;
+    }
+    
+    public boolean hasWarnings()
+    {
+        return hasWarnings;
+    }
+
+    public String getFilename()
+    {
+        return filename;
+    }
+
+    public int getLineNo()
+    {
+        return lineno;
+    }
+
+    public String getMessage()
+    {
+        return message;
+    }
+    
+    public String getWarning()
+    {
+        return warning;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.io.Writer#write(char[], int, int)
+     */
+    public void write(char[] cbuf, int off, int len)
+        throws IOException
+    {
+        int lineBufLen = lineBuf.length();
+        lineBuf += new String(cbuf, off, len);
+        
+        int startSearch = lineBufLen - newLineSequence.length() + 1;
+        if (startSearch < 0) {
+            startSearch = 0;
+        }
+        
+        int eolIndex = lineBuf.indexOf(newLineSequence, startSearch);
+        if (eolIndex != -1) {
+            String line = lineBuf.substring(0, eolIndex);
+            lineBuf = lineBuf.substring(eolIndex + newLineSequence.length());
+            processLine(line);
+        }
+    }
+
+    public void flush()
+        throws IOException
+    {
+
+    }
+
+    public void close()
+        throws IOException
+    {
+        if (lineBuf.length() != 0) {
+            processLine(lineBuf);
+            lineBuf = "";
+        }
+    }
+
+    private void processLine(String msg)
+    {
+        if (haserror)
+            return;
+            
+        if (ignoreCount > 0) {
+            ignoreCount--;
+            return;
+        }
+
+        // there are some error messages that give important information in the
+        // following lines. Try to munge it into a better message by utilising the
+        // second/third line of the error
+        if (hasfollowup) {
+            int colonPoint = 9;
+            String label = msg.substring(0, colonPoint);
+            String info = msg.substring(colonPoint).trim();
+            
+            if(label.equals("found   :")) {             // incompatible types
+                message += " - found " + info;
+            } else if (label.equals("required:")) {
+                message += " but expected " + info;
+                haserror = true;  
+            } else if (label.equals("symbol  :")) {     // unresolved symbol
+                message += " - " + info;                             
+                haserror = true;  
+            }
+            else {
+                // if not what we were expecting, bail out
+                haserror = true;  
+            }
+            
+            return;          
+        }
+
+        int first_colon = msg.indexOf(':', 0);
+        if(first_colon == -1) {
+            // no colon may mean we are processing the end of compile msgs
+            // of the form
+            // x warning(s)
+
+            if (msg.trim().endsWith("warnings") || msg.trim().endsWith("warning")) {
+                warning += msg.trim() + newLineSequence;
+                hasWarnings = true;
+                return;
+            }
+            
+            // otherwise, cannot read format of error message
+            DialogManager.showErrorWithText(null, "compiler-error", msg);
+            return;
+        }
+
+        // "unchecked" warnings for generics begin with "Note: "
+        // and the filename is everything from there to ".java uses"
+        if(msg.startsWith("Note: ")) {
+            if(internal) // set from compiler.showunchecked in the PrefMgr
+                return;
+            int uses = msg.indexOf(".java uses");
+            if(uses != -1) {
+                filename = msg.substring(5, uses) + ".java";
+            }
+            warning += msg.trim() + newLineSequence;
+            hasWarnings = true;
+            return;
+        }
+        
+        filename = msg.substring(0, first_colon);
+
+        // Windows might have a colon after drive name. If so, ignore it
+        if(! filename.endsWith(".java")) {
+            first_colon = msg.indexOf(':', first_colon + 1);
+            if(first_colon == -1) {
+                // cannot read format of error message
+                DialogManager.showErrorWithText(null, "compiler-error", msg);
+                return;
+            }
+            filename = msg.substring(0, first_colon);
+        }
+        int second_colon = msg.indexOf(':', first_colon + 1);
+        if(second_colon == -1) {
+            // cannot read format of error message
+            DialogManager.showErrorWithText(null, "compiler-error", msg);
+            return;
+        }
+
+        lineno = 0;
+        try {
+            lineno = Integer.parseInt(msg.substring(first_colon + 1, second_colon));
+        } catch(NumberFormatException e) {
+            // ignore it
+        }
+
+        message = msg.substring(second_colon + 1).trim();
+
+        if (message.startsWith("warning:")) {
+            // Record the warnings and display them to users.
+            // This may end up multi-line, so ensure that the
+            // message is broken into (single-spaced) lines
+            warning += msg.trim() + newLineSequence;
+            ignoreCount = 2;
+            // This type of warning generates an additional two lines:
+            // one is a duplicate of the source line, the next is empty
+            // other than a single caret (^) indicating the position in the line.
+            if (message.startsWith("warning: [unchecked] unchecked cast")) {
+                ignoreCount = 4;
+            }
+            else if (message.startsWith("warning: non-varargs call of varargs method with inexact argument type for last parameter")) {
+                ignoreCount = 4;
+            }
+            
+            if(!hasWarnings)
+                hasWarnings = true;           
+            return;
+        }
+
+        if (message.equals("cannot resolve symbol")
+                || message.equals("cannot find symbol")
+                || message.equals("incompatible types")) {
+            hasfollowup = true;
+        }
+        else {
+            haserror = true;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/Job.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/Job.java
new file mode 100644
index 0000000000000000000000000000000000000000..51e44d32da6f891eb601fd603a973e2221c57fd7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/Job.java
@@ -0,0 +1,106 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.List;
+
+import bluej.Config;
+import bluej.classmgr.BPClassLoader;
+
+/**
+ * A compiler "job". A list of filenames to compile + parameters.
+ * Jobs are held in a queue by the CompilerThread, which compiles them
+ * by running the job's "compile" method.
+ *
+ * @author  Michael Cahill
+ */
+class Job
+{
+    Compiler compiler;  // The compiler for this job
+    CompileObserver observer;
+    File destDir;
+    BPClassLoader bpClassLoader;
+    File sources[];
+    boolean internal; // true for compiling shell files, 
+                      // or user files if we want to suppress 
+                      // "unchecked" warnings, false otherwise
+    private List<String> userCompileOptions;
+    private Charset fileCharset;
+    
+    /**
+     * Create a job with a set of sources.
+     */
+    public Job(File[] sourceFiles, Compiler compiler, CompileObserver observer,
+                        BPClassLoader bpClassLoader, File destDir, boolean internal,
+                        List<String> userCompileOptions, Charset fileCharset)
+    {
+        this.sources = sourceFiles;
+        this.compiler = compiler;
+        this.observer = observer;
+        this.bpClassLoader = bpClassLoader;
+        this.destDir = destDir;
+        this.internal = internal;
+        this.userCompileOptions = userCompileOptions;
+        this.fileCharset = fileCharset;
+    }
+    
+    /**
+     * Compile this job
+     */
+    public void compile()
+    {
+        try {
+            if(observer != null) {
+                observer.startCompile(sources);
+            }
+
+            if(destDir != null) {
+                compiler.setDestDir(destDir);
+            }
+
+            compiler.setClasspath(bpClassLoader.getClassPathAsFiles());
+            if (bpClassLoader.loadsForJavaMEproject()) {
+                compiler.setBootClassPath(bpClassLoader.getJavaMElibsAsFiles());
+            }
+            else {
+                compiler.setBootClassPath(null);
+                String majorVersion = System.getProperty("java.specification.version"); 
+                userCompileOptions.add(0, "-source");
+                userCompileOptions.add(1, majorVersion);
+            }
+
+            boolean successful = compiler.compile(sources, observer, internal, userCompileOptions, fileCharset);
+
+            if(observer != null) {
+                observer.endCompile(sources, successful);
+            }
+        } catch(Exception e) {
+            System.err.println(Config.getString("compileException") + ": " + e);
+            e.printStackTrace();
+            if (observer != null) {
+                observer.endCompile(sources, false);
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/JobQueue.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/JobQueue.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e108370305f6334822887162cd336c5283322bd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/JobQueue.java
@@ -0,0 +1,111 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import bluej.Config;
+import bluej.classmgr.BPClassLoader;
+import bluej.pkgmgr.Project;
+import bluej.utility.Utility;
+
+/**
+ * Reasonably generic interface between the BlueJ IDE and the Java compiler.
+ * 
+ * @author Michael Cahill
+ */
+public class JobQueue
+{
+    private static JobQueue queue = null;
+
+    public static synchronized JobQueue getJobQueue()
+    {
+        if (queue == null) {
+            queue = new JobQueue();
+        }
+        return queue;
+    }
+
+    // ---- instance ----
+
+    private CompilerThread thread = null;
+    private Compiler compiler = null;
+
+    /**
+     * Construct the JobQueue. This is private; use getJobQueue() to get the job queue instance.
+     */
+    private JobQueue()
+    {
+        compiler = new CompilerAPICompiler();
+        thread = new CompilerThread();
+
+        // Lower priority to improve GUI response time during compilation
+        int priority = Thread.currentThread().getPriority() - 1;
+        priority = Math.max(priority, Thread.MIN_PRIORITY);
+        thread.setPriority(priority);
+
+        thread.start();
+    }
+
+    /**
+     * Adds a job to the compile queue.
+     * 
+     * @param sources   The files to compile
+     * @param observer  Observer to be notified when compilation begins,
+     *                  errors/warnings, completes
+     * @param classPath The classpath to use to locate objects/source code
+     * @param destDir   Destination for class files?
+     * @param suppressUnchecked    Suppress "unchecked" warning in java 1.5
+     */
+    public void addJob(File[] sources, CompileObserver observer, BPClassLoader bpClassLoader, File destDir,
+            boolean suppressUnchecked, Charset fileCharset)
+    {
+        List<String> options = new ArrayList<String>();
+        if (bpClassLoader.loadsForJavaMEproject()) {
+            String optionString = Config.getPropString(Compiler.JAVAME_COMPILER_OPTIONS, "");
+            options.addAll(Utility.dequoteCommandLine(optionString));
+        }
+        String optionString = Config.getPropString(Compiler.COMPILER_OPTIONS, "");
+        options.addAll(Utility.dequoteCommandLine(optionString));
+        
+        thread.addJob(new Job(sources, compiler, observer, bpClassLoader,
+                destDir, suppressUnchecked, options, fileCharset));
+    }
+
+    /**
+     * Wait until the compiler job queue is empty, then return.
+     */
+    public void waitForEmptyQueue()
+    {
+        synchronized (thread) {
+            while (thread.isBusy()) {
+                try {
+                    thread.wait();
+                }
+                catch (InterruptedException ex) {}
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/WriterOutputStream.java b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/WriterOutputStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..39d83ab4bda7c7aab11d9cb36d7f7a5b67e442ce
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/compiler/WriterOutputStream.java
@@ -0,0 +1,164 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.compiler;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * An output stream which decodes its input using a character set encoding,
+ * and writes the resulting characters to a Writer.
+ * 
+ * @author Davin McCall
+ */
+public class WriterOutputStream extends OutputStream
+{
+    private Charset cs = Charset.forName(System.getProperty("file.encoding"));
+    private CharsetDecoder decoder = cs.newDecoder();
+    
+    /*
+     * We use two buffers, one is a byte buffer and the other is a character buffer.
+     * Bytes written to the output stream are stored in the byte buffer. When the
+     * buffer gets full, the decoder is called; it reads from the byte buffer and
+     * writes to the character buffer. When the character buffer is full, the
+     * characters are written to the underlying writer.
+     */
+    
+    ByteBuffer inBuffer;
+    CharBuffer outBuffer;
+    
+    private Writer writer;
+
+    /**
+     * Create a new WriterOutputStream which writes to the given writer.
+     */
+    public WriterOutputStream(Writer writer)
+    {
+        this.writer = writer;
+        decoder.reset();
+        decoder.onMalformedInput(CodingErrorAction.REPLACE);
+        decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+        inBuffer = ByteBuffer.allocate(4096);
+        inBuffer.clear();
+        outBuffer = CharBuffer.allocate(4096);
+        outBuffer.clear();
+    }
+    
+    public void write(int b)
+        throws IOException
+    {
+        write(new byte[] {(byte) b}, 0, 1);
+    }
+
+    public void write(byte[] b, int off, int len)
+        throws IOException
+    {
+        int remaining = inBuffer.remaining();
+        while (len > 0) {
+            int toWrite = remaining;
+            
+            if (toWrite > len) {
+                toWrite = len;
+            }
+            
+            inBuffer.put(b, off, toWrite);
+            off += toWrite;
+            len -= toWrite;
+            
+            remaining -= toWrite;
+            if (remaining == 0) {
+                flush();
+                remaining = inBuffer.remaining();
+            }
+        }
+    }
+    
+    /**
+     * Flush the input buffer (byte buffer), as much as possible. This may
+     * leave a few undecoded bytes in the buffer.
+     * 
+     * @param endOfInput  true if there is no more input available
+     * @throws IOException
+     */
+    private void flushInBuffer(boolean endOfInput) throws IOException
+    {
+        // Prepare to read from the input buffer
+        inBuffer.flip();
+        
+        CoderResult result = decoder.decode(inBuffer, outBuffer, endOfInput);
+        while (result.isOverflow()) {
+            flushOutBuffer();
+            result = decoder.decode(inBuffer, outBuffer, endOfInput);
+        }
+        
+        // Remove processed input from the input buffer, and position for writing
+        inBuffer.compact();
+    }
+    
+    /**
+     * Flush the output buffer (character buffer). All characters which have
+     * been decoded so far will be written to the underlying writer.
+     * 
+     * @throws IOException
+     */
+    private void flushOutBuffer() throws IOException
+    {
+        outBuffer.flip();
+        writer.write(outBuffer.toString());
+        outBuffer.clear();
+    }
+    
+    /**
+     * Decode as much input as possible, write all decoded input to the
+     * underlying writer, and flush the writer.
+     * 
+     * @param endOfInput  true if there is no more input available
+     * @throws IOException
+     */
+    private void flush(boolean endOfInput)
+        throws IOException
+    {
+        flushInBuffer(endOfInput);
+        flushOutBuffer();
+        writer.flush();
+    }
+    
+    public void flush() throws IOException
+    {
+        flush(false);
+    }
+    
+    public void close() throws IOException
+    {
+        if (writer != null) {
+            flush(true);
+            writer = null;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/Debugger.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/Debugger.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef9c5e443e88d0546d179f4f0a17f5ea1cc48a29
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/Debugger.java
@@ -0,0 +1,317 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Map;
+
+import bluej.classmgr.BPClassLoader;
+import bluej.debugger.jdi.JdiDebugger;
+
+/**
+ * A class defining the debugger primitives needed by BlueJ. May be supported by different
+ * implementations, locally or remotely.
+ * 
+ * <p>Debugger has a listener interface to allow listening for certain events. Events reported to
+ * the listener are guaranteed to be serialised, that is, a callback will not be entered while
+ * the previous callback is still executing.
+ * 
+ * <p>Part of the listener interface is notification of debugger state changes. There possible
+ * states are UNKNOWN, NOTREADY, IDLE, RUNNING, SUSPENDED and LAUNCH_FAILED. Only certain
+ * transitions are possible:
+ * 
+ * <ul>
+ * <li>UNKNOWN to NOTREADY: when the debugger is first launched
+ * <li>NOTREADY to IDLE:  when the debugger finishes launching or restarting
+ * <li>IDLE to RUNNING:  when the debugger begins execution of user code
+ * <li>IDLE to NOTREADY:  when the virtual machine restarts (possibly for external reasons)
+ * <li>RUNNING to IDLE:  when user code finishes or is otherwise terminated
+ * <li>RUNNING to SUSPENDED:  when a breakpoint is hit etc.
+ * <li>SUSPENDED to RUNNING:  when execution is continued after a breakpoint etc.
+ * </ul>
+ * 
+ * Transitions that do not conform to the list are modified by inserting appropriate transitions.
+ * For instance a transition from RUNNING to NOTREADY is represented as a transition first to
+ * IDLE and then to NOTREADY. 
+ *
+ * @author  Michael Cahill
+ * @author  Michael Kolling
+ * @author  Andrew Patterson
+ */
+public abstract class Debugger
+{
+    // Set this key with a non-null value on any breakpoints that you want to
+    // persist through calls to removeBreakpointsForClass, and through the clear-all breakpoint
+    // removal that happens, for example, when a new class loader is added to the VM
+    public static final String PERSIST_BREAKPOINT_PROPERTY = "VMReference.PERSIST_BREAKPOINT";    
+    
+    public static final int NORMAL_EXIT = 0;
+    public static final int EXCEPTION = 2;
+    public static final int TERMINATED = 3;
+
+    /** Virtual machine states **/
+    /** The unknown state can only be the previous state, and only in the first state change */
+    public static final int UNKNOWN = 0;
+    /** The debugger is not yet ready to execute code etc */
+    public static final int NOTREADY = 1;
+    /** The debugger is idle: ready to execute */
+    public static final int IDLE = 2;
+    /** The debugger is currently running user code */ 
+    public static final int RUNNING = 3;
+    /** The debugger is suspended, i.e. running user code but stopped at a breakpoint/step */
+    public static final int SUSPENDED = 4;
+    /** The debugger failed to start. */
+    public static final int LAUNCH_FAILED = 5;
+
+    /**
+     * Create an instance of a debugger.
+     * The constructor for the debugger should not be
+     * a long process. Actual startup for the debug
+     * VM should go in launch().
+     * 
+     * @return  a Debugger instance
+     */
+    public static Debugger getDebuggerImpl(File startingDirectory, DebuggerTerminal terminal)
+    {
+        return new JdiDebugger(startingDirectory, terminal);
+    }
+
+    /**
+     * Set the user libraries to be added to the system classpath when the VM is launched
+     * or restarted.
+     */
+    public abstract void setUserLibraries(URL[] libraries);
+    
+    /**
+     * Launch a VM for running user code, which will be controlled by this debugger instance.
+     * This should be called only once.
+     * 
+     * <p>This can be a lengthy process so this should be executed in a sub thread.
+     */
+    public abstract void launch();
+
+    /**
+     * Terminate the debug VM, stop all user processes etc. Optionally restart afterwards.
+     */
+    public abstract void close(boolean restart);
+
+    /**
+     * Add a listener for DebuggerEvents
+     * 
+     * @param l  the DebuggerListener to add
+     * @return  the machine state at the time the listener was added
+     *          (any changes from this state will have been signalled to the listener)
+     */
+    public abstract int addDebuggerListener(DebuggerListener l);
+
+    /**
+     * Remove a listener for DebuggerEvents.
+     * 
+     * @param l  the DebuggerListener to remove
+     */
+    public abstract void removeDebuggerListener(DebuggerListener l);
+
+    /**
+     * Create a class loader in the debugger.
+     */
+    public abstract void newClassLoader(BPClassLoader bpClassLoader);
+
+    /**
+     * Remove all breakpoints in the given class.
+     */
+    public abstract void removeBreakpointsForClass(String className);
+
+    /**
+     * Add a debugger object into the project scope.
+     * 
+     * @param   scopeId          the scope identifier
+     * @param   newInstanceName  the name of the object
+     * @param   dob              the object itself
+     * @return  true if the object could be added with this name,
+     *          false if there was a name clash.
+     */
+    public abstract boolean addObject(String scopeId, String newInstanceName, DebuggerObject dob);
+
+    /**
+     * Remove a debugger object from the project scope.
+     */
+    public abstract void removeObject(String scopeId, String instanceName);
+
+    /**
+     * Return the debugger objects that exist in the
+     * debugger.
+     * 
+     * @return  a Map of (String name, DebuggerObject obj) entries
+     */
+    public abstract Map<String,DebuggerObject> getObjects();
+
+    /**
+     * Guess a suitable name for an object about to be put on the object bench.
+     * 
+     * @param  startingName  a fully qualified class name (will be stripped of
+     *                        qualifying part) or a field name that will be used
+     *                        as the basis for the new name.
+     * @return  a String suitable as a name for an object on the object bench. 
+     */
+    public abstract String guessNewName(String className);
+
+    /**
+     * Guess a suitable name for an object about to be put on the object bench.
+     * 
+     * @param obj      the object that will be put on the object bench
+     * @return a String suitable as a name for an object on the object bench.
+     */
+    public abstract String guessNewName(DebuggerObject obj);
+
+    /**
+     * Return the machine status; one of the "machine state" constants:
+     * (IDLE, RUNNING, SUSPENDED, NOTREADY).
+     */
+    public abstract int getStatus();
+    
+    /**
+     * Run the setUp() method of a test class and return the created
+     * objects.
+     * 
+     * @param className  the fully qualified name of the class
+     * @return          a Map of (String name, DebuggerObject obj) entries
+     */
+    public abstract Map<String,DebuggerObject> runTestSetUp(String className);
+
+    /**
+     * Run a single test method in a test class and return the result.
+     * 
+     * @param  className  the fully qualified name of the class
+     * @param  methodName the name of the method
+     * @return            a DebuggerTestResult object
+     */
+    public abstract DebuggerTestResult runTestMethod(String className, String methodName);
+
+    /**
+     * Dispose all top level windows in the remote machine.
+     */
+    public abstract void disposeWindows();
+
+    /**
+     * "Run" a class (i.e. invoke its main method without arguments)
+     */
+    public abstract DebuggerResult runClassMain(String className)
+        throws ClassNotFoundException;
+
+    /**
+     * Instantiate a class using the default constructor for that class.
+     * @param className  The name of the class to instantiate
+     * @return   The result of the constructor call
+     */
+    public abstract DebuggerResult instantiateClass(String className);
+
+    /**
+     * Instantiate a class using a specific constructor for that class.
+     * 
+     * @param className  The name of the class to instantiate
+     * @param argTypes   The formal parameter types (class names)
+     * @param args       The arguments
+     * @return   The result of the constructor call
+     */
+    public abstract DebuggerResult instantiateClass(String className, String [] paramTypes, DebuggerObject [] args);
+    
+    /**
+     * Get a class from the virtual machine, using the current classloader.
+     * 
+     * @param className   The name of the class to load
+     * @param initialize  Whether to initialize the class. Initialization causes execution
+     *                    of user code, which may take an arbitrary amount of time.
+     *                    Initialization will not be performed if the debugger is already
+     *                    running user code (i.e. the state is RUNNING).
+     * 
+     * @throws ClassNotFoundException if the class couldn't be located.
+     */
+    public abstract DebuggerClass getClass(String className, boolean initialize)
+        throws ClassNotFoundException;
+
+    /**
+     * Get a reference to a string in the remote machine whose value is the
+     * same as the given value. Returns null if the remote VM terminates
+     * or the string cannot be mirrored for some other reason (such as
+     * out of memory).
+     * 
+     * @param value  The string value to mirror
+     * @return       The remote object with the same value, or null
+     */
+    public abstract DebuggerObject getMirror(String value);
+
+    /**
+     * Set/clear a breakpoint at a specified line in a class.
+     *
+     * @param className  The class in which to set the breakpoint.
+     * @param line       The line number of the breakpoint.
+     * @param set        True to set, false to clear a breakpoint.
+     * @param properties Extra properties to set on the breakpoint.  Can (and usually should) be null.
+     * @return           a string of the error message generated performing
+     *                   this operation or null
+     */
+    public abstract String toggleBreakpoint(String className, int line,
+                                            boolean set, Map<String, String> properties);
+
+    /**
+     * Set/clear a breakpoint at a specified method in a class (specified by name).
+     *
+     * @param className  The class in which to set the breakpoint.
+     * @param line       The line number of the breakpoint.
+     * @param set        True to set, false to clear a breakpoint.
+     * @param properties Extra properties to set on the breakpoint.  Can (and usually should) be null.
+     * @return           a string of the error message generated performing
+     *                   this operation or null
+     */
+    public abstract String toggleBreakpoint(String className, String method, boolean set,
+                                            Map<String,String> properties);
+    
+    /**
+     * Set/clear a breakpoint at a specified method in a class.
+     * It is safe to call this method from a debugger event listener (unlike
+     * the other toggleBreakpoint() methods).
+     *
+     * @param className  The class in which to set the breakpoint.
+     * @param line       The line number of the breakpoint.
+     * @param set        True to set, false to clear a breakpoint.
+     * @param properties Extra properties to set on the breakpoint.  Can (and usually should) be null.
+     * @return           a string of the error message generated performing
+     *                   this operation or null
+     */
+    public abstract String toggleBreakpoint(DebuggerClass debuggerClass, String method, boolean set,
+            Map<String, String> properties);
+    
+    /**
+     * A tree model representing the threads running in the debug VM.
+     *  
+     * @return  a TreeModel with DebuggerThread objects
+     *          as the leaves.
+     */
+    public abstract DebuggerThreadTreeModel getThreadTreeModel();
+
+    /**
+     * Set or clear the option to hide system threads.
+     * This method also updates the current display if necessary.
+     */
+    public abstract void hideSystemThreads(boolean hide);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerClass.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..3587687900f731b5504d93440e1da90ab92a8e82
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerClass.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+import java.util.List;
+
+/**
+ * A class for representing classes in the debugged VM.
+ *
+ * @author     Michael Kolling
+ */
+public abstract class DebuggerClass
+{
+    /**
+     *  Return the name of this class (fully qualified).
+     *
+     *@return    The class name
+     */
+    public abstract String getName();
+
+    /**
+     * Get a list of static fields declared in this class.
+     */
+    public abstract List<DebuggerField> getStaticFields();
+    
+    /**
+     * Get the static field specified by the given index.
+     */
+    public DebuggerField getStaticField(int slot)
+    {
+        return getStaticFields().get(slot);
+    }
+    
+    /**
+     * Returns true if this represents a Java interface
+     * 
+     */
+    public abstract boolean isInterface();
+
+    /**
+     * Returns true if this represents an enum
+     * 
+     */
+    public abstract boolean isEnum();
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..16c07755745442002e039a432bb4c41765c4c593
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerEvent.java
@@ -0,0 +1,130 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+import java.util.EventObject;
+
+
+/**
+ * Represents an event occurring in the BlueJ debugger implementation.
+ */
+public class DebuggerEvent extends EventObject
+{
+    public static interface BreakpointProperties
+    {
+        public Object get(Object key);
+    }
+
+    /**
+     * The readiness state of the debugger changed.
+     */
+    public final static int DEBUGGER_STATECHANGED = 1;
+    /** 
+     * A thread halted, due to a step event, or because it was programmatically halted
+     * via the DebuggerThread interface.
+     * 
+     * We use the _UNKNOWN version when the exact cause is not known, and the more
+     * specific _STEP_OVER or STEP_INTO when we know it is from a step event
+     */
+    public final static int THREAD_HALT_UNKNOWN = 2;
+    public final static int THREAD_HALT_STEP_OVER = 3;
+    public final static int THREAD_HALT_STEP_INTO = 4;
+    /**
+     * A thread halted due to hitting a breakpoint.
+     */
+    public final static int THREAD_BREAKPOINT = 5;
+    /**
+     * A thread resumed execution (due to this being requested via the DebuggerThread
+     * interface).
+     */
+    public final static int THREAD_CONTINUE = 6;
+
+    private int id;
+    private DebuggerThread thr;
+    private int oldState, newState;
+    private BreakpointProperties props;
+
+    public DebuggerEvent(Object source, int id)
+    {
+        super(source);
+
+        this.id = id;
+    }
+
+    public DebuggerEvent(Debugger source, int id, DebuggerThread thr, BreakpointProperties props)
+    {
+        this(source, id);
+
+        this.thr = thr;
+        this.props = props;
+    }
+
+    public DebuggerEvent(Object source, int id, int oldState, int newState)
+    {
+        this(source, id);
+
+        this.oldState = oldState;
+        this.newState = newState;
+    }
+
+    public int getID()
+    {
+        return id;
+    }
+    
+    public boolean isHalt()
+    {
+        return id == THREAD_BREAKPOINT || id == THREAD_HALT_STEP_INTO || id == THREAD_HALT_STEP_OVER || id == THREAD_HALT_UNKNOWN;
+    }
+
+    public DebuggerThread getThread()
+    {
+        return thr;
+    }
+
+    public int getOldState()
+    {
+        return oldState;
+    }
+
+    public int getNewState()
+    {
+        return newState;
+    }
+
+    /**
+     * Get the properties associated with the breakpoint that was reached.
+     * May return null.
+     */
+    public DebuggerEvent.BreakpointProperties getBreakpointProperties()
+    {
+        return props;
+    }
+
+    @Override
+    public String toString()
+    {
+        return super.toString() + "[id=" + id + ",thr=" + thr + "]";
+    }
+    
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerField.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerField.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc1173955ccf6ad3ae1ab6d19b2a9f76f739786d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerField.java
@@ -0,0 +1,98 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+import bluej.debugger.gentype.JavaType;
+
+/**
+ * Representation of a class or object field, together with its value.
+ * 
+ * @author Davin McCall
+ */
+public abstract class DebuggerField
+{
+    /**
+     * Get the field name
+     */
+    public abstract String getName();
+    
+    /**
+     * Get the field type
+     */
+    public abstract JavaType getType();
+    
+    /**
+     * Get the field modifiers. see {@link java.lang.reflect.Modifier}.
+     */
+    public abstract int getModifiers();
+    
+    /**
+     * Get a string representation of the value of the field.
+     * For null, the string "null" will be returned.
+     * For a primitive, a string representation of the value will be returned.
+     * For a string, the return will be a quoted Java literal string expression.
+     * For any other reference type, the return will be DebuggerObject.OBJECT_REFERENCE.
+     */
+    public abstract String getValueString();
+    
+    /**
+     * If the field value is an object (or null), return it as a DebuggerObject.
+     * 
+     * @param expectedType   the known type of the field, which may be more precise than the declared type.
+     *                       May be null.
+     */
+    public abstract DebuggerObject getValueObject(JavaType expectedType);
+
+    /**
+     * Get the class which declares this field.
+     */
+    public abstract DebuggerClass getDeclaringClass();
+    
+    /**
+     * Get the qualified name of the class which declares this field.
+     */
+    public String getDeclaringClassName()
+    {
+        return getDeclaringClass().getName();
+    }
+    
+    /**
+     * Check whether this field is hidden - redefined in a subclass or ambiguously multiply inherited
+     */
+    public abstract boolean isHidden();
+    
+    /**
+     * Check whether the field type is a reference type.
+     */
+    public boolean isReferenceType()
+    {
+        return ! getType().isPrimitive();
+    }
+    
+    /**
+     * Check whether the field value is null.
+     */
+    public boolean isNull()
+    {
+        return getValueString().equals("null");
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..de80755d235146f6896f1d77a1589a056e418fd1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerListener.java
@@ -0,0 +1,74 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+/**
+ * The listener for Debugger events.
+ *
+ * <p>Debugger events are processed in two stages.
+ * 
+ * <p>First, for certain event types (including breakpoint and step events),
+ * all the events in a set are passed to examineDebuggerEvent. This method
+ * should return true to prevent debugger user interface updates from reflecting
+ * the thread stoppage; this might be done because the listener intends to resume
+ * the thread execution immediately.
+ * 
+ * <p>The result of all examineDebuggerEvent calls for an event set are ORed
+ * together and later passed to processDebuggerEvent, which should act on the
+ * boolean accordingly.  In particular, if the interface is given the value true,
+ * it should not update.
+ * 
+ * <p>Calls to examineDebuggerEvent() and processDebuggerEvent() are synchronous,
+ * that is:
+ * <ul>
+ * <li>A single set of events is handled at a time. Such a set will include events
+ * affecting only a single thread.
+ * <li>examineDebuggerEvent() will be called for each event in the set, in series.
+ * <li>processDebuggerEvent() will then be called for each event in the set, in series.
+ * <li>The processing of two separate event sets will occur in series.
+ * </ul>
+ * 
+ * @see DebuggerEvent
+ */
+public interface DebuggerListener
+{
+    /**
+     * Examines the debugger event -- a precursor to a call to
+     * processDebuggerEvent. This should return true if the event should not
+     * cause the debugger UI to be updated.
+     * 
+     * <p>Related events (belonging to the same thread) will all be processed
+     * before being passed on to processDebuggerEvent().
+     * 
+     * @see #processDebuggerEvent(DebuggerEvent, boolean)
+     */
+    boolean examineDebuggerEvent(DebuggerEvent e);
+    
+    /**
+     * Called after examineDebuggerEvent to process an event.
+     * 
+     * @param skipUpdate   true if any listener requested that
+     *                  the UI not be updated due to this event
+     *                 (or another event in this event set).
+     */
+    void processDebuggerEvent(DebuggerEvent e, boolean skipUpdate);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerObject.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..22a2b5ebc2cd4a7b31c3e88f1ec20de058f204fd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerObject.java
@@ -0,0 +1,135 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.JavaType;
+
+/**
+ * A class representing an object, and its type, in the debugged VM. The "null" value
+ * can also be represented.
+ *
+ * @author     Michael Kolling
+ */
+public abstract class DebuggerObject
+{
+    public static final String OBJECT_REFERENCE = "<object reference>";
+    
+    /**
+     * Get the fully qualified name of the class of this object.
+     * If this object is the "null object", return an empty string.
+     *
+     * @return  the fully qualified class name
+     */
+    public abstract String getClassName();
+    
+    /**
+     *  Get the class of this object.
+     *
+     *  @return    The class object.
+     */
+    public abstract DebuggerClass getClassRef();
+    
+    /**
+     * Get the complete generic type of this object, if known. If not known, the raw
+     * dynamic type of the object is returned, or null if this is the null object.
+     * 
+     * @return    The object type (or null for the null object).
+     */
+    public abstract GenTypeClass getGenType();
+
+    /**
+     *  Return true if this object is an array.
+     *
+     *@return    The Array value
+     */
+    public abstract boolean isArray();
+
+    /**
+     * Return true if this object has a null value
+     */
+    public abstract boolean isNullObject();
+
+    /**
+     * Get all field/value pairs for the object.
+     */
+    public abstract List<DebuggerField> getFields();
+    
+    /**
+     * Get a field/value pair, specified by index. 
+     */
+    public DebuggerField getField(int slot)
+    {
+        return getFields().get(slot);
+    }
+    
+    /**
+     * Get an instance field/value pair, specified by index.
+     */
+    public DebuggerField getInstanceField(int slot)
+    {
+        for (DebuggerField field : getFields()) {
+            if (! Modifier.isStatic(field.getModifiers())) {
+                if (slot == 0) {
+                    return field;
+                }
+                slot--;
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Return the number of array elements. Returns -1 if the object is not an array.
+     */
+    public abstract int getElementCount();
+
+    /**
+     * Return the array element type. Returns null if the object is not an array.
+     */
+    public abstract JavaType getElementType();
+    
+    /**
+     * Return the array element object for the specified index.
+     */
+    public abstract DebuggerObject getElementObject(int index);
+    
+    /**
+     * Return a string representation of the array element at the specified index.
+     * For null, the string "null" will be returned.
+     * For a primitive, a string representation of the value will be returned.
+     * For a string, the return will be a quoted Java literal string expression.
+     * For any other reference type, the return will be DebuggerObject.OBJECT_REFERENCE.
+     */
+    public abstract String getElementValueString(int index);
+
+    /**
+     * Return the JDI object. This exposes the JDI to Inspectors.
+     * If JDI is not being used, it should return null.
+     *
+     * @return    The ObjectReference value
+     */
+    public abstract com.sun.jdi.ObjectReference getObjectReference();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerResult.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..7409939beaa0c708d199c22abd444bf1d8060471
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerResult.java
@@ -0,0 +1,93 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+/**
+ * This class represents the result of a debugger invocation (execution of user code).
+ * The three result types are:
+ *  NORMAL_EXIT - execution completed normally, result object may be available
+ *  EXCEPTION - execution terminated via an exception, ExceptionDescription available
+ *  TERMINATED - remote VM terminated before execution completed (possibly result of
+ *                System.exit() call).
+ * 
+ * @author Davin McCall
+ */
+public class DebuggerResult
+{
+    private int exitStatus; // one of Debugger.NORMAL_EXIT, EXCEPTION, TERMINATED
+    private DebuggerObject resultObject;
+    private ExceptionDescription exception;
+    
+    /**
+     * Construct a DebuggerResult for a normal completion.
+     * @param resultObject  The result of the execution.
+     */
+    public DebuggerResult(DebuggerObject resultObject)
+    {
+        exitStatus = Debugger.NORMAL_EXIT;
+        this.resultObject = resultObject;
+    }
+    
+    /**
+     * Construct a DebuggerResult for an execution which resulted in an exception.
+     */
+    public DebuggerResult(ExceptionDescription exception)
+    {
+        exitStatus = Debugger.EXCEPTION;
+        this.exception = exception;
+    }
+    
+    public DebuggerResult(int status)
+    {
+        exitStatus = status;
+    }
+    
+    /**
+     * Get the status of the invocation. Returns one of:
+     * <ul>
+     * <li>Debugger.NORMAL_EXIT - the invocation succeeded
+     * <li>Debugger.EXCEPTION   - an exception occurred in the invoked code
+     * <li>Debugger.TERMINATED  - the debug VM exited (possibly due to a
+     *                            System.exit() call)
+     * </ul>
+     * @return
+     */
+    public int getExitStatus()
+    {
+        return exitStatus;
+    }
+    
+    /**
+     * Returns the result of the invocation as a DebuggerObject.
+     * This is only valid for a NORMAL_EXIT; any other invocation
+     * result will cause this method to return null.
+     */
+    public DebuggerObject getResultObject()
+    {
+        return resultObject;
+    }
+    
+    public ExceptionDescription getException()
+    {
+        return exception;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerTerminal.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerTerminal.java
new file mode 100644
index 0000000000000000000000000000000000000000..59a6108980bf18b46224d7d7739470287b78d888
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerTerminal.java
@@ -0,0 +1,38 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+import java.io.*;
+
+/**
+ *
+ * @author  Andrew Patterson
+ * @version $Id: DebuggerTerminal.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface DebuggerTerminal
+{
+    Writer getErrorWriter();
+
+    Writer getWriter();
+
+    Reader getReader();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerTestResult.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerTestResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..badf258d17175124111f286e5f07ba39568d87fb
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerTestResult.java
@@ -0,0 +1,113 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+/**
+ * A class representing the running of a single test
+ * method.
+ *
+ * @author  Andrew Patterson
+ */
+public abstract class DebuggerTestResult
+{
+    /**
+     * Return the fully qualified name of the test method.
+     * 
+     * @return  the name of the test method in the
+     *          form ClassName.methodName
+     */
+    public String getName()
+    {
+        return getQualifiedClassName() + "." + getMethodName();
+    }
+
+    
+    /**
+     * Get the name of the test method.
+     */
+    public abstract String getMethodName();
+
+    /**
+     * Get the fully qualified class name which the test method belongs to
+     */
+    public abstract String getQualifiedClassName();
+
+    /**
+     * Return the run time of the test in milliseconds
+     * 
+     * @return  the total running time of the test in
+     *          milliseconds
+     */
+    abstract public int getRunTimeMs();
+    
+    /**
+     * Return whether this test method was a success.
+     * 
+     * @return  true if this test was a success
+     */
+    abstract public boolean isSuccess();
+    
+    /**
+     * If !isSuccess then this returns true if the
+     * test result was an expected 'failure'.
+     * 
+     * @return  true if this test resulted in a failure
+     */
+    abstract public boolean isFailure();
+    
+    /**
+     * If !isSuccess then this returns true if the
+     * test result was an unexpected 'error'.
+     * 
+     * @return  true if this test resulted in an error
+     */
+    abstract public boolean isError();
+    
+    /**
+     * Return a stack trace for the test failure/error.
+     * 
+     * This method can be called only when the test
+     * resulted in a failure or an error.
+     * 
+     * @return  a String of the stack trace of the failure/error
+     */
+    abstract public String getTrace();
+    
+    /**
+     * Return an exception message for the test failure/error.
+     * 
+     * This method can be called only when the test
+     * resulted in a failure or an error.
+     * 
+     * @return  a String of the details of the exception thrown
+     */
+    abstract public String getExceptionMessage();
+    
+    /**
+     * Return the location of the failure/error point (ie. the point where
+     * the exception was thrown). May return null if the information is not
+     * available.
+     * 
+     * @return  a SourceLocation with the details of the failure point
+     */
+    abstract public SourceLocation getExceptionLocation();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerThread.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..2588fdac464b8b2b1db2624938302e09a4dd81d2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerThread.java
@@ -0,0 +1,89 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+import java.util.List;
+
+/**
+ * A class defining the debugger thread primitives needed by BlueJ.
+ *
+ * @author  Michael Cahill
+ * @author  Michael Kolling
+ * @author  Andrew Patterson
+ */
+public abstract class DebuggerThread
+{
+    public abstract String getName();
+
+    public abstract String getStatus();
+
+    public abstract boolean isSuspended();
+    public abstract boolean isAtBreakpoint();
+
+    public abstract String getClass(int frameNo);
+    public abstract String getClassSourceName(int frameNo);
+    public abstract int getLineNumber(int frameNo);
+    public abstract boolean isKnownSystemThread();
+
+    /**
+     * Get the current execution of the stack. This is only reliable if the
+     * thread is currently halted.
+     */
+    public abstract List<SourceLocation> getStack();
+    
+    public abstract List<String> getLocalVariables(int frameNo);
+    public abstract boolean varIsObject(int frameNo, int index);
+    public abstract DebuggerObject getStackObject(int frameNo, int index);
+    
+    /**
+     * Return the current instance object of some frame on this thread.
+     * The returned object may represent the null reference if the frame
+     * is for a static method.
+     */
+    public abstract DebuggerObject getCurrentObject(int frameNo);
+    
+    /**
+     * Return the current class of this thread (may return null if the
+     * class cannot be determined).
+     */
+    public abstract DebuggerClass getCurrentClass(int frameNo);
+
+    public abstract void setSelectedFrame(int frame);
+    public abstract int getSelectedFrame();
+
+    public abstract void halt();
+    public abstract void cont();
+
+    /**
+     * Step to the next line in the current method. This is only valid when the thread is
+     * suspended. It is safe to call this from a DebuggerListener.
+     */
+    public abstract void step();
+
+    /**
+     * Step to the next executed line (which might be in a called method). This is only valid when the
+     * thread is suspended. It is safe to call this from a DebuggerListener.
+     */
+    public abstract void stepInto();
+    
+    public abstract boolean sameThread(DebuggerThread thread);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerThreadTreeModel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerThreadTreeModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e1ef7a69b67990495805cf9bf6501c10bbcd7c9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/DebuggerThreadTreeModel.java
@@ -0,0 +1,79 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+
+/**
+ * An interface defining the trees the debugger uses to represent threads.
+ * 
+ * The primary objects that we should be dealing with are the standard TreeModel
+ * objects. The special functions added in this interface are the only way we
+ * can map those TreeModel nodes into usable DebuggerThread objects and visa
+ * versa.
+ * 
+ * The TreeModel is used as the model for a Swing tree widget (JTree). A
+ * synchronisation mechanism must be provided to ensure that modifications to
+ * the tree only occur on the event handling thread.
+ * 
+ * @author Andrew Patterson
+ * @version $Id: DebuggerThreadTreeModel.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface DebuggerThreadTreeModel
+    extends TreeModel
+{
+    /**
+     * Return the DebuggerThread object stored in a tree node.
+     * 
+     * @param node
+     *            an object returned from one of the TreeModel methods ie.
+     *            getChild(), getRoot() etc
+     * @return the DebuggerThread represented by this node or null if this node
+     *         does not represent a DebuggerThread.
+     */
+    public DebuggerThread getNodeAsDebuggerThread(Object node);
+
+    /**
+     * Find a node path in the tree that leads to a particular DebuggerThread.
+     * 
+     * @param thr
+     *            the DebuggerThread to look for
+     * @return the TreePath to a node holding the thr or null if one does not
+     *         exist
+     */
+    public TreePath findNodeForThread(DebuggerThread thr);
+
+    /**
+     * Define the interface for a synchronization method.
+     */
+    public interface SyncMechanism
+    {
+        public void invokeLater(Runnable r);
+    }
+
+    /**
+     * Set the synchronisation method used to control access to the tree model.
+     * This can be used to enforce Swing threading safety.
+     */
+    public void setSyncMechanism(SyncMechanism s);
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/ExceptionDescription.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/ExceptionDescription.java
new file mode 100644
index 0000000000000000000000000000000000000000..03b932b70045d7987f24d306cdfc806473245838
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/ExceptionDescription.java
@@ -0,0 +1,90 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+import java.util.List;
+
+/**
+ * A description of an exception.
+ *
+ * @author Michael Kolling
+ */
+public final class ExceptionDescription
+{
+    private String className;
+    private String text;
+    private List<SourceLocation> stack;
+
+    /**
+     * Construct an exception description.
+     * 
+     * @param className  The name of the exception class
+     * @param text       The exception message
+     * @param stack      The stack trace for the exception
+     */
+    public ExceptionDescription(String className, String text, 
+                                List<SourceLocation> stack)
+    {
+        this.className = className;
+        this.text = text;
+        this.stack = stack;
+    }
+
+    public ExceptionDescription(String text)
+    {
+        this.className = null;
+        this.text = text;
+        this.stack = null;
+    }
+
+    /**
+     * Return the name of the exception class.
+     */
+    public String getClassName()
+    {
+        return className;
+    }
+
+    /**
+     * Return the text of the exception.
+     */    
+    public String getText()
+    {
+        return text;
+    }
+
+    /**
+     * Return the stack (a list of SourceLocation objects) for the exception
+     * location. Element 0 in the list is the current frame, higher numbers
+     * are caller frames.
+     */
+    public List<SourceLocation> getStack()
+    {
+        return stack;
+    }
+
+    public String toString()
+    {
+        return className + ": " + text;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/SourceLocation.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/SourceLocation.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c140966c337c57b6ae30b98843cc00be2b06ef9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/SourceLocation.java
@@ -0,0 +1,73 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger;
+
+/**
+ * This class holds a location in some source code
+ *
+ * @author  Michael Kolling
+ * @version $Id: SourceLocation.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public final class SourceLocation
+{
+    private String classname;
+    private String filename;
+    private String methodname;
+    private int lineNumber;
+
+    public SourceLocation(String classname, String filename, 
+                          String methodname, int lineNumber)
+    {
+        this.classname = classname;
+        this.filename = filename;
+        this.methodname = methodname;
+        this.lineNumber = lineNumber;
+    }
+
+    public String getClassName()
+    {
+        return classname;
+    }
+
+    public String getFileName()
+    {
+        return filename;
+    }
+
+    public String getMethodName()
+    {
+        return methodname;
+    }
+
+    public int getLineNumber()
+    {
+        return lineNumber;
+    }
+    
+    /**
+     * Return the location in the format "<class>.<method>"
+     */
+    public String toString()
+    {
+        return classname + "." + methodname;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/BadInheritanceChainException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/BadInheritanceChainException.java
new file mode 100644
index 0000000000000000000000000000000000000000..a21f67298a094b8d62399c477bca03e02abeb874
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/BadInheritanceChainException.java
@@ -0,0 +1,36 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+/**
+ * Certain methods perform mappings of type parameters between a superclass
+ * and subclass. This exception is thrown when the given classes have no
+ * inheritance relationship (the "superclass" is not really a superclass of the
+ * subclass).
+ * 
+ * @author Davin McCall
+ * @version $Id: BadInheritanceChainException.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class BadInheritanceChainException extends RuntimeException
+{
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/FieldReflective.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/FieldReflective.java
new file mode 100644
index 0000000000000000000000000000000000000000..60662c3c76bd898832143fa56c768fce80c31169
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/FieldReflective.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+/**
+ * This class represents a field in a Java type represented
+ * by a Reflective.
+ * 
+ * @author Davin McCall
+ */
+public class FieldReflective
+{
+    private String name;
+    private JavaType type;
+    private int modifiers;
+    
+    public FieldReflective(String name, JavaType type, int modifiers)
+    {
+        this.name = name;
+        this.type = type;
+        this.modifiers = modifiers;
+    }
+    
+    public String getName()
+    {
+        return name;
+    }
+    
+    public JavaType getType()
+    {
+        return type;
+    }
+    
+    public int getModifiers()
+    {
+        return modifiers;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeArray.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..f68e7a18cd59ccb00adce09da3bdb77459b82b5a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeArray.java
@@ -0,0 +1,218 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.utility.JavaReflective;
+
+/**
+ * A specialization of GenTypeClass for arrays.
+ * 
+ * @author Davin McCall
+ */
+public class GenTypeArray extends GenTypeSolid
+{
+    JavaType baseType;
+    
+    /**
+     * Construct a new GenTypeArray, with the given component type.
+     */
+    public GenTypeArray(JavaType baseType)
+    {
+        super();
+        this.baseType = baseType;
+    }
+
+    public String toString(boolean stripPrefix)
+    {
+        return baseType.toString(stripPrefix) + "[]";
+    }
+    
+    public String toString(NameTransform nt)
+    {
+        return baseType.toString(nt) + "[]";
+    }
+
+    @Override
+    public String toTypeArgString(NameTransform nt)
+    {
+        return toString(nt);
+    }
+
+    public String arrayComponentName()
+    {
+        return "[" + baseType.getUpperBound().arrayComponentName();
+    }
+    
+    @Override
+    public JavaType getCapture()
+    {
+        JavaType baseCap = baseType.getCapture();
+        if (baseCap == baseType) {
+            return this;
+        }
+        return baseCap.getArray();
+    }
+        
+    public JavaType getArrayComponent()
+    {
+        return baseType;
+    }
+    
+    public GenTypeSolid getLowerBound()
+    {
+        return this;
+    }
+
+    @Override
+    public boolean equals(JavaType other)
+    {
+        return baseType.equals(other.getArrayComponent());
+    }
+    
+    @Override
+    public void erasedSuperTypes(Set<Reflective> s)
+    {
+        GenTypeSolid baseSolid = baseType.getUpperBound().asSolid();
+        if (baseSolid != null) {
+            Set<Reflective> bSupers = new HashSet<Reflective>();
+            baseSolid.erasedSuperTypes(bSupers);
+            for (Reflective r : bSupers) {
+                s.add(r.getArrayOf());
+            }
+        }
+        else {
+            // Must be primitive
+            Class<?> aClass = null;
+            JavaType baseType = this.baseType.getUpperBound();
+            if (baseType.typeIs(JT_VOID)) {
+                aClass = void.class;
+            }
+            else if (baseType.typeIs(JT_BOOLEAN)) {
+                aClass = boolean.class;
+            }
+            else if (baseType.typeIs(JT_BYTE)) {
+                aClass = byte.class;
+            }
+            else if (baseType.typeIs(JT_CHAR)) {
+                aClass = char.class;
+            }
+            else if (baseType.typeIs(JT_DOUBLE)) {
+                aClass = double.class;
+            }
+            else if (baseType.typeIs(JT_FLOAT)) {
+                aClass = float.class;
+            }
+            else if (baseType.typeIs(JT_INT)) {
+                aClass = int.class;
+            }
+            else if (baseType.typeIs(JT_LONG)) {
+                aClass = long.class;
+            }
+            s.add(new JavaReflective(aClass).getArrayOf());
+        }
+    }
+    
+    @Override
+    public GenTypeArray getArray()
+    {
+        return new GenTypeArray(this);
+    }
+    
+    @Override
+    public JavaType getErasedType()
+    {
+        JavaType baseErased = baseType.getErasedType();
+        if (baseErased == baseType) {
+            return this;
+        }
+        else {
+            return baseErased.getArray();
+        }
+    }
+    
+    @Override
+    public void getParamsFromTemplate(Map<String, GenTypeParameter> map,
+            GenTypeParameter template)
+    {
+        GenTypeParameter ntemplate = template.getArrayComponent();
+        if (ntemplate != null) {
+            baseType.getParamsFromTemplate(map, ntemplate);
+        }
+    }
+        
+    @Override
+    public GenTypeClass[] getReferenceSupertypes()
+    {
+        // There's not really much we can do here
+        return new GenTypeClass[0];
+    }
+    
+    @Override
+    public GenTypeParameter mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams)
+    {
+        GenTypeParameter mappedBase = baseType.mapTparsToTypes(tparams);
+        if (mappedBase != baseType) {
+            if (mappedBase.isWildcard()) {
+                // An array of wildcard should be represented instead as a wildcard
+                // with array bounds.
+                GenTypeSolid ubound = mappedBase.getUpperBound().asSolid();
+                ubound = (ubound == null) ? ubound : ubound.getArray();
+                GenTypeSolid lbound = mappedBase.getLowerBound();
+                lbound = (lbound == null) ? lbound : lbound.getArray();
+                new GenTypeWildcard(ubound, lbound);
+            }
+            return mappedBase.getUpperBound().getArray();
+        }
+        return this;
+    }
+    
+    @Override
+    public boolean isAssignableFrom(JavaType t)
+    {
+        JavaType componentType = t.getArrayComponent();
+        if (componentType != null) {
+            return baseType.getCapture().isAssignableFrom(componentType);
+        }
+        return false;
+    }
+    
+    @Override
+    public boolean isAssignableFromRaw(JavaType t)
+    {
+        JavaType componentType = t.getArrayComponent();
+        if (componentType != null) {
+            return baseType.getCapture().isAssignableFromRaw(componentType);
+        }
+        return false;
+    }
+    
+    @Override
+    public boolean isInterface()
+    {
+        return false;
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeArrayClass.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeArrayClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..48b77dac4e06c6fef20b9b56295fe0e2772ca12d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeArrayClass.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+/**
+ * This class represents array types for which we have a reflective.
+ * 
+ * @author Davin McCall
+ */
+public class GenTypeArrayClass extends GenTypeClass
+{
+    private JavaType componentType;
+    
+    public GenTypeArrayClass(Reflective r, JavaType componentType)
+    {
+        super(r);
+        this.componentType = componentType;
+    }
+
+    @Override
+    public JavaType getArrayComponent()
+    {
+        return componentType;
+    }
+    
+    @Override
+    public String toString(NameTransform nt)
+    {
+        return componentType.toString(nt) + "[]";
+    }
+    
+    @Override
+    public GenTypeClass getErasedType()
+    {
+        JavaType newComponentType = componentType.getErasedType();
+        if (newComponentType != componentType) {
+            return new GenTypeArrayClass(reflective, newComponentType);
+        }
+        else {
+            return this;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeCapture.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeCapture.java
new file mode 100644
index 0000000000000000000000000000000000000000..486a06920bd738a4a62b4dfd4f53ecfa6e07a732
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeCapture.java
@@ -0,0 +1,77 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.Map;
+
+/**
+ * Represents the capture of a type parameter.
+ * 
+ * <p>See capture conversion in the Java Language Specification, section 5.1.12. Instances
+ * of this class represent the "fresh type variable" mentioned there. 
+ * 
+ * @author Davin McCall
+ */
+public class GenTypeCapture extends GenTypeTpar
+{
+    private GenTypeWildcard wildcard;
+    
+    public GenTypeCapture(GenTypeWildcard wildcard)
+    {
+        super("?capture?");
+        this.wildcard = wildcard;
+    }
+    
+    public String toString(boolean stripPrefix)
+    {
+        return wildcard.toString(stripPrefix);
+    }
+    
+    public String toString(NameTransform nt)
+    {
+        return wildcard.toString(nt);
+    }
+    
+    public String toTypeArgString(NameTransform nt)
+    {
+        return wildcard.toTypeArgString(nt);
+    }
+    
+    @Override
+    public GenTypeSolid mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams)
+    {
+        return new GenTypeCapture((GenTypeWildcard) wildcard.mapTparsToTypes(tparams));
+    }
+
+    @Override
+    public String arrayComponentName()
+    {
+        return null;
+    }
+
+    @Override
+    public JavaType getErasedType()
+    {
+        return wildcard.getUpperBound().getErasedType();
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeClass.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..81cf7f4e3158a77a4b13fd31cbf793b2e9f463f7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeClass.java
@@ -0,0 +1,744 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.*;
+
+/**
+ * Represent a (possibly generic) type. This can include wildcard types,
+ * type parameters, etc; ie. anything that JDK 1.5 "Type" can represent. 
+ * 
+ * Objects of this type are immutable.
+ * 
+ * @author Davin McCall
+ */
+public class GenTypeClass extends GenTypeSolid
+{
+    // ---------- Instance fields -----------
+    
+    /** List of type parameters; null if none (there may be an outer class with parameters) */
+    protected List<? extends GenTypeParameter> params = null;
+    protected Reflective reflective = null;
+    /** Outer class, *iff* an outer class has type parameters; otherwise null */
+    protected GenTypeClass outer = null; // outer class of this class
+    
+    // ---------- Constructors -------------
+    
+    /**
+     * Constructor for a non-generic class type.
+     * 
+     * @param r   The Reflective representing the class.
+     */
+    public GenTypeClass(Reflective r)
+    {
+        reflective = r;
+    }
+    
+    /**
+     * New GenTypeClass from a reflective and an ordered list of type parameters
+     * 
+     * @param r  The Reflective representing the class.
+     * @param params  A list of GenTypeParameterizables giving the type
+     *                  parameters in declaration order
+     */
+    public GenTypeClass(Reflective r, List<GenTypeParameter> params)
+    {
+        this(r, params, null);
+    }
+    
+    /**
+     * New GenTypeClass from a reflective and an ordered list of type
+     * parameters, representing an inner class of a specified class.
+     * This should only be used if the outer class is generic AND this inner
+     * class is a non-static inner class.<p>
+     * 
+     * <i>outer</i> may be null, to specify no outer class. In this case this
+     * constructor is equivalent to GenTypeClass(r, params). 
+     * 
+     * @param r  The Reflective representing the class.
+     * @param params  A list of GenTypeParameter giving the type
+     *                  parameters in declaration order
+     */
+    public GenTypeClass(Reflective r, List<? extends GenTypeParameter> params, GenTypeClass outer)
+    {
+        reflective = r;
+        if (params != null && ! params.isEmpty()) {
+            this.params = params;
+        }
+        this.outer = outer;
+    }
+    
+    /**
+     * New GenTypeClass from a reflective and map of type parameter names to
+     * types. For type parameters not in the map, the base type is used (as
+     * a wilcard with "extends" clause). If the map is null however, the type
+     * is treated as a raw type.
+     * 
+     * @param r  The Reflective representing the class.
+     * @param mparams  A map of String -> GenTypeParameter giving the
+     *                 type parameters. The map may be modified (if it is not
+     *                 empty) by this constructor.
+     */
+    public GenTypeClass(Reflective r, Map<String,GenTypeParameter> mparams)
+    {
+        reflective = r;
+        
+        // if mparams == null, this is a raw type. Nothing more to do.
+        if (mparams == null) {
+            return;
+        }
+        
+        List<GenTypeParameter> params = new ArrayList<GenTypeParameter>();
+        
+        Iterator<GenTypeDeclTpar> declParmsI = r.getTypeParams().iterator();
+        while( declParmsI.hasNext() ) {
+            GenTypeDeclTpar next = declParmsI.next();
+            String nextName = next.getTparName();
+            if(mparams.get(nextName) == null)
+                params.add(new GenTypeExtends(next.getBound()));
+            else {
+                params.add((GenTypeParameter) mparams.get(nextName));
+                mparams.remove(nextName);
+            }
+        }
+        if (params.isEmpty()) {
+            params = null;
+        }
+
+        this.params = params;
+        
+        // If there are still entries in the map, they may belong to an outer class
+        if (! mparams.isEmpty() && ! r.isStatic()) {
+            Reflective outerReflective = r.getOuterClass();
+            if (outerReflective != null) {
+                outer = new GenTypeClass(outerReflective, mparams);
+            }
+        }
+    }
+    
+    // ---------- instance methods -------------
+
+    public GenTypeClass asClass()
+    {
+        return this;
+    }
+    
+    public GenTypeClass getErasedType()
+    {
+        return new GenTypeClass(reflective);
+    }
+        
+    /**
+     * Get the name of the type as known to the classloader. The name returned is
+     * encoded so that it can be passed to a ClassLoader's "loadClass" method (dots
+     * between outer and inner class names are changed to '$', and arrays are
+     * encoded).
+     */
+    public String classloaderName()
+    {
+        return reflective.getName();
+    }
+    
+    public String arrayComponentName()
+    {
+        return "L" + classloaderName() + ";";
+    }
+    
+    /**
+     * Return an unmodifiable list of the type parameters applied to the
+     * innermost class in this generic type. 
+     */
+    public List<? extends GenTypeParameter> getTypeParamList()
+    {
+        if (params == null)
+            return Collections.emptyList();
+        else
+            return params;
+    }
+    
+    /**
+     * Get the containing type. If this is a generic type whose class is an
+     * inner class, and an outer class is also generic, this will return the
+     * outer class of the class type. NOTE, it will not necessarily work if
+     * no outer class is generic, or if this is a raw type!
+     */
+    public GenTypeClass getOuterType()
+    {
+        return outer;
+    }
+    
+    /**
+     * Determine whether this class is an inner type. This works regardless
+     * of whether outer types are generic etc.
+     */
+    public boolean isInnerType()
+    {
+        return reflective.getName().indexOf('$') != -1;
+    }
+    
+    /**
+     * Check whether the type is a generic type (with type parameters).
+     * Returns false for parameterless types and raw types.
+     * 
+     * @return  true if the type has type parameters
+     */
+    public boolean isGeneric()
+    {
+        if (outer != null)
+            return true;
+        else
+            return (params != null);
+    }
+    
+    /**
+     * Check whether this is a raw type, ie. a generic class type with no
+     * type parameter substitutions supplied. (Return is false for a non-
+     * generic class type).
+     * 
+     * @return  true if the type is a raw type
+     */
+    public boolean isRaw()
+    {
+        // Outer class should only have been specified if it is generic -
+        // and it is not possible for the inner class to be raw if the outer
+        // is not also raw (or, if it is, the outer should be treated as
+        // raw anyway).
+        if (outer != null || params != null) {
+            return false;
+        }
+        
+        Reflective r = reflective;
+        List<?> formalParams = reflective.getTypeParams();
+        while (formalParams.isEmpty()) {
+            if (r.isStatic()) {
+                return false;
+            }
+            r = r.getOuterClass();
+            if (r == null) {
+                return false;
+            }
+            formalParams = r.getTypeParams();
+        }
+        
+        return true;
+    }
+
+    public boolean isInterface()
+    {
+        return reflective.isInterface();
+    }
+    
+    // transform is only applied to outermost class
+    public String toString(NameTransform nt)
+    {
+        String baseClass = classloaderName();
+
+        if (outer != null) {
+            int i = baseClass.lastIndexOf('$');
+            baseClass = outer.toString(nt) + '.' + baseClass.substring(i + 1);
+        }
+        else {
+            baseClass = nt.transform(baseClass);
+            baseClass = baseClass.replace('$', '.');
+        }
+
+        // Append type parameters, if any
+        if(params == null)
+            return baseClass;
+        String r = baseClass + '<';
+        for(Iterator<? extends GenTypeParameter> i = params.iterator(); i.hasNext(); ) {
+            r += i.next().toTypeArgString(nt);
+            if( i.hasNext() )
+                r += ',';
+        }
+        r += '>';
+        return r;
+    }
+    
+    public String toTypeArgString(NameTransform nt)
+    {
+        return toString(nt);
+    }
+    
+    public boolean equals(JavaType other)
+    {
+        if (other == this)
+            return true;
+        if (other == null)
+            return false;
+        
+        GenTypeClass oClass = other.asClass();
+        if (oClass == null) {
+            return false;
+        }
+        
+        JavaType arrayComponent = getArrayComponent();
+        JavaType oarrayComponent = oClass.getArrayComponent();
+        if (arrayComponent != null) {
+            return arrayComponent.equals(oarrayComponent);
+        }
+        else if (oarrayComponent != null) {
+            return false;
+        }
+        
+        // the class name must match
+        if (! classloaderName().equals(oClass.classloaderName()))
+            return false;
+        
+        // outer class (if any) must match
+        if (outer == null && oClass.outer != null)
+            return false;
+        if (outer != null)
+            if (! outer.equals(oClass.outer))
+                return false;
+        
+        if (params == null && oClass.params == null)
+            return true;
+        if (params == null && oClass.params != null)
+            return false;
+        if (params != null && oClass.params == null)
+            return false;
+        
+        Iterator<? extends GenTypeParameter> i = params.iterator();
+        Iterator<? extends GenTypeParameter> j = oClass.params.iterator();
+        
+        // All the parameter types must match...
+        while( i.hasNext() ) {
+            if( ! j.hasNext() || ! i.next().equals(j.next())) {
+                return false;
+            }
+        }
+        
+        // and there must be the same number of parameters
+        if( j.hasNext() )
+            return false;
+
+        return true;
+    }
+    
+    /**
+     * Get the reflective represented by this GenTypeClass. This can return null
+     * if the GenTypeClass represents an array.
+     */
+    public Reflective getReflective()
+    {
+        return reflective;
+    }
+    
+    /*
+     * Note this does not handle boxing/unboxing conversions.
+     * 
+     *  (non-Javadoc)
+     * @see bluej.debugger.gentype.JavaType#isAssignableFrom(bluej.debugger.gentype.JavaType)
+     */
+    public boolean isAssignableFrom(JavaType t)
+    {
+        if (t.isNull())
+            return true;
+        
+        if (! (t instanceof GenTypeSolid) )
+            return false;
+        
+        GenTypeClass tc = t.asClass();
+        if (tc != null) {
+            // If this type is raw, no need to bother with type parameters
+            if (isRaw()) {
+                return reflective.isAssignableFrom(tc.reflective);
+            }
+            
+            // If all the type arguments contain those from the other class, after
+            // mapping the base type to this class type, then the other type is
+            // assignable to this - otherwise it's not. Also check outer classes.
+            GenTypeClass cclass = this;
+            GenTypeClass tclass;
+            try {
+                tclass = tc.mapToSuper(reflective.getName());
+            }
+            catch (BadInheritanceChainException bice) {
+                return false;
+            }
+            
+            if (tclass.isRaw())
+                return false;
+            while (cclass != null) {
+                if (cclass.params != null) {
+                    Iterator<? extends GenTypeParameter> i = cclass.params.iterator();
+                    Iterator<? extends GenTypeParameter> j = tclass.params.iterator();
+                    while (i.hasNext()) {
+                        GenTypeParameter cpar = i.next();
+                        GenTypeParameter tpar = j.next();
+                        if (! cpar.contains(tpar))
+                            return false;
+                    }
+                }
+                cclass = cclass.outer;
+                tclass = tclass.outer;
+            }
+            
+            return true;
+        }
+        
+        // Check each of the reference supertypes
+        GenTypeClass [] stypes = ((GenTypeSolid) t).getReferenceSupertypes();
+        for (int i = 0; i < stypes.length; i++) {
+            if (isAssignableFrom(stypes[i]))
+                return true;
+        }
+        
+        return false;
+    }
+    
+    public boolean isAssignableFrom(GenTypeClass c)
+    {
+        Reflective r = c.reflective;
+
+        // check the inheritance hierarchy
+        if( getInheritanceChain(r, reflective.getName()) != null) {
+
+            GenTypeClass other = c.mapToSuper(reflective.getName());
+            if (isRaw() || other.isRaw())
+                return true;
+            
+            if (outer != null) {
+                if (! outer.isAssignableFrom(other.outer))
+                    return false;
+            }
+            
+            if (params != null) {
+                Iterator<? extends GenTypeParameter> i = params.iterator();
+                Iterator<? extends GenTypeParameter> j = other.params.iterator();
+                while (i.hasNext()) {
+                    GenTypeParameter myParam = i.next();
+                    GenTypeParameter oParam = j.next();
+                    if (! myParam.contains(oParam))
+                        return false;
+                }
+            }
+            
+            return true;
+        }
+
+        return false;
+    }
+    
+    public boolean isAssignableFromRaw(JavaType t)
+    {
+        if (! (t instanceof GenTypeClass))
+            return false;
+        
+        GenTypeClass c = (GenTypeClass) t;
+        Reflective r = c.reflective;
+
+        // check the inheritance hierarchy
+        if( getInheritanceChain(r, reflective.getName()) != null)
+            return true;
+        else
+            return false;
+    }
+    
+    /**
+     * Map the type parameters in a base type to a super type, apply the
+     * resulting type parameters to the super type, and return the result.
+     * 
+     * For instance, if A&lt;T&gt; extends B&lt;U&gt;, Then to map an instance
+     * of  A&lt;Integer&gt; to B, pass "B" as the super type; The return is
+     * then B&lt;Integer&gt;.
+     * 
+     * @param subType   the supertype to map from
+     * @param basename    the fully-qualified name of the base type to map to
+     * 
+     * @throws BadInheritanceChainException
+     */
+    public GenTypeClass mapToSuper(String basename)
+    {
+        if( classloaderName().equals(basename))
+            return this;
+        
+        // the base type could actually be an interface, or a base class. 
+        Stack<Reflective> inheritanceStack = getInheritanceChain(reflective, basename);
+        if( inheritanceStack == null ) {
+            throw new BadInheritanceChainException();
+        }
+        
+        String bname;
+        Iterator<Reflective> i = inheritanceStack.iterator();
+        i.next();  // skip the topmost class, we've already got that.
+        Reflective baseType;
+        Reflective subType = reflective;
+        GenTypeClass ccc = this;
+        
+        do {
+            baseType = (Reflective)i.next();
+            bname = baseType.getName();
+            Map<String,GenTypeParameter> tparams = ccc.getMap();
+            ccc = mapGenericParamsToDirectBase(tparams, subType, baseType);
+            subType = baseType;
+        } while( ! bname.equals(basename) );
+        return ccc;
+    }
+
+    /**
+     * Worker function for mapGenericParamsToBase. Maps only to a direct base.
+     * @param tparams   a Map of String -> GenTypeClass
+     * @param subType   the derived type
+     * @param baseType  the base type
+     */
+    private static GenTypeClass mapGenericParamsToDirectBase(Map<String,? extends GenTypeParameter> tparams,
+            Reflective subType, Reflective baseType)
+    {
+        GenTypeClass baseClass = subType.superTypeByName(baseType.getName());
+        if (tparams == null) {
+            // sub-type inherits from the raw base class
+            return new GenTypeClass(baseClass.reflective);
+        }
+        baseClass = (GenTypeClass) baseClass.mapTparsToTypes(tparams);
+        return baseClass;
+    }
+    
+    /**
+     * Return the corresponding type if all type parameters are replaced with
+     * corresponding actual types, as defined by a Map (String -> GenType).
+     * 
+     * @param tparams  A map defining the translation from type parameter
+     *                 name (String) to its actual type (GenType). The map
+     *                 can be null to return the raw type.
+     * @return the corresponding type structure, with parameters mapped.
+     */
+    public GenTypeClass mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams)
+    {
+        // If there are no generic parameters, there's nothing to map...
+        if( params == null && outer == null )
+            return this;
+        
+        if (tparams == null) {
+            return new GenTypeClass(reflective);
+        }
+        
+        // Otherwise map each parameter, return the result.
+        List<GenTypeParameter> retlist = new ArrayList<GenTypeParameter>();
+        if (params != null) {
+            Iterator<? extends GenTypeParameter> i = params.iterator();
+            while( i.hasNext() ) {
+                retlist.add(i.next().mapTparsToTypes(tparams));
+            }
+        }
+        
+        GenTypeClass newOuter = null;
+        if (outer != null) {
+            newOuter = (GenTypeClass) outer.mapTparsToTypes(tparams);
+        }
+        
+        return new GenTypeClass(reflective, retlist, newOuter);
+    }
+    
+    public GenTypeClass mapToDerived(Reflective derivedType)
+    {        
+        // Get a map (parameter name -> type) for this class.
+        if(! isGeneric() )
+            return new GenTypeClass(derivedType);
+        
+        // One simple class is when super class = this.
+        // TODO don't use class names as equality test
+        if( derivedType.getName().equals(classloaderName()))
+            return this;
+        
+        // Construct a list (actually a stack) of classes from the
+        // super type down to this type.
+        Stack<Reflective> classes = getInheritanceChain(derivedType, classloaderName());
+        if( classes == null )
+            return null;
+        
+        // This loop continuously pops the next superclass from the stack,
+        // maps the parameter types across, and repeat until the stack is
+        // empty (and the target superclass has therefore been mapped).
+        // Reflective curBase = (Reflective)classes.pop();
+        GenTypeClass curBaseC = this;
+        classes.pop();
+        
+        while( ! classes.empty() ) {
+            Reflective curSubtype = (Reflective)classes.pop();
+            HashMap<String,GenTypeParameter> newMap = new HashMap<String,GenTypeParameter>();
+           
+            // Check that the super inherits from the generic version of base
+            GenTypeClass baseDecl = curSubtype.superTypeByName(curBaseC.classloaderName());
+            if (baseDecl.isRaw()) {
+                return new GenTypeClass(derivedType);
+            }
+            
+            // Get the mapping of tpar names to types
+            baseDecl.getParamsFromTemplate(newMap, curBaseC);
+            
+            // Apply the mapping to the subtype
+            curBaseC = new GenTypeClass(curSubtype, newMap);
+        }
+        
+        return curBaseC;
+    }
+
+    /**
+     * Get a map of type parameter names to the corresponding types, for this
+     * type. The returned map is a mutable copy, that is, it can freely be
+     * modified by the caller without affecting this GenTypeClass object. 
+     * 
+     * <p>Returns null if this represents a raw type, or an empty map if the
+     * type is not a generic type.
+     * 
+     * <p>Note that a map is not enough to completely describe a type, due to
+     * the possibility of inner/outer types having type parameters with the
+     * same name.
+     * 
+     * @return the map (of String -> GenTypeParameterizable).
+     */
+    public Map<String,GenTypeParameter> getMap()
+    {
+        if (isRaw()) {
+            return null;
+        }
+        
+        HashMap<String,GenTypeParameter> r = new HashMap<String,GenTypeParameter>();
+        mergeMap(r);
+        return r;
+    }
+    
+    /**
+     * Get a map of type parameter names to the corresponding types, for this
+     * type. Existing entries in the map will be overwritten. 
+     * 
+     * The returned does not indicate if this type is a raw type.
+     */
+    public void mergeMap(Map<String, GenTypeParameter> m)
+    {
+        if (outer != null)
+            outer.mergeMap(m);
+
+        List<GenTypeDeclTpar> formalParams = reflective.getTypeParams();
+        if( params == null )
+            return;
+        Iterator<? extends GenTypeParameter> paramIterator = params.iterator();
+        Iterator<GenTypeDeclTpar> formalIterator = formalParams.iterator();
+        
+        // go through each type parameter, assign it the type from our
+        // params list.
+        while( paramIterator.hasNext() ) {
+            GenTypeParameter paramType = paramIterator.next();
+            GenTypeDeclTpar formalType = (GenTypeDeclTpar)formalIterator.next();
+            
+            String paramName = formalType.getTparName();
+            m.put(paramName, paramType);
+        }
+    }
+    
+    /**
+     * Determine the inheritance, or implementation chain between two different
+     * types. For instance, if A extends B and B extends C, the chain between
+     * A and C is "A,B,C". Likewise, if D implements E which extends F, the
+     * chain between D and F is "D,E,F".
+     * 
+     * returns a Stack of Reflective.
+     */
+    private static Stack<Reflective> getInheritanceChain(Reflective top, String bottom)
+    {
+        Stack<Reflective> r = new Stack<Reflective>();
+        r.push(top);
+        if( top.getName().equals(bottom )) {
+            return r;
+        }
+        
+        // Go through each base/interface and try to discover the hieararchy
+        List<Reflective> l = top.getSuperTypesR();
+        for(Iterator<Reflective> i = l.iterator(); i.hasNext(); ) {
+            Reflective next = i.next();
+            Stack<Reflective> r2 = getInheritanceChain(next, bottom);
+            if( r2 != null ) {
+                r.addAll(r2);
+                return r;
+            }
+        }
+        return null;
+    }
+    
+    /*
+     * see bluej.debugger.gentype.GenTypeSolid#getParamsFromTemplate(java.util.Map, bluej.debugger.gentype.GenTypeParameterizable)
+     */
+    public void getParamsFromTemplate(Map<String,GenTypeParameter> r, GenTypeParameter template)
+    {
+        // We are classA<...>, template could be anything.
+        // possibilities for template:
+        //      classA<...>  - fine, just map the parameters seperately
+        //      ?            - can't map anything
+        //      ? extends classB<...> - first map classB to classA, then
+        //                        map the parameters
+        //           - same with super clause
+        //           - with multiple bounds, map seperately and then precisify
+        
+        if (template instanceof GenTypeClass) {
+            GenTypeClass classTemplate = (GenTypeClass) template;
+            if (classTemplate.classloaderName().equals(classloaderName())) {
+                if (params == null || classTemplate.params == null)
+                    return;
+                Iterator<? extends GenTypeParameter> i = params.iterator();
+                Iterator<? extends GenTypeParameter> j = classTemplate.params.iterator();
+
+                // Handle case that this is an inner class
+                if (outer != null)
+                    outer.getParamsFromTemplate(r, classTemplate.outer);
+                
+                // loop through each parameter
+                while (i.hasNext() && j.hasNext()) {
+                    GenTypeSolid ip = (GenTypeSolid) i.next();
+                    GenTypeParameter jp = j.next();
+
+                    ip.getParamsFromTemplate(r, jp);
+                }
+            }
+        }
+
+        return;
+    }
+    
+    public void erasedSuperTypes(Set<Reflective> s)
+    {
+        Stack<Reflective> refs = new Stack<Reflective>();
+        refs.push(reflective);
+        
+        while(! refs.empty()) {
+            Reflective r = (Reflective) refs.pop();
+            if (! s.contains(r)) {
+                // The reflective is not already in the set, so
+                // add it and queue its supertypes
+                s.add(r);
+                refs.addAll(r.getSuperTypesR());
+            }
+        }
+    }
+    
+    public GenTypeClass [] getReferenceSupertypes()
+    {
+        return new GenTypeClass[] {this};
+    }
+    
+    @Override
+    public GenTypeClass getArray()
+    {
+        return new GenTypeArrayClass(reflective.getArrayOf(), this);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeDeclTpar.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeDeclTpar.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6de0ce79d45bf4ca4408202fd9ea139c8f869b3
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeDeclTpar.java
@@ -0,0 +1,192 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This represents a type parameter in a declaration list. It is the same
+ * as a type parameter anywhere else, except that it can be bounded.
+ * 
+ * @author Davin McCall
+ */
+public class GenTypeDeclTpar extends GenTypeTpar
+{
+    protected GenTypeSolid [] upperBounds;
+    protected GenTypeSolid lBound = null;
+    
+    /**
+     * Construct a GenTypeDeclTpar without specifying bounds. The bounds should then be
+     * set using setBounds(). Until that occurs any intermediate method call has undefined
+     * results.
+     */
+    public GenTypeDeclTpar(String parname)
+    {
+        super(parname);
+    }
+    
+    public GenTypeDeclTpar(String parname, GenTypeSolid bound)
+    {
+        super(parname);
+        upperBounds = new GenTypeSolid [] { bound };
+    }
+    
+    /**
+     * Constructor for a type parameter with bounds. The array passed to this
+     * constructor should not be modified afterwards.
+     * 
+     * @param parname  The name of this type parameter
+     * @param bounds   The declared upper bounds for this type parameter
+     */
+    public GenTypeDeclTpar(String parname, GenTypeSolid [] bounds)
+    {
+        super(parname);
+        upperBounds = bounds;
+    }
+    
+    /**
+     * Constructor for a type parameter with a lower bound (as well as upper bounds).
+     * This can occur from capture conversion of a "? super XX" wildcard.
+     */
+    public GenTypeDeclTpar(String parname, GenTypeSolid [] ubounds, GenTypeSolid lbound)
+    {
+        super(parname);
+        upperBounds = ubounds;
+        lBound = lbound;
+    }
+    
+    /**
+     * Set the bounds. This should only be done when first creating the instance; otherwise,
+     * GenTypeDeclTpar instances should be immutable (as with other JavaTypes).
+     */
+    public void setBounds(GenTypeSolid [] ubounds)
+    {
+        upperBounds = ubounds;
+    }
+    
+    /**
+     * Get the upper bound (possibly an intersection type).
+     */
+    public GenTypeSolid getBound()
+    {
+        return IntersectionType.getIntersection(upperBounds);
+    }
+    
+    /**
+     * Get the bounds of this type parameter, as an array of GenTypeSolid.
+     */
+    public GenTypeSolid [] upperBounds()
+    {
+        GenTypeSolid [] r = new GenTypeSolid [upperBounds.length];
+        System.arraycopy(upperBounds, 0, r, 0, upperBounds.length);
+        return r;
+    }
+    
+    public GenTypeSolid [] lowerBounds()
+    {
+        if (lBound == null) {
+            return new GenTypeSolid[0];
+        }
+        else {
+            return new GenTypeSolid [] {lBound};
+        }
+    }
+        
+    /* (non-Javadoc)
+     * @see bluej.debugger.gentype.GenTypeTpar#mapTparsToTypes(java.util.Map)
+     */
+    public GenTypeSolid mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams)
+    {
+        if (tparams == null)
+            return new GenTypeWildcard(upperBounds(), lowerBounds()).getCapture().asSolid();
+        
+        GenTypeParameter newType = (GenTypeParameter)tparams.get(getTparName());
+        if( newType == null )
+            return new GenTypeWildcard(upperBounds(), lowerBounds()).getCapture().asSolid();
+        else
+            return newType.getCapture().asSolid();
+    }
+    
+    /**
+     * Returns a string describing this type parameter. This includes name and
+     * bound as written in Java.<br>
+     * 
+     * Example: T extends Integer
+     */
+    public String toString(boolean stripPrefix)
+    {
+        //need prefix to match java.lang.Object
+        String bound = getBound().toString(false);
+        if (bound.equals("java.lang.Object")) {
+            return getTparName();
+        }
+        else {
+            //now we strip the prefix if needed
+            return getTparName() + " extends " + getBound().toString(stripPrefix);
+        }
+    }
+    
+    public String arrayComponentName()
+    {
+        return getErasedType().arrayComponentName();
+    }
+    
+    public JavaType getErasedType()
+    {
+        return upperBounds[0].getErasedType();
+    }
+
+    public void erasedSuperTypes(Set<Reflective> s)
+    {
+        for (int i = 0; i < upperBounds.length; i++) {
+            upperBounds[i].erasedSuperTypes(s);
+        }
+    }
+    
+    public GenTypeClass [] getReferenceSupertypes()
+    {
+        ArrayList<GenTypeClass> al = new ArrayList<GenTypeClass>();
+        for (int i = 0; i < upperBounds.length; i++) {
+            GenTypeClass [] brs = upperBounds[i].getReferenceSupertypes();
+            for (int j = 0; j < brs.length; j++) {
+                al.add(brs[j]);
+            }
+        }
+        return (GenTypeClass []) al.toArray(new GenTypeClass[0]);
+    }
+
+    public boolean isAssignableFrom(JavaType t)
+    {
+        if (super.isAssignableFrom(t)) {
+            return true;
+        }
+        
+        if (lBound != null) {
+            return lBound.isAssignableFrom(t);
+        }
+        
+        return false;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeExtends.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeExtends.java
new file mode 100644
index 0000000000000000000000000000000000000000..924f16eb047e1deb0a409f2b7f87da6810308b4a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeExtends.java
@@ -0,0 +1,48 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+/**
+ * "? extends ..." type.
+ * 
+ * @author Davin McCall
+ */
+public class GenTypeExtends extends GenTypeWildcard
+{
+    /**
+     * Construct a "? extends ..." without specifying the upper bound at this time.
+     * The upper bound should then be set using "setUpperBound()".
+     */
+    public GenTypeExtends()
+    {
+        super((GenTypeSolid) null, (GenTypeSolid) null);
+    }
+    
+    /**
+     * Construct a "? extends ..." type with the specified upper bound (which
+     * may be an intersection type).
+     */
+    public GenTypeExtends(GenTypeSolid baseType)
+    {
+        super(baseType, null);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeParameter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeParameter.java
new file mode 100644
index 0000000000000000000000000000000000000000..61f992da623c738ecfcedb208432f5fb5f21460a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeParameter.java
@@ -0,0 +1,259 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.Map;
+
+import bluej.utility.JavaNames;
+
+/**
+ * Interface for a parameterizable type, that is, a type which could have type
+ * parameters. This includes classes, arrays, wild card types, and type
+ * parameters themselves.
+ * 
+ * @author Davin McCall
+ */
+public abstract class GenTypeParameter
+{
+
+    private static NameTransform stripPrefixNt = new NameTransform() {
+        public String transform(String x) {
+            return JavaNames.stripPrefix(x);
+        }
+    };
+    
+    private static NameTransform nullTransform = new NameTransform() {
+        public String transform(String x) {
+            return x;
+        }
+    };
+    
+    /**
+     * Return an equivalent type where all the type parameters have been mapped
+     * to the corresponding types using the given map.
+     * 
+     * @param tparams
+     *            A map of (String name -> GenType type).
+     * @return An equivalent type with parameters mapped.
+     */
+    abstract public GenTypeParameter mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams);
+
+    public boolean equals(Object other)
+    {
+        if (other instanceof GenTypeParameter) {
+            return equals((GenTypeParameter) other);
+        } else {
+            return false;
+        }
+    }
+    
+    abstract public boolean equals(GenTypeParameter other);
+
+    /**
+     * Find the most precise type that can be determined by taking into account
+     * commonalities between this type and the given type. For instance if the
+     * other class is a subtype of this type, return the subtype. Also, if
+     * the types have wildcard type parameters, combine them to form a more
+     * specific parameter.
+     * 
+     * @param other  The other type to precisify against
+     * @return  The most precise determinable type, or null if this comparison
+     *          is meaningless for the given type (incompatible types).
+     */
+    public GenTypeParameter precisify(GenTypeParameter other)
+    {
+        GenTypeSolid upperBound = getUpperBound().asSolid();
+        if (upperBound == null) {
+            return this;
+        }
+        GenTypeSolid lowerBound = getLowerBound();
+        
+        // Calculate new upper bounds
+        GenTypeSolid newUpper = null;
+        GenTypeSolid otherUpper = IntersectionType.getIntersection(other.getUpperBounds());
+        if (otherUpper == null) {
+            newUpper = upperBound;
+        }
+        else {
+            newUpper = IntersectionType.getIntersection(new GenTypeSolid [] {otherUpper, upperBound});
+        }
+        
+        // Calculate new lower bounds
+        GenTypeSolid newLower = null;
+        GenTypeSolid otherLower = other.getLowerBound();
+        if (otherLower == null) {
+            newLower = lowerBound;
+        }
+        else if (lowerBound == null) {
+            newLower = otherLower;
+        }
+        else {
+            newLower = GenTypeSolid.lub(new GenTypeSolid [] {otherLower, lowerBound});
+        }
+        
+        // If the upper bounds now equals the lower bounds, we have a solid
+        if (newUpper != null && newUpper.equals(newLower)) {
+            return newUpper;
+        }
+        else {
+            return new GenTypeWildcard(newUpper, newLower);
+        }
+    }
+
+    /**
+     * Get the upper bounds of this type. For a solid type the upper bounds are the
+     * type itself, except for an intersection type, where the bounds are the aggregated
+     * bounds of the components of the intersection.
+     */
+    abstract public GenTypeSolid [] getUpperBounds();
+    
+    /**
+     * Get the upper bounds (possibly as an intersection).
+     */
+    abstract public JavaType getUpperBound();
+
+    /**
+     * Get the lower bounds of this type. For a solid type the lower bounds are the
+     * type itself.
+     */
+    abstract public GenTypeSolid getLowerBound();
+    
+    /**
+     * Return true if this type "contains" the other type. That is, if this type as a
+     * type argument imposes less or equal constraints than the other type in the same
+     * place.
+     * 
+     * @param other  The other type to test against
+     * @return True if this type contains the other type
+     */
+    public final boolean contains(GenTypeParameter other)
+    {
+        GenTypeSolid myLower = getLowerBound();
+        JavaType myUpper = getUpperBound();
+        
+        GenTypeSolid otherLower = other.getLowerBound();
+        JavaType otherUpper = other.getUpperBound();
+        
+        if (myUpper != null) {
+            if (otherUpper == null) {
+                if (myUpper.asClass() == null) {
+                    return false;
+                }
+                else {
+                    if (! myUpper.asClass().classloaderName().equals("java.lang.Object")) {
+                        return false;
+                    }
+                }
+            }
+            else {
+                if (! myUpper.isAssignableFrom(otherUpper)) {
+                    return false;
+                }
+            }
+        }
+        
+        if (myLower != null) {
+            if (otherLower == null) {
+                return false;
+            }
+            if (! otherLower.isAssignableFrom(myLower)) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Get a string representation of the type, optionally stripping package prefixes
+     */
+    public String toString(boolean stripPrefix)
+    {
+        if (stripPrefix) {
+            return toString(stripPrefixNt);
+        }
+        else {
+            return toString(nullTransform);
+        }
+    }
+    
+    /**
+     * Returns a string which is a java-source valid type argument,
+     * compatible with this actual type. For an intersection type this
+     * returns a compatible wildcard.
+     * 
+     * @param stripPrefix   True if package prefixes should be stripped
+     */
+    public String toTypeArgString(boolean stripPrefix)
+    {
+        if (stripPrefix)
+            return toString(stripPrefixNt);
+        else
+            return toString(nullTransform);
+    }
+
+    /**
+     * Get a string representation of a type, using the specified name
+     * transform on all qualified class names.
+     * 
+     * @param nt  The name transform to use
+     * @return    A string representation of this type.
+     */
+    public String toString(NameTransform nt)
+    {
+        return toString();
+    }
+    
+    /**
+     * Returns a string which is a java-source valid type argument
+     * compatible with this actual type, modified using the given name
+     * transform.
+     * 
+     * For an intersection type this returns a compatible wildcard.
+     * 
+     * @param nt
+     * @return
+     */
+    abstract public String toTypeArgString(NameTransform nt);
+    
+    /**
+     * Get the erased type of this type.
+     */
+    abstract public JavaType getErasedType();
+    
+    abstract public JavaType getCapture();
+    
+    /**
+     * Check whether this represents a primitive type.
+     */
+    public boolean isPrimitive()
+    {
+        return false;
+    }
+
+    public abstract boolean isWildcard();
+    
+    public GenTypeParameter getArrayComponent()
+    {
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeSolid.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeSolid.java
new file mode 100644
index 0000000000000000000000000000000000000000..4deb6fcbd8cfb751546a11760ee2db7f6a204669
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeSolid.java
@@ -0,0 +1,410 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+
+/**
+ * A "solid" type is a non-primitive, non-wildcard type. This includes arrays,
+ * classes, and type parameters. Basically, a "solid" is anything that can be
+ * a component type for a wildcard clause.
+ * 
+ * @author Davin McCall
+ */
+public abstract class GenTypeSolid extends JavaType
+{
+    // force toString(NameTransform) to be reimplemented
+    public abstract String toString(NameTransform nt);
+    
+    // provide a default implementation for toString().
+    public String toString()
+    {
+        return toString(false);
+    }
+    
+    public boolean isPrimitive()
+    {
+        return false;
+    }
+    
+    public abstract boolean isInterface();
+    
+    /**
+     * Get the erased supertypes of this type, as defined in the JLS 3.0
+     * section 15.12.2.7.
+     * 
+     * @param s  The set into which to store the reflectives
+     */
+    public abstract void erasedSuperTypes(Set<Reflective> s);
+    
+    /**
+     * Find the minimal set of supertypes of this type which are reference types. For tpars
+     * this is the bounds. For a class/interface this is the type itself. 
+     */
+    public abstract GenTypeClass [] getReferenceSupertypes();
+    
+    /**
+     * Assuming that this is some solid type that is either a tpar or a
+     * class whose type arguments also match this definition (recursively),
+     * and the given template is a similar type (a constraint if this is
+     * a tpar, or the same class with type arguments acting as constraints).<p>
+     * 
+     * For example, if this type is LinkedList&lt;T&gt;, and the template
+     * is LinkedList&lt;Thread&gt;, then this method returns a map containing
+     * the mapping "T -&gt; Thread".<p> 
+     * 
+     * The given map may already contain some mappings. In this case, the
+     * existing mappings will be retained or made more specific.
+     * 
+     * @param map   A map to which mappings should be added
+     * @param template   The template to use
+     */
+    abstract public void getParamsFromTemplate(Map<String,GenTypeParameter> map, GenTypeParameter template);
+    
+    /*
+     *  Implement methods from GenTypeParameterizable
+     */
+    
+    public GenTypeSolid [] getUpperBounds()
+    {
+        return new GenTypeSolid [] {this};
+    }
+    
+    @Override
+    public GenTypeSolid getUpperBound()
+    {
+        return this;
+    }
+    
+    @Override
+    public GenTypeSolid getLowerBound()
+    {
+        return this;
+    }
+    
+    @Override
+    public JavaType getCapture()
+    {
+        return this;
+    }
+    
+    @Override
+    public GenTypeSolid asSolid()
+    {
+        return this;
+    }
+    
+    @Override
+    public boolean isWildcard()
+    {
+        return false;
+    }
+    
+    /*
+     * Static methods
+     */
+    
+    /**
+     * Calculate lub, as defined in revised JLS 15.12.2. Essentially this
+     * means, calculate the most specific type to which all the given types are
+     * convertible.<p>
+     */
+    public static GenTypeSolid lub(GenTypeSolid [] ubounds)
+    {
+        Stack<GenTypeClass[]> btstack = new Stack<GenTypeClass[]>();
+        return lub(ubounds, btstack);
+    }
+    
+    /*
+     * Private static methods
+     */
+    
+    /**
+     * lub workhorse method, uses a stack backtrace to avoid infinite recursion.
+     */
+    private static GenTypeSolid lub(GenTypeSolid [] ubounds, Stack<GenTypeClass[]> lubBt)
+    {
+        // "lowest(/least) upper bound"?
+        
+        List<GenTypeSolid> l = new ArrayList<GenTypeSolid>();
+        Reflective [] mec = minimalErasedCandidateSet(ubounds);
+        for (int i = 0; i < mec.length; i++) {
+            l.add(Candidate(mec[i], ubounds, lubBt));
+        }
+        
+        GenTypeSolid [] intersecting = l.toArray(new GenTypeSolid[l.size()]);
+        return IntersectionType.getIntersection(intersecting);
+    }
+    
+    /**
+     * This is the "Candidate" (and "CandidateInvocation") function as defined
+     * in the proposed JLS, section 15.12.2.7
+     * 
+     * @param t        The class type to find the candidate type for
+     * @param ubounds  The complete set of bounding types (see lub())
+     * @param lubBt    A backtrace used to avoid infinite recursion
+     * @return  The candidate type
+     */
+    private static GenTypeClass Candidate(Reflective t, GenTypeSolid [] ubounds, Stack<GenTypeClass[]> lubBt)
+    {
+        GenTypeClass [] ri = relevantInvocations(t, ubounds);
+        return leastContainingInvocation(ri, lubBt);
+    }
+    
+    /**
+     * Find the least containing invocation from a set of invocations. The
+     * invocations a, b, ... are types based on the same class G. The return is
+     * a generic type G<...> such that all  a, b, ... are convertible to the
+     * return type.<p>
+     * 
+     * This is "lci" as defined in the JLS 3rd edition section 15.12.2.7 
+     * 
+     * @param types   The invocations
+     * @param lubBt   A backtrace used to avoid infinite recursion
+     * @return   The least containing type
+     */
+    private static GenTypeClass leastContainingInvocation(GenTypeClass [] types, Stack<GenTypeClass[]> lubBt)
+    {
+        // first check for infinite recursion:
+        boolean breakRecursion = false;
+        Iterator<GenTypeClass[]> si = lubBt.iterator();
+        while (si.hasNext()) {
+            GenTypeSolid [] sbounds = si.next();
+            int i;
+            for (i = 0; i < sbounds.length; i++) {
+                if (! sbounds[i].equals(types[i])) {
+                    break;
+                }
+            }
+            breakRecursion = (i == sbounds.length);
+            // TODO this is really supposed to result in a recursively-
+            // defined type.
+        }
+        
+        lubBt.push(types);
+        GenTypeClass rtype = types[0];
+        for (int i = 1; i < types.length; i++) {
+            rtype = leastContainingInvocation(rtype, types[i], lubBt, breakRecursion);
+        }
+        lubBt.pop();
+        return rtype;
+    }
+    
+    /**
+     * Find the least containing invocation from two invocations.
+     */
+    private static GenTypeClass leastContainingInvocation(GenTypeClass a, GenTypeClass b, Stack<GenTypeClass[]> lubBt, boolean breakRecursion)
+    {
+        if (! a.getReflective().getName().equals(b.getReflective().getName()))
+            throw new IllegalArgumentException("Class types must be the same.");
+        
+        if (a.isRaw() || b.isRaw())
+            return (a.isRaw()) ? a : b;
+        
+        // Handle arrays - apply against component type
+        int arrCount = 0; // number of array dimensions
+        GenTypeClass origA = a;
+        while (a.getArrayComponent() != null) {
+            a = a.getArrayComponent().asClass();
+            b = b.getArrayComponent().asClass();
+            if (a == null) {
+                // if a is now null, the array is of primitive type
+                return origA;
+            }
+            arrCount++;
+        }
+        
+        List<GenTypeParameter> lc = new ArrayList<GenTypeParameter>();
+        Iterator<? extends GenTypeParameter> i = a.getTypeParamList().iterator();
+        Iterator<? extends GenTypeParameter> j = b.getTypeParamList().iterator();
+        
+        GenTypeClass oa = a.getOuterType();
+        GenTypeClass ob = b.getOuterType();
+        GenTypeClass oc = null;
+        if (oa != null && ob != null)
+            oc = leastContainingInvocation(oa, ob, lubBt, breakRecursion);
+
+        // lci(G<X1,...,Xn>, G<Y1,...,Yn>) =
+        //       G<lcta(X1,Y1), ..., lcta(Xn,Yn)>
+        while (i.hasNext()) {
+            GenTypeParameter atype = (GenTypeParameter) i.next();
+            GenTypeParameter btype = (GenTypeParameter) j.next();
+            GenTypeParameter rtype;
+            if (! breakRecursion)
+                rtype = leastContainingTypeArgument(atype, btype, lubBt);
+            else
+                rtype = new GenTypeUnbounded();
+            lc.add(rtype);
+        }
+        
+        // re-instate array dimensions
+        GenTypeClass rval = new GenTypeClass(a.getReflective(), lc, oc);
+        while (arrCount-- > 0) {
+            rval = rval.getArray();
+        }
+        return rval;
+    }
+    
+    /**
+     * Find the "least containing" type of two type parameters. This is "lcta"
+     * as defined in the JLS section 15.12.2.7 
+     * 
+     * @param a      The first type parameter
+     * @param b      The second type parameter
+     * @param lubBt  The backtrace for avoiding infinite recursion
+     * @return   The least containing type
+     */
+    private static GenTypeParameter leastContainingTypeArgument(GenTypeParameter a, GenTypeParameter b, Stack<GenTypeClass[]> lubBt)
+    {
+        GenTypeSolid ac = a.getCapture().asSolid();
+        GenTypeSolid bc = b.getCapture().asSolid();
+        
+        // Both arguments are of solid type
+        if (ac != null && bc != null) {
+            if (ac.equals(bc))
+                return ac;
+            else
+                return lub(new GenTypeSolid [] {ac, bc}, lubBt);
+        }
+        
+        if (ac != null || bc != null) {
+            // One is a solid type and the other is a wildcard type. Ensure
+            // that ac is the solid and b is the wildcard:
+            if (ac == null) {
+                ac = bc;
+                b = a;
+            }
+
+            GenTypeSolid lbound = b.getLowerBound();
+            if (lbound != null) {
+                return new GenTypeWildcard(null, IntersectionType.getIntersection(lbound, ac));
+            }
+        }
+        
+        GenTypeSolid lboundsa = a.getLowerBound();
+        GenTypeSolid lboundsb = b.getLowerBound();
+        if (lboundsa != null && lboundsb != null) {
+            return new GenTypeWildcard(null, IntersectionType.getIntersection(lboundsa, lboundsb));
+        }
+        
+        if (lboundsa != null || lboundsb != null) {
+            // lcta(? super U, ? extends V)
+            if (a.equals(b))
+                return a;
+            
+            // otherwise return good old '?'.
+            return new GenTypeUnbounded();
+        }
+        
+        // The only option left is lcta(? extends U, ? extends V)
+        GenTypeSolid [] uboundsa = a.getUpperBounds();
+        GenTypeSolid [] uboundsb = b.getUpperBounds();
+        GenTypeClass [] args = new GenTypeClass[uboundsa.length + uboundsb.length];
+        System.arraycopy(uboundsa, 0, args, 0, uboundsa.length);
+        System.arraycopy(uboundsb, 0, args, uboundsa.length, uboundsb.length);
+        return lub(args);
+    }
+    
+    /**
+     * Find the "minimal erased candidate set" of a set of types (MEC as
+     * defined in the JLS, section 15.12.2.7. This is the set of all (raw)
+     * supertypes common to each type in the given set, with no duplicates or
+     * redundant types (types whose presence is dictated by the presence of a
+     * subtype).
+     * 
+     * @param types   The types for which to find the MEC.
+     * @return        The MEC as an array of Reflective.
+     */
+    private static Reflective [] minimalErasedCandidateSet(GenTypeSolid [] types)
+    {
+        // have to find *intersection* of all sets and remove redundant types
+        
+        Set<Reflective> rset = new HashSet<Reflective>();
+        types[0].erasedSuperTypes(rset);
+        
+        for (int i = 1; i < types.length; i++) {
+            Set<Reflective> rset2 = new HashSet<Reflective>();
+            types[i].erasedSuperTypes(rset2);
+            
+            // find the intersection incrementally
+            Iterator<Reflective> j = rset2.iterator();
+            while (j.hasNext()) {
+                if( ! rset.contains(j.next()))
+                    j.remove();
+            }
+            rset = rset2;
+        }
+        
+        // Now remove redundant types
+        Iterator<Reflective> i = rset.iterator();
+        while (i.hasNext()) {
+            Iterator<Reflective> j = rset.iterator();
+            Reflective ri = (Reflective) i.next();
+            
+            while (j.hasNext()) {
+                Reflective ji = (Reflective) j.next();
+                if (ri == ji)
+                    continue;
+                
+                if (ri.isAssignableFrom(ji)) {
+                    i.remove();
+                    break;
+                }
+            }
+        }
+        
+        Reflective [] rval = new Reflective[rset.size()];
+        rset.toArray(rval);
+        
+        return rval;
+    }
+
+    /**
+     * Find the "relevant invocations" of some class. That is, given the class,
+     * find the generic types corresponding to that class which occur in the
+     * given parameter list.<P>
+     * 
+     * This is "Inv" described in the JLS section 15.12.2.7
+     *  
+     * @param r       The class whose invocations to find
+     * @param ubounds The parameter list to search
+     * @return        A list of generic types all based on the class r
+     */
+    private static GenTypeClass [] relevantInvocations(Reflective r, GenTypeSolid [] ubounds)
+    {
+        ArrayList<GenTypeClass> rlist = new ArrayList<GenTypeClass>();
+        for (int i = 0; i < ubounds.length; i++) {
+            GenTypeClass [] blist = ubounds[i].getReferenceSupertypes();
+            for (int j = 0; j < blist.length; j++) {
+                rlist.add(blist[j].mapToSuper(r.getName()));
+            }
+        }
+        return rlist.toArray(new GenTypeClass[rlist.size()]);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeSuper.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeSuper.java
new file mode 100644
index 0000000000000000000000000000000000000000..fcb95ecda1abc1da2bbe9783ddca9a0a58352d60
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeSuper.java
@@ -0,0 +1,67 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+
+/**
+ * "? super ..." type.
+ * 
+ * @author Davin McCall
+ */
+public class GenTypeSuper extends GenTypeWildcard
+{
+    /**
+     * Construct a "? super ..." type without specifying the lower bound
+     * at this time. Use "setLowerBound()" to set the lower bound before
+     * using the resulting type.
+     */
+    public GenTypeSuper()
+    {
+        super((GenTypeSolid) null, (GenTypeSolid) null);
+    }
+    
+    /**
+     * Construct a "? super ..." type with the specified lower bound.
+     */
+    public GenTypeSuper(GenTypeSolid baseType)
+    {
+        super(null, baseType);
+    }
+    
+    /*
+     * @see bluej.debugger.gentype.GenTypeParameter#toString(boolean)
+     */
+    @Override
+    public String toString(boolean stripPrefix)
+    {
+        return "? super " + lowerBound.toString(stripPrefix);
+    }
+    
+    /*
+     * @see bluej.debugger.gentype.GenTypeWildcard#toString(bluej.debugger.gentype.NameTransform)
+     */
+    @Override
+    public String toString(NameTransform nt)
+    {
+        return "? super " + lowerBound.toString(nt);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeTpar.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeTpar.java
new file mode 100644
index 0000000000000000000000000000000000000000..49478057b0bb98df4927d9db99d9987399704545
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeTpar.java
@@ -0,0 +1,163 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.Map;
+import java.util.Set;
+
+
+public class GenTypeTpar extends GenTypeSolid
+{
+    private String name;
+    
+    public GenTypeTpar(String parname)
+    {
+        name = parname;
+    }
+    
+    public String getTparName()
+    {
+        return name;
+    }
+    
+    public String toString(boolean stripPrefix)
+    {
+        return name;
+    }
+    
+    public String toString(NameTransform nt)
+    {
+        return name;
+    }
+        
+    public String toTypeArgString(NameTransform nt)
+    {
+        return name;
+    }
+    
+    public String arrayComponentName()
+    {
+        // We don't know the erased type.
+        throw new UnsupportedOperationException();
+    }
+    
+    public boolean isInterface()
+    {
+        return false;
+    }
+    
+    public boolean equals(JavaType other)
+    {
+        // For tpars to be equal, they must be the *same* tpar.
+        return other == this;
+    }
+    
+    public GenTypeParameter mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams)
+    {
+        if (tparams == null)
+            return this;
+        
+        GenTypeParameter newType = tparams.get(name);
+        if( newType == null ) {
+            return this;
+        }
+        else {
+            return newType;
+        }
+    }
+    
+    public void getParamsFromTemplate(Map<String,GenTypeParameter> map, GenTypeParameter template)
+    {
+        // If a mapping already exists, precisify it against the template.
+        // Otherwise, create a new mapping to the template.
+        
+        GenTypeParameter x = map.get(name);
+        if (x != null)
+            x = x.precisify(template);
+        else
+            x = template;
+        map.put(name, x);
+    }
+    
+    public GenTypeParameter precisify(GenTypeParameter other)
+    {
+        // shouldn't get called.
+        return other;
+    }
+    
+    public boolean isPrimitive()
+    {
+        return false;
+    }
+    
+    public boolean isAssignableFrom(JavaType t)
+    {
+        if (t.isNull())
+            return true;
+        
+        // If the other type has an upper bound which is this tpar, it's assignable
+        if (t instanceof GenTypeParameter) {
+            GenTypeParameter tp = (GenTypeParameter) t;
+            GenTypeSolid [] ubounds = tp.getUpperBounds();
+            for (int i = 0; i < ubounds.length; i++) {
+                if (ubounds[i] == this)
+                    return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    public boolean isAssignableFromRaw(JavaType t)
+    {
+        // We don't know the erased type.
+        throw new UnsupportedOperationException();
+    }
+    
+    public JavaType getErasedType()
+    {
+        // We don't know the erased type.
+        throw new UnsupportedOperationException();
+    }
+    
+    public void erasedSuperTypes(Set<Reflective> s)
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    public GenTypeClass [] getReferenceSupertypes()
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
+    public GenTypeArray getArray()
+    {
+        return new GenTypeArray(this);
+    }
+    
+    @Override
+    public JavaType getCapture()
+    {
+        return this;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeUnbounded.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeUnbounded.java
new file mode 100644
index 0000000000000000000000000000000000000000..4fb986b6d0293e6bee178267a8fa65e791bbb2c2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeUnbounded.java
@@ -0,0 +1,50 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+
+/**
+ * An unbounded wildcard.
+ * 
+ * @author Davin McCall
+ */
+public class GenTypeUnbounded extends GenTypeWildcard
+{
+    public GenTypeUnbounded()
+    {
+        super((GenTypeSolid) null, null);
+    }
+    
+    /**
+     * A constructor where we recognise the real upper bound as "Object".
+     */
+    public GenTypeUnbounded(GenTypeClass objectClass)
+    {
+        super(objectClass, null);
+    }
+    
+    @Override
+    public String toTypeArgString(NameTransform nt)
+    {
+        return "?";
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeWildcard.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeWildcard.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc4c7c5aecda4ed2926decfeb17db44d813fb2ea
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/GenTypeWildcard.java
@@ -0,0 +1,212 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+/**
+ * A wildcard type with an upper and/or lower bound.
+ * 
+ * <p>Note that both an upper and lower bound is allowed. This type doesn't occur
+ * naturally- it can't be specified in the Java language. But in some cases we
+ * can deduce the type of some object to be this.
+ *
+ * @author Davin McCall
+ */
+public class GenTypeWildcard extends GenTypeParameter
+{
+    GenTypeSolid upperBound; // ? extends upperBound
+    GenTypeSolid lowerBound; // ? super lowerBound
+    
+    /**
+     * Constructor for a wildcard with a specific upper and lower bound, either of
+     * which may be null.
+     */
+    public GenTypeWildcard(GenTypeSolid upper, GenTypeSolid lower)
+    {
+        upperBound = upper;
+        lowerBound = lower;
+    }
+    
+    /**
+     * Constructor with a given range of upper and lower bounds.
+     * 
+     * @param uppers  The upper bounds
+     * @param lowers  The lower bounds
+     */
+    public GenTypeWildcard(GenTypeSolid [] uppers, GenTypeSolid [] lowers)
+    {
+        if (uppers.length != 0) {
+            upperBound = IntersectionType.getIntersection(uppers);
+        }
+        if (lowers.length != 0) {
+            lowerBound = GenTypeSolid.lub(lowers);
+        }
+    }
+    
+    @Override
+    public String toString()
+    {
+        return toString(false);
+    }
+        
+    @Override
+    public String toString(NameTransform nt)
+    {
+        if (lowerBound != null) {
+            return "? super " + lowerBound.toString(nt);
+        }
+        else if (upperBound != null) {
+            String uboundStr = upperBound.toString();
+            if (! uboundStr.equals("java.lang.Object"))
+                return "? extends " + upperBound.toString(nt);
+        }
+        return "?";
+    }
+    
+    @Override
+    public String toTypeArgString(NameTransform nt)
+    {
+        return toString(nt);
+    }
+    
+    @Override
+    public GenTypeWildcard mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams)
+    {
+        GenTypeSolid newUpper = null;
+        GenTypeSolid newLower = null;
+        
+        // Find new upper bounds
+        if (upperBound != null) {
+            ArrayList<GenTypeSolid> newUppers = new ArrayList<GenTypeSolid>();
+            GenTypeSolid [] upperBounds = upperBound.getUpperBounds();
+            
+            // find the new upper bounds
+            for (int i = 0; i < upperBounds.length; i++) {
+                GenTypeParameter newBound = upperBounds[i].mapTparsToTypes(tparams);
+                if (newBound instanceof GenTypeWildcard) {
+                    GenTypeWildcard newWcBound = (GenTypeWildcard) newBound;
+                    newUppers.add(newWcBound.upperBound);
+                }
+                else {
+                    newUppers.add((GenTypeSolid) newBound);
+                }
+            }
+            GenTypeSolid [] newUppersA = (GenTypeSolid []) newUppers.toArray(new GenTypeSolid[newUppers.size()]);
+            newUpper = IntersectionType.getIntersection(newUppersA);
+        }
+        
+        // find the new lower bounds
+        // This is easier. If the lower bound is an intersection type, it comes from
+        // lub() and therefore contains no immediate type parameters.
+        if (lowerBound != null) {
+            GenTypeParameter newLowerP = lowerBound.mapTparsToTypes(tparams);
+            newLower = newLowerP.getLowerBound();
+        }
+        
+        return new GenTypeWildcard(newUpper, newLower);
+    }
+    
+    @Override
+    public boolean equals(GenTypeParameter other)
+    {
+        if (this == other)
+            return true;
+        
+        if (! other.isWildcard()) {
+            return false;
+        }
+        
+        GenTypeSolid otherLower = other.getLowerBound();
+        JavaType otherUpper = other.getUpperBound();
+        
+        if (upperBound != null && ! upperBound.equals(otherUpper)) {
+            return false;
+        }
+        if (upperBound == null && otherUpper != null) {
+            return false;
+        }
+        if (lowerBound != null && ! lowerBound.equals(otherLower)) {
+            return false;
+        }
+        if (lowerBound == null && otherLower != null) {
+            return false;
+        }
+        
+        return true;
+    }
+    
+    @Override
+    public JavaType getErasedType()
+    {
+        return upperBound.getErasedType();
+    }
+    
+    @Override
+    public boolean isWildcard()
+    {
+        return true;
+    }
+    
+    /**
+     * Get the upper bounds of this wildcard type, as an array. The upper
+     * bounds are those occurring in "extends" clauses.
+     * 
+     * @return A copy of the upper bounds.
+     */
+    @Override
+    public GenTypeSolid[] getUpperBounds()
+    {
+        if (upperBound != null) {
+            return upperBound.getUpperBounds();
+        }
+        else {
+            return new GenTypeSolid[0];
+        }
+    }
+    
+    @Override
+    public GenTypeSolid getUpperBound()
+    {
+        return upperBound;
+    }
+    
+    /**
+     * Get the lower bounds of this wildcard type, as an array. The lower
+     * bounds are those occurring in "super" clauses.
+     * 
+     * @return A copy of the lower bounds.
+     */
+    @Override
+    public GenTypeSolid getLowerBound()
+    {
+        return lowerBound;
+    }
+        
+    @Override
+    public JavaType getCapture()
+    {
+        return new GenTypeCapture(this);
+    }
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/IntersectionType.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/IntersectionType.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd6ae1f1e0965660ce3eb2e074bb42e3e3458b2b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/IntersectionType.java
@@ -0,0 +1,277 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+
+import java.util.*;
+
+/**
+ * Represents an intersection type, eg. I1&I2&I3 as specified in the Java Language
+ * Specification. 
+ * 
+ * @author Davin McCall
+ */
+public class IntersectionType extends GenTypeSolid
+{
+    private GenTypeSolid [] intersectTypes;
+    
+    private IntersectionType(GenTypeSolid [] types)
+    {
+        if (types.length == 0) {
+            throw new IllegalArgumentException();
+        }
+        
+        intersectTypes = types;
+    }
+    
+    /**
+     * Factory method. Avoids creation of an intersection to hold only one type.
+     * 
+     * @param types   The types to create an intersection of
+     * @return        The intersection of the given types
+     */
+    public static GenTypeSolid getIntersection(GenTypeSolid [] types)
+    {
+        // A quick optimization for a common case.
+        if (types.length == 1)
+            return types[0];
+        
+        // First remove cruft. If there are two classes (as opposed to interfaces),
+        // combine them.
+        
+        ArrayList<GenTypeSolid> nonclasstypes = new ArrayList<GenTypeSolid>();
+        GenTypeClass classtype = null;
+        
+        for (int i = 0; i < types.length; i++) {
+            GenTypeClass tclass = types[i].asClass();
+            if (tclass != null && ! tclass.isInterface()) {
+                if (classtype == null)
+                    classtype = tclass;
+                else {
+                    classtype = combineClasses(tclass, classtype);
+                }
+            }
+            else {
+                nonclasstypes.add(types[i]);
+            }
+        }
+        
+        // If there is a class, insert it at the head of the list.
+        if (classtype != null)
+            nonclasstypes.listIterator().add(classtype);
+        
+        // If there's only type left, return it.
+        if (nonclasstypes.size() == 1)
+            return nonclasstypes.get(0);
+        
+        return new IntersectionType(nonclasstypes.toArray(new GenTypeSolid[nonclasstypes.size()]));
+    }
+    
+    /**
+     * Convenience method to get the intersection of two types.
+     * @param a  The first type
+     * @param b  The second type
+     * @return  The intersection of the two types
+     */
+    public static GenTypeSolid getIntersection(GenTypeSolid a, GenTypeSolid b)
+    {
+        return getIntersection(new GenTypeSolid [] {a, b});
+    }
+    
+    /**
+     * Combine two classes, to yield one class which is the intersection of both.
+     * @param a  The first class
+     * @param b  The second class
+     * @return The intersection (as a single class)
+     */
+    public static GenTypeClass combineClasses(GenTypeClass a, GenTypeClass b)
+    {
+        // One class must be derived from the other
+        //GenTypeParameterizable gtp = classtype.precisify(tclass);
+        GenTypeClass aE = (GenTypeClass) a.getErasedType();
+        GenTypeClass bE = (GenTypeClass) b.getErasedType();
+        if (! aE.equals(bE)) {
+            if (aE.isAssignableFrom(bE)) {
+                a = (GenTypeClass) a.mapToDerived(bE.reflective);
+            }
+            else {
+                b = (GenTypeClass) b.mapToDerived(aE.reflective);
+            }
+        }
+        
+        if (a.isRaw())
+            return b;
+        
+        if (b.isRaw())
+            return a;
+        
+        // Handle outer class recursively
+        GenTypeClass outer = null;
+        if (a.outer != null) {
+            outer = combineClasses(a.outer, b.outer);
+        }
+        
+        // Precisify type arguments
+        List<GenTypeParameter> newParams = null;
+        if (a.params != null) {
+            newParams = new ArrayList<GenTypeParameter>();
+            Iterator<? extends GenTypeParameter> ia = a.params.iterator();
+            Iterator<? extends GenTypeParameter> ib = b.params.iterator();
+            while (ia.hasNext()) {
+                GenTypeParameter tpa = ia.next();
+                GenTypeParameter tpb = ib.next();
+                newParams.add(tpa.precisify(tpb));
+            }
+        }
+        
+        return new GenTypeClass(a.reflective, newParams, outer);
+    }
+    
+    public String toString(NameTransform nt)
+    {
+        // This must return a valid java type. We can throw away all but one of
+        // the intersection types, and it will be ok. So let's not use
+        // java.lang.Object if we have any other choice.
+        
+        String xx = intersectTypes[0].toString();
+        if (intersectTypes.length > 1 && xx.equals("java.lang.Object")) {
+            return intersectTypes[1].toString(nt);
+        }
+        else {
+            return intersectTypes[0].toString(nt);
+        }
+    }
+    
+    public String toTypeArgString(NameTransform nt)
+    {
+        // As a type argument, we can only go to a wildcard
+        
+        return "? extends " + toString(nt);
+    }
+
+    public boolean isInterface()
+    {
+        return false;
+    }
+
+    public GenTypeSolid[] getUpperBounds()
+    {
+        ArrayList<GenTypeSolid> ubounds = new ArrayList<GenTypeSolid>();
+        for (int i = 0; i < intersectTypes.length; i++) {
+            GenTypeSolid [] itUbounds = intersectTypes[i].getUpperBounds();
+            Collections.addAll(ubounds, itUbounds);
+        }
+        return ubounds.toArray(new GenTypeSolid[ubounds.size()]);
+    }
+
+    public GenTypeSolid[] getLowerBounds()
+    {
+        return new GenTypeSolid[] {this};
+    }
+        
+    public GenTypeSolid mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams)
+    {
+        GenTypeSolid [] newIsect = new GenTypeSolid[intersectTypes.length];
+        for (int i = 0; i < intersectTypes.length; i++) {
+            newIsect[i] = (GenTypeSolid) intersectTypes[i].mapTparsToTypes(tparams);
+        }
+        return new IntersectionType(newIsect);
+    }
+
+    public boolean equals(JavaType other)
+    {
+        if (other == null)
+            return false;
+        
+        if (other instanceof JavaType) {
+            JavaType otherJT = (JavaType) other;
+            return isAssignableFrom(otherJT) && otherJT.isAssignableFrom(this);
+        }
+        
+        return false;
+    }
+
+    public void getParamsFromTemplate(Map<String,GenTypeParameter> map, GenTypeParameter template)
+    {
+        // This won't be needed
+        return;
+    }
+
+    public GenTypeParameter precisify(GenTypeParameter other)
+    {
+        // This won't be needed, I think
+        throw new UnsupportedOperationException();
+    }
+
+    public String arrayComponentName()
+    {
+        return getErasedType().arrayComponentName();
+    }
+
+    public JavaType getErasedType()
+    {
+        return intersectTypes[0].getErasedType();
+    }
+
+    public boolean isAssignableFrom(JavaType t)
+    {
+        for (int i = 0; i < intersectTypes.length; i++) {
+            if (intersectTypes[i].isAssignableFrom(t))
+                return true;
+        }
+        return false;
+    }
+
+    public boolean isAssignableFromRaw(JavaType t)
+    {
+        for (int i = 0; i < intersectTypes.length; i++) {
+            if (intersectTypes[i].isAssignableFromRaw(t))
+                return true;
+        }
+        return false;
+    }
+    
+    public void erasedSuperTypes(Set<Reflective> s)
+    {
+        for (int i = 0; i < intersectTypes.length; i++) {
+            intersectTypes[i].erasedSuperTypes(s);
+        }
+    }
+    
+    public GenTypeClass [] getReferenceSupertypes()
+    {
+        ArrayList<GenTypeClass> rsupTypes = new ArrayList<GenTypeClass>();
+        for (int i = 0; i < intersectTypes.length; i++) {
+            GenTypeClass [] isTypes = intersectTypes[i].getReferenceSupertypes();
+            for (int j = 0; j < isTypes.length; j++) {
+                rsupTypes.add(isTypes[j]);
+            }
+        }
+        return rsupTypes.toArray(new GenTypeClass[rsupTypes.size()]);
+    }
+    
+    @Override
+    public GenTypeArray getArray()
+    {
+        return new GenTypeArray(this);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/JavaPrimitiveType.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/JavaPrimitiveType.java
new file mode 100644
index 0000000000000000000000000000000000000000..70ee168ef746f9cb078014f659657734b456bd21
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/JavaPrimitiveType.java
@@ -0,0 +1,256 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.Map;
+
+/**
+ * Base class for primitive/built-in types.
+ * 
+ * @author Davin McCall
+ */
+public class JavaPrimitiveType
+    extends JavaType
+{
+    private static JavaPrimitiveType [] primitiveTypes = new JavaPrimitiveType[JavaType.JT_MAX+1];
+    private static String [] typeNames = { "void", "null", "boolean", "char",
+            "byte", "short", "int", "long", "float", "double" };
+    
+    // each element represents a primitive type, and contains an array of
+    // other types that this type can be assigned from
+    private static int assignableFrom [][] = new int [JT_MAX+1][];
+    {
+        assignableFrom[JT_VOID]    = new int[] {};
+        assignableFrom[JT_NULL]    = new int[] {};
+        assignableFrom[JT_BOOLEAN] = new int[] { JT_BOOLEAN };
+        assignableFrom[JT_CHAR]    = new int[] { JT_CHAR };
+        assignableFrom[JT_BYTE]    = new int[] { JT_BYTE };
+        assignableFrom[JT_SHORT]   = new int[] { JT_SHORT, JT_BYTE };
+        assignableFrom[JT_INT]     = new int[] { JT_INT, JT_BYTE, JT_SHORT, JT_CHAR };
+        assignableFrom[JT_LONG]    = new int[] { JT_LONG, JT_BYTE, JT_SHORT, JT_CHAR, JT_INT };
+        assignableFrom[JT_FLOAT]   = new int[] { JT_FLOAT, JT_LONG, JT_BYTE, JT_SHORT, JT_CHAR, JT_INT, JT_LONG };
+        assignableFrom[JT_DOUBLE]  = new int[] { JT_DOUBLE, JT_LONG, JT_BYTE, JT_SHORT, JT_CHAR, JT_INT, JT_LONG, JT_FLOAT };
+    }
+    
+    // instance fields
+    
+    private int myIndex;
+    
+    /*
+     * Private constructor. Use "getXXX" methods to get a primitive instance. 
+     */
+    protected JavaPrimitiveType(int index)
+    {
+        myIndex = index;
+    }
+    
+    private static JavaPrimitiveType getType(int v)
+    {
+        if (primitiveTypes[v] == null) {
+            primitiveTypes[v] = new JavaPrimitiveType(v);
+        }
+        
+        return primitiveTypes[v];
+    }
+    
+    /**
+     * Obtain an instance of "void".
+     */
+    public static JavaPrimitiveType getVoid()
+    {
+        return getType(JT_VOID);
+    }
+    
+    public static JavaPrimitiveType getNull()
+    {
+        return getType(JT_NULL);
+    }
+    
+    public static JavaPrimitiveType getBoolean()
+    {
+        return getType(JT_BOOLEAN);
+    }
+    
+    public static JavaPrimitiveType getByte()
+    {
+        return getType(JT_BYTE);
+    }
+    
+    public static JavaPrimitiveType getChar()
+    {
+        return getType(JT_CHAR);
+    }
+    
+    public static JavaPrimitiveType getShort()
+    {
+        return getType(JT_SHORT);
+    }
+    
+    public static JavaPrimitiveType getInt()
+    {
+        return getType(JT_INT);
+    }
+    
+    public static JavaPrimitiveType getLong()
+    {
+        return getType(JT_LONG);
+    }
+    
+    public static JavaPrimitiveType getFloat()
+    {
+        return getType(JT_FLOAT);
+    }
+    
+    public static JavaPrimitiveType getDouble()
+    {
+        return getType(JT_DOUBLE);
+    }
+    
+    @Override
+    public String toString()
+    {
+        return typeNames[myIndex];
+    }
+    
+    @Override
+    public String arrayComponentName()
+    {
+        // Simple lookup by index. It's not possible to have an array of
+        // void or null types.
+        return "!!ZCBSIJFD".substring(myIndex, myIndex + 1);
+    }
+    
+    @Override
+    public boolean isAssignableFrom(JavaType o)
+    {
+        int [] assignables = assignableFrom[myIndex];
+        for (int i = 0; i < assignables.length; i++) {
+            if (o.typeIs(assignables[i]))
+                return true;
+        }
+        return false;
+    }
+    
+    @Override
+    public JavaType getErasedType()
+    {
+        return this;
+    }
+
+    /*
+     * For primitive types, "isAssignableFromRaw" is equivalent to
+     * "isAssignableFrom".
+     */
+    @Override
+    public boolean isAssignableFromRaw(JavaType t)
+    {
+        return isAssignableFrom(t);
+    }
+
+    @Override
+    public boolean isPrimitive()
+    {
+        return true;
+    }
+    
+    @Override
+    public boolean isNumeric()
+    {
+        return myIndex >= JT_LOWEST_NUMERIC;
+    }
+    
+    @Override
+    public boolean isIntegralType()
+    {
+        return myIndex >= JT_CHAR && myIndex <= JT_LONG;
+    }
+    
+    @Override
+    public boolean typeIs(int v)
+    {
+        return myIndex == v;
+    }
+    
+    @Override
+    public JavaType mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams)
+    {
+        return this;
+    }
+    
+    @Override
+    public GenTypeArray getArray()
+    {
+        return new GenTypeArray(this);
+    }
+    
+    @Override
+    public JavaType getCapture()
+    {
+        return this;
+    }
+    
+    @Override
+    public void getParamsFromTemplate(Map<String, GenTypeParameter> map,
+            GenTypeParameter template)
+    {
+        
+    }
+    
+    @Override
+    public GenTypeSolid getLowerBound()
+    {
+        return null;
+    }
+    
+    @Override
+    public JavaPrimitiveType getUpperBound()
+    {
+        return this;
+    }
+    
+    @Override
+    public GenTypeSolid[] getUpperBounds()
+    {
+        return null;
+    }
+    
+    @Override
+    public String toTypeArgString(NameTransform nt)
+    {
+        return toString();
+    }
+    
+    @Override
+    public boolean equals(JavaType other)
+    {
+        if (other == null) {
+            return false;
+        }
+        return other.typeIs(myIndex);
+    }
+    
+    @Override
+    public boolean isWildcard()
+    {
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/JavaType.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/JavaType.java
new file mode 100644
index 0000000000000000000000000000000000000000..6cd53b273cef1bd08875c9b8a50c2a2625ffcdfb
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/JavaType.java
@@ -0,0 +1,221 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.Map;
+
+/**
+ * JavaType, a tree structure describing a type (including generic types).
+ * 
+ * Most functionality is in subclasses. Default implementations for many
+ * methods are provided.
+ * 
+ * @author Davin McCall
+ */
+
+public abstract class JavaType extends GenTypeParameter
+{
+    public static int JT_VOID = 0;
+    public static int JT_NULL = 1;
+    public static int JT_BOOLEAN = 2;
+    public static int JT_CHAR = 3;
+    public static int JT_BYTE = 4;
+    public static int JT_SHORT = 5;
+    public static int JT_INT = 6;
+    public static int JT_LONG = 7;
+    public static int JT_FLOAT = 8;
+    public static int JT_DOUBLE = 9;
+    
+    public static int JT_MAX = 9;
+    
+    public static int JT_LOWEST_NUMERIC = JT_CHAR; // all above are numeric
+    public static int JT_LOWEST_FLOAT = JT_FLOAT; // all above are float point
+    
+    /**
+     * Get a string representation of a type, using the specified name
+     * transform on all qualified class names.
+     * 
+     * @param nt  The name transform to use
+     * @return    A string representation of this type.
+     */
+    public String toString(NameTransform nt)
+    {
+        return toString();
+    }
+    
+    /**
+     * Get a string representation of a type.<p>
+     * 
+     * Where possible this returns a valid java type, even for cases where
+     * type inference has yielded an invalid java type. See GenTypeWildcard.
+     * 
+     * @return  A string representation of this type.
+     */
+    abstract public String toString();
+
+    /**
+     * Get the name of this type as it must appear in the class name of an
+     * array with this type as the component type. The array class name is
+     * as defined in documentation for Class.getName().<p>
+     * 
+     * For instance, primitive types are represented as a single upper case
+     * character (boolean = Z, byte = B etc). Reference types are encoded
+     * as "Lpkg1.pkg2.classname;" ie the fully qualified name preceded by
+     * "L" and with ";" appended.
+     */
+    abstract public String arrayComponentName();
+
+    /**
+     * Assuming that this is some type which encloses some type parameters by
+     * name, and the given template is a similar type but with actual type
+     * arguments, obtain a map which maps the name of the argument (in this
+     * type) to the actual type (from the template type).<p>
+     * 
+     * The given map may already contain some mappings. In this case, the
+     * existing mappings will be retained or made more specific.
+     * 
+     * @param map   A map to which mappings should be added
+     * @param template   The template to use
+     */
+    abstract public void getParamsFromTemplate(Map<String,GenTypeParameter> map, GenTypeParameter template);
+
+    /**
+     * Determine whether the type represents a primitive type such as "int".
+     * This includes the null type, void, and numeric constants.
+     */
+    abstract public boolean isPrimitive();
+    
+    /**
+     * Determine whether the type is a numeric type (char, byte, short, int,
+     * long, float, double)
+     */
+    public boolean isNumeric()
+    {
+        return false;
+    }
+    
+    /**
+     * Determine whether the type is a primitive integral type: char, byte,
+     * short, int or long (specifically excluding float and double)
+     */
+    public boolean isIntegralType()
+    {
+        return false;
+    }
+    
+    /**
+     * Determine whether the type represents the void type.
+     */
+    final public boolean isVoid()
+    {
+        return typeIs(JT_VOID);
+    }
+    
+    /**
+     * Determine whether the type represents the null type. 
+     */
+    final public boolean isNull()
+    {
+        return typeIs(JT_NULL);
+    }
+    
+    /**
+     * Test whether the type is one of the types represented by the constants
+     * GT_VOID, GT_NULL, GT_INT, GT_LONG etc.
+     */
+    public boolean typeIs(int v)
+    {
+        return false;
+    }
+    
+    /**
+     * If this type represents a class type, get it. Otherwise returns null.
+     * Arrays with a non-class component type (including arrays of primitives) may return null.
+     */
+    public GenTypeClass asClass()
+    {
+        return null;
+    }
+    
+    /**
+     * If this type represents a "solid" (reference) type, get it. Otherwise return null.
+     */
+    public GenTypeSolid asSolid()
+    {
+        return null;
+    }
+
+    abstract public boolean equals(JavaType other);
+    
+    public boolean equals(GenTypeParameter other)
+    {
+        if (other instanceof JavaType) {
+            return equals((JavaType) other);
+        }
+        return false;
+    }
+
+    /**
+     * Determine whether a variable of this type could legally be assigned
+     * (without casting, boxing, unchecked conversion etc) a value of the given type.
+     * 
+     * @param t  The type to check against
+     * @return   true if the type is assignable to this type
+     */
+    abstract public boolean isAssignableFrom(JavaType t);
+    
+    /**
+     * Determine whether a variable of this type could legally be assigned
+     * (without casting etc) a value of the given type, if treating both this
+     * and the other as raw types.
+     * 
+     * @param t  The type to check against
+     * @return   true if the type is assignable to this type
+     */
+    abstract public boolean isAssignableFromRaw(JavaType t);
+    
+    /**
+     * Get an equivalent type where the type parameters have been mapped to
+     * an actual type. Type parameters not present in the map are instead
+     * mapped to their bound (as a wildcard, ? extends X).
+     * 
+     * @param tparams A map (String->JavaType) mapping the name of the type
+     *                parameter to the corresponding type. May be null, to map
+     *                to the raw type.
+     * @return A type with parameters mapped
+     */
+    abstract public GenTypeParameter mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams);
+    
+    /**
+     * If this is an array type, get the component type. If this is not an
+     * array type, return null.
+     */
+    public JavaType getArrayComponent()
+    {
+        return null;
+    }
+    
+    /**
+     * Get an array type whose component type is this type.
+     */
+    abstract public GenTypeSolid getArray();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/MethodReflective.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/MethodReflective.java
new file mode 100644
index 0000000000000000000000000000000000000000..c33645f79260571cf91a540512a925bd711b1dad
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/MethodReflective.java
@@ -0,0 +1,167 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents a method from a reflective.
+ * 
+ * @author Davin McCall
+ */
+public class MethodReflective
+{
+    private String name;
+    private JavaType returnType;
+    private List<GenTypeDeclTpar> tparTypes;
+    private List<JavaType> paramTypes;
+    private boolean isVarArgs;
+    private Reflective declaringType;
+    private String javaDoc;
+    private List<String> paramNames;
+    private int modifiers;
+    
+    /**
+     * Construct a MethodReflective object.
+     * @param name        The name of the method
+     * @param returnType  The return type of the method
+     * @param tparTypes   The type parameter definitions (for a generic method); may be null
+     * @param paramTypes  The types of the method parameters
+     * @param isVarArgs   Whether the method is a "varargs" method. If true, the last paramType is
+     *                    the component type, not the array type.
+     * @param isStatic    Whether the method is a static method
+     */
+    public MethodReflective(String name, JavaType returnType, List<GenTypeDeclTpar> tparTypes,
+            List<JavaType> paramTypes, Reflective declaringType, boolean isVarArgs, int modifiers)
+    {
+        this.name = name;
+        this.returnType = returnType;
+        this.tparTypes = tparTypes;
+        this.paramTypes = paramTypes;
+        this.declaringType = declaringType;
+        this.isVarArgs = isVarArgs;
+        this.modifiers = modifiers;
+    }
+    
+    /**
+     * Set the javadoc for this method.
+     */
+    public void setJavaDoc(String javaDoc)
+    {
+        this.javaDoc = javaDoc;
+    }
+    
+    /**
+     * Get the javadoc for this method. Returns null if not available
+     * (if it has not been set).
+     */
+    public String getJavaDoc()
+    {
+        return javaDoc;
+    }
+    
+    /**
+     * Set the parameter names for this method.
+     * @param paramNames  A list of parameter names. The MethodReflective takes ownership
+     *                    of the given list (it should not be later modified).
+     */
+    public void setParamNames(List<String> paramNames)
+    {
+        this.paramNames = paramNames;
+    }
+    
+    /**
+     * Get the parameter names for this method, if known.
+     * @return A list of the parameter names in order, or null if the parameter names are
+     *         not known.
+     */
+    public List<String> getParamNames()
+    {
+        return paramNames;
+    }
+    
+    /**
+     * Get the method name.
+     */
+    public String getName()
+    {
+        return name;
+    }
+    
+    /**
+     * Check whether the method is a static method.
+     */
+    public boolean isStatic()
+    {
+        return Modifier.isStatic(modifiers);
+    }
+    
+    /**
+     * Get the method modifiers as a bitmask.
+     * 
+     * @see java.lang.reflect.Modifier
+     */
+    public int getModifiers()
+    {
+        return modifiers;
+    }
+    
+    public boolean isVarArgs()
+    {
+        return isVarArgs;
+    }
+    
+    public boolean isAbstract()
+    {
+        return false; // not yet implemented
+    }
+    
+    /**
+     * Get the method parameter types. For a varargs method, the last parameter type returned is
+     * the element type, not the array type.
+     */
+    public List<JavaType> getParamTypes()
+    {
+        return paramTypes;
+    }
+    
+    /**
+     * Get the method type parameters. If the method has no type parameters,
+     * returns an empty list.
+     */
+    public List<GenTypeDeclTpar> getTparTypes()
+    {
+        return tparTypes == null ? Collections.<GenTypeDeclTpar>emptyList() : tparTypes;
+    }
+    
+    public JavaType getReturnType()
+    {
+        return returnType;
+    }
+    
+    public Reflective getDeclaringType()
+    {
+        return declaringType;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/NameTransform.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/NameTransform.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ca9cba349199ba014eb2d1acc049892b2d3b0c8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/NameTransform.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+/*
+ * Interface for representing some sort of transform on type names, such as
+ * stripping of package prefixes.
+ * 
+ * @author Davin McCall
+ * 
+ * @version $Id: NameTransform.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface NameTransform
+{
+    /**
+     * Translate the given (fully qualified) type name.
+     * 
+     * @param typeName
+     *            The type name to translate
+     * @return The translated type name
+     */
+    public String transform(String typeName);
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/Reflective.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/Reflective.java
new file mode 100644
index 0000000000000000000000000000000000000000..c002003b7b69ba725d372b7a0fae4d9ede0dd794
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/Reflective.java
@@ -0,0 +1,180 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A "reflective" is an object representing a java type. This interface
+ * provides methods to, for instance, find the superclass/superinterfaces,
+ * determine the generic type parameters, etc.
+ *  
+ * @author Davin McCall
+ */
+public abstract class Reflective
+{
+    /**
+     * Get the name of the class or interface represented by the reflective.
+     * The name is such that it can be passed to ClassLoader's loadClass
+     * method.
+     * 
+     * @return The fully qualified class/interface name.
+     */
+    public abstract String getName();
+    
+    /**
+     * Get the name of the class or interface represented by the reflective.
+     * The name is in a form that can be presented nicely to the user.
+     */
+    public String getSimpleName()
+    {
+        return getName();
+    }
+    
+    /**
+     * Get the formal type parameters of the class/interface this reflective
+     * represents. Note that this does not give the type parameters from
+     * outer classes which may still parameterize this reflective's class.
+     * 
+     * @return  The parameters as a List of GenTypeDeclTpar
+     */
+    public abstract List<GenTypeDeclTpar> getTypeParams();
+    
+    /**
+     * Get the (direct) supertypes of this reflective, as a list of reflectives.
+     * Supertypes of an array include the "Object" class as well as arrays whose
+     * component type is a supertype of this array's component type.
+     * @return A List of Reflectives
+     */
+    public abstract List<Reflective> getSuperTypesR();
+    
+    /**
+     * Get the supertypes of this reflective, as a list of GenTypes. The type
+     * parameter names will refer to the type parameters in the parent type.
+     * @return A List of GenTypeClass.
+     */
+    public abstract List<GenTypeClass> getSuperTypes();
+    
+    /**
+     * Get a reflective which represents an array, whose element type is
+     * represented by this reflective.
+     * 
+     * @return A reflective representing an array
+     */
+    public abstract Reflective getArrayOf();
+    
+    /**
+     * Return true if a variable of the reference type reflected by this
+     * reflective can be assigned a value of the type represented by the given
+     * reflective.
+     * 
+     * @param r  The other reflective
+     * @return   True if the other reflective type is assignable to this type
+     */
+    public abstract boolean isAssignableFrom(Reflective r);
+    
+    /**
+     * Return true if this reflective represents an interface type rather than
+     * a class type.
+     * @return   True if this reflective represents an interface
+     */
+    public abstract boolean isInterface();
+    
+    /**
+     * Get a supertype (as a GenTypeClass) by name. The default implementation
+     * uses getSuperTypes() and searches the resulting list.
+     * 
+     * @param rawName   the name of the supertype to find
+     * @return          the supertype as a GenTypeClass
+     */
+    public GenTypeClass superTypeByName(String rawName)
+    {
+        List<GenTypeClass> superTypes = getSuperTypes();
+        Iterator<GenTypeClass> i = superTypes.iterator();
+        while( i.hasNext() ) {
+            GenTypeClass next = i.next();
+            if( next.classloaderName().equals(rawName) )
+                return next;
+        }
+        return null;
+    }
+    
+    /**
+     * Find another class as if it were to be loaded by this one. Ie. use this
+     * class's classloader.
+     * 
+     * @param name  The name of the class to locate
+     */
+    abstract public Reflective getRelativeClass(String name);
+    
+    /**
+     * Get the outer class of this one, if there is one.
+     */
+    public Reflective getOuterClass()
+    {
+        int dollarIndex = getName().lastIndexOf('$');
+        if (dollarIndex != -1) {
+            // Note that package names can have '$' in them, so
+            // we need to check for that case:
+            int dotIndex = getName().indexOf('.', dollarIndex);
+            if (dotIndex == -1) {
+                String outerName = getName().substring(0, dollarIndex);
+                return getRelativeClass(outerName);
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Determine whether this class is a static inner class.
+     */
+    abstract public boolean isStatic();
+    
+    /**
+     * Determine whether this class is declared public.
+     */
+    abstract public boolean isPublic();
+    
+    /**
+     * Get the methods declared in the type represented by this Reflective.
+     * This does not include methods declared in the superclass(es), nor does
+     * it include synthetic methods.
+     * 
+     * @return a map which maps method names to a set of methods
+     *    (represented by MethodReflective objects) 
+     */
+    abstract public Map<String,Set<MethodReflective>> getDeclaredMethods();
+    
+    /**
+     * Get the fields declared in the type represented by this Reflective.
+     * This does not include fields declared in the superclass(es).
+     */
+    abstract public Map<String,FieldReflective> getDeclaredFields();
+    
+    /**
+     * Get the inner classes of the type represented by this Reflective.
+     */
+    abstract public List<Reflective> getInners();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/TextType.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/TextType.java
new file mode 100644
index 0000000000000000000000000000000000000000..b53c64682a4b803e1bc193dfd7535f785f855791
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/gentype/TextType.java
@@ -0,0 +1,192 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.gentype;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A type for which we know the text representation, but not the structure. Ie.
+ * a type that the user has supplied in a text box, and which we haven't yet
+ * parsed or performed equivalent magic with.<p>
+ * 
+ * This is an actual type, not a wildcard, and not a primitive.<p>
+ * 
+ * Most operations on this type fail with an UnsupportedOperationException.
+ * 
+ * @author Davin McCall
+ */
+public class TextType extends GenTypeSolid
+{
+    private String text;
+    
+    public TextType(String text)
+    {
+        this.text = text;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return text;
+    }
+    
+    public String arrayComponentName()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /*
+     * @see bluej.debugger.gentype.GenType#isPrimitive()
+     */
+    @Override
+    public boolean isPrimitive()
+    {
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.debugger.gentype.GenType#getErasedType()
+     */
+    public JavaType getErasedType()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.debugger.gentype.GenType#isAssignableFrom(bluej.debugger.gentype.GenType)
+     */
+    public boolean isAssignableFrom(JavaType t)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.debugger.gentype.GenType#isAssignableFromRaw(bluej.debugger.gentype.GenType)
+     */
+    public boolean isAssignableFromRaw(JavaType t)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.debugger.gentype.GenType#mapTparsToTypes(java.util.Map)
+     */
+    public JavaType mapTparsToTypes(Map<String, ? extends GenTypeParameter> tparams)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public GenTypeClass asClass()
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    // methods from GenTypeParameterizable
+    
+    public void getParamsFromTemplate(Map<String,GenTypeParameter> map, GenTypeParameter template)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public GenTypeSolid getLowerBound()
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    public boolean equals(JavaType other)
+    {
+        if (other == null) {
+            return false;
+        }
+        
+        if (other == this) {
+            return true;
+        }
+        
+        throw new UnsupportedOperationException();
+    }
+
+    public String toTypeArgString(NameTransform nt)
+    {
+        // throw new UnsupportedOperationException();
+        
+        // Text types are generally typed in by the user, and require
+        // no transformation.
+        return text;
+    }
+    
+    public GenTypeSolid [] getUpperBounds()
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    public GenTypeSolid getUpperBound()
+    {
+        // Maybe not correct, but good enough for our purposes.
+        return this;
+    }
+    
+    @Override
+    public JavaType getCapture()
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
+    public GenTypeArray getArray()
+    {
+        return new GenTypeArray(this);
+    }
+    
+    @Override
+    public boolean isWildcard()
+    {
+        return false;
+    }
+    
+    @Override
+    public void erasedSuperTypes(Set<Reflective> s)
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
+    public GenTypeClass[] getReferenceSupertypes()
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
+    public boolean isInterface()
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
+    public String toString(NameTransform nt)
+    {
+        return text;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiArray.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..34e6085e16eccb3cfa8facfd8b2ada98badec84c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiArray.java
@@ -0,0 +1,191 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2000-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.GenTypeArray;
+import bluej.debugger.gentype.GenTypeArrayClass;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+import com.sun.jdi.ArrayReference;
+import com.sun.jdi.ArrayType;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.Value;
+
+/**
+ * Represents an array object running on the user (remote) machine.
+ *
+ * @author     Michael Kolling
+ * @created    December 26, 2000
+ */
+public class JdiArray extends JdiObject
+{    
+    private JavaType componentType; 
+    
+    protected JdiArray(ArrayReference obj)
+    {
+        this.obj = obj;
+        obj.disableCollection();
+        calcComponentType();
+    }
+
+    /**
+     * Constructor for when the array type is known.
+     * @param obj           The reference to the the remote object
+     * @param expectedType  The known type of the object
+     */
+    protected JdiArray(ArrayReference obj, JavaType expectedType)
+    {
+        this.obj = obj;
+        obj.disableCollection();
+        // All arrays extend java.lang.Object - so it's possible that the
+        // expected type is java.lang.Object and not an array type at all.
+        if(expectedType instanceof GenTypeArray) {
+            String ctypestr = obj.referenceType().signature();
+            JavaType genericType = expectedType;
+            int level = 0;
+            
+            // Go downwards until we find the base component type
+            while(genericType instanceof GenTypeArray) {
+                GenTypeArray genericArray = (GenTypeArray)genericType;
+                genericType = genericArray.getArrayComponent();
+                ctypestr = ctypestr.substring(1);
+                level++;
+            }
+            
+            // If the arrays are of different depths, no inference is possible
+            // (this is possible because all arrays extend Object)
+            if(ctypestr.charAt(0) == '[') {
+                calcComponentType();
+                return;
+            }
+
+            // The array may be of a primitive type.
+            if(genericType.isPrimitive()) {
+                calcComponentType();
+                return;
+            }
+
+            // It's not really possible for an array to have a component type
+            // that is a wildcard, but this type is inferred in some cases so
+            // it must be handled here.
+            
+            JavaType component;
+            
+            if (genericType instanceof GenTypeClass) {
+                // the sig looks like "Lpackage/package/class;". Strip the 'L'
+                // and the ';'
+                String compName = ctypestr.substring(1, ctypestr.length() - 1);
+                compName = compName.replace('/', '.');
+
+                Reflective compReflective = new JdiReflective(compName, obj.referenceType());
+                component = ((GenTypeClass) genericType).mapToDerived(compReflective);
+
+                while (level > 1) {
+                    component = component.getArray();
+                    level--;
+                }
+                componentType = component;
+            }
+        }
+        
+        if (componentType == null) {
+            calcComponentType();
+        }
+    }
+    
+    private void calcComponentType()
+    {
+        ArrayType ar = (ArrayType) obj.referenceType();
+        String componentSig = ar.componentSignature();
+        JdiReflective.StringIterator i = new JdiReflective.StringIterator(componentSig);
+        componentType = JdiReflective.typeFromSignature(i, null, ar);
+    }
+
+    /**
+     * Get the name of the class of this object.
+     * 
+     * @return String representing the Class name.
+     */
+    @Override
+    public String getClassName()
+    {
+        return obj.referenceType().name();
+    }
+
+    /**
+     * Get the GenType object representing the type of this array.
+     * 
+     * @return   GenType representing the type of the array.
+     */
+    @Override
+    public GenTypeClass getGenType()
+    {
+        Reflective r = new JdiArrayReflective(componentType, obj.referenceType());
+        return new GenTypeArrayClass(r, componentType);
+    }
+    
+    /**
+     * Return true if this object is an array.
+     *
+     * @return    The Array value
+     */
+    @Override
+    public boolean isArray()
+    {
+        return true;
+    }
+
+    @Override
+    public int getElementCount()
+    {
+        return ((ArrayReference) obj).length();
+    }
+    
+    @Override
+    public JavaType getElementType()
+    {
+        return componentType;
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        Value val = ((ArrayReference) obj).getValue(index);
+        return JdiUtils.getJdiUtils().getValueString(val);
+    }
+
+    /*
+     * Return the object in object field 'slot'.
+     *
+     * @param  slot  The slot number to be returned
+     * @return       The InstanceFieldObject value
+     */
+    @Override
+    public DebuggerObject getElementObject(int index)
+    {
+        Value val = ((ArrayReference) obj).getValue(index);
+        return JdiObject.getDebuggerObject((ObjectReference) val, componentType);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiArrayReflective.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiArrayReflective.java
new file mode 100644
index 0000000000000000000000000000000000000000..f76f9fc578453ea8065649102d9c06de78aa36c1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiArrayReflective.java
@@ -0,0 +1,69 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import bluej.debugger.gentype.*;
+
+import com.sun.jdi.ClassLoaderReference;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.VirtualMachine;
+
+/**
+ * A proxy-type reflective for arrays.
+ * 
+ * @author Davin McCall
+ */
+public class JdiArrayReflective extends JdiReflective
+{
+    private JavaType componentType;
+    
+    public JdiArrayReflective(JavaType t, ReferenceType srctype)
+    {
+        super(null, srctype);
+        componentType = t;
+    }
+    
+    /**
+     * Create a new JdiArrayReflective representing an array with a certain component type.
+     * @param t            The component type
+     * @param classLoader  The classloader used to load the component type (or the array)
+     * @param vm           The virtual machine holding the type
+     */
+    public JdiArrayReflective(JavaType t, ClassLoaderReference classLoader, VirtualMachine vm)
+    {
+        super("[" + t.arrayComponentName(), classLoader, vm);
+        componentType = t;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return super.getName();
+    }
+    
+    @Override
+    protected void checkLoaded()
+    {
+        name = "[" + componentType.arrayComponentName();
+        super.checkLoaded();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiClass.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e401619fb25d078ebbabd39bb275c52ccab8b38
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiClass.java
@@ -0,0 +1,123 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerField;
+import bluej.utility.Debug;
+
+import com.sun.jdi.ClassType;
+import com.sun.jdi.Field;
+import com.sun.jdi.InterfaceType;
+import com.sun.jdi.ReferenceType;
+
+/**
+ * Represents an class running on the user (remote) machine.
+ *
+ * @author     Michael Kolling
+ * @created    December 26, 2000
+ */
+public class JdiClass extends DebuggerClass
+{
+    ReferenceType remoteClass;  // the remote class represented
+    List<Field> staticFields;
+
+    // -- instance methods --
+
+    /**
+     *  Create a remote class object.
+     *
+     *@param  obj  the remote debugger object (Jdi code) this encapsulates.
+     */
+    public JdiClass(ReferenceType remoteClass)
+    {
+        this.remoteClass = remoteClass;
+        getRemoteFields();
+    }
+
+
+    /*
+     * Return the name of this class (fully qualified).
+     *
+     * @return    The class name
+     */
+    @Override
+    public String getName()
+    {
+        return remoteClass.name();
+    }
+
+    @Override
+    public List<DebuggerField> getStaticFields()
+    {
+        List<Field> visibleFields = remoteClass.visibleFields();
+        List<DebuggerField> rlist = new ArrayList<DebuggerField>(staticFields.size());
+        for (Field field : staticFields) {
+            rlist.add(new JdiField(field, null, ! visibleFields.contains(field)));
+        }
+        return rlist;
+    }
+
+    /*
+     * Returns true if this represents a Java interface
+     */
+    @Override
+    public boolean isInterface()
+    {
+        return remoteClass instanceof InterfaceType;
+    }
+
+    /*
+     * Returns true if this represents an enum
+     */
+    @Override
+    public boolean isEnum()
+    {
+        if (remoteClass instanceof ClassType) {
+            return JdiUtils.getJdiUtils().isEnum((ClassType) remoteClass);
+        }
+        return false;
+    }
+
+    /**
+     *  Get the list of fields for this object.
+     */
+    private void getRemoteFields()
+    {
+        staticFields = new ArrayList<Field>();
+
+        if (remoteClass != null) {
+            List<Field> allFields = remoteClass.allFields();
+            for (int i = 0; i < allFields.size(); i++) {
+                Field field = (Field) allFields.get(i);
+                if (field.isStatic())
+                    staticFields.add(field);
+            }
+        }
+        else {
+            Debug.reportError("cannot get fields for remote class");
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiDebugger.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiDebugger.java
new file mode 100644
index 0000000000000000000000000000000000000000..461840b7ed308f43c339d4ee02c728de3ccd0f4c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiDebugger.java
@@ -0,0 +1,1237 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import bluej.Config;
+import bluej.classmgr.BPClassLoader;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerEvent;
+import bluej.debugger.DebuggerListener;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.DebuggerResult;
+import bluej.debugger.DebuggerTerminal;
+import bluej.debugger.DebuggerTestResult;
+import bluej.debugger.DebuggerThreadTreeModel;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugger.SourceLocation;
+import bluej.debugmgr.Invoker;
+import bluej.utility.Debug;
+import bluej.utility.JavaNames;
+
+import com.sun.jdi.ArrayReference;
+import com.sun.jdi.Field;
+import com.sun.jdi.InvocationException;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.StringReference;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.VMOutOfMemoryException;
+import com.sun.jdi.Value;
+
+/**
+ * A class implementing the execution and debugging primitives needed by BlueJ.
+ * 
+ * <p>This class is tightly coupled with the classes VMReference and
+ * VMEventHandler. JdiDebugger is the half of the debugger that is persistent
+ * across debugger sessions. VMReference and VMEventHandler will be constructed
+ * anew each time a remote VM is started. VMReference handles most of the work
+ * of making the remote VM do things. VMEventHandler starts a new thread that
+ * listens for remote VM events and calls back into VMReference on reciept of
+ * these events.
+ * 
+ * <p>Most of the actual access to the virtual machine occurs through the
+ * MachineLoader thread. When the vm is restarted by user request, a new loader
+ * thread is created immediately so that any method calls/etc will execute on
+ * the new machine (after waiting until it has loaded).
+ * 
+ * @author Michael Kolling
+ * @author Andrew Patterson
+ */
+public class JdiDebugger extends Debugger
+{
+    private static final int loaderPriority = Thread.NORM_PRIORITY - 2;
+
+    // If false, specifies that a new VM should be started when the old one dies
+    private boolean autoRestart = true;
+
+    // Did we order the VM to restart ourself? This is used to flag the launch()
+    // method that a new loader thread doesn't need to be re-created.
+    private boolean selfRestart = false;
+
+    /**
+     * The reference to the current remote VM handler. Will be null if the remote VM is not
+     * currently running.
+     */
+    private VMReference vmRef;
+
+    // the thread that we spawn to load the current remote VM
+    private MachineLoaderThread machineLoader;
+    
+    /** An object to provide a lock for server thread execution */
+    private Object serverThreadLock = new Object();
+
+    // a set holding all the JdiThreads in the VM
+    private JdiThreadSet allThreads;
+
+    // a TreeModel exposing selected JdiThreads in the VM
+    private JdiThreadTreeModel treeModel;
+
+    // listeners for events that occur in the debugger
+    private List<DebuggerListener> listenerList = new ArrayList<DebuggerListener>();
+
+    // the directory to launch the VM in
+    private File startingDirectory;
+
+    // terminal to use for all VM input and output
+    private DebuggerTerminal terminal;
+
+    // a Set of strings which have been used as names on the
+    // object bench. We endeavour to not reuse them.
+    private Set<String> usedNames;
+
+    // indicate whether we want to see system threads
+    private boolean hideSystemThreads;
+    
+    /**
+     * Current machine state. This is changed only by the VM event queue (see VMEventHandler),
+     * but write access is also protected by the listener list mutex. This makes it possible to
+     * add a listener and know the state at the time the listener was added. Furthermore the
+     * state will only be set to RUNNING while the server thread lock is also held.
+     */
+    private int machineState = NOTREADY;
+    
+    // classpath to be used for the remote VM
+    private BPClassLoader lastProjectClassLoader;
+    
+    // most recent exception description
+    private ExceptionDescription lastException;
+    
+    /** User libraries to be added to VM classpath */
+    private URL[] libraries = {};
+
+    /**
+     * Construct an instance of the debugger.
+     * 
+     * <p>This constructor should not be used by the main part of BlueJ. Access
+     * should be through Debugger.getDebuggerImpl().
+     * 
+     * @param startingDirectory
+     *            a File representing the directory we should launch the debug
+     *            VM in.
+     * @param terminal
+     *            a Terminal where we can do input/output.
+     */
+    public JdiDebugger(File startingDirectory, DebuggerTerminal terminal)
+    {
+        this.startingDirectory = startingDirectory;
+        this.terminal = terminal;
+
+        allThreads = new JdiThreadSet();
+        treeModel = new JdiThreadTreeModel(new JdiThreadNode());
+        usedNames = new TreeSet<String>();
+        hideSystemThreads = true;
+    }
+
+    @Override
+    public void setUserLibraries(URL[] libraries)
+    {
+        this.libraries = libraries;
+    }
+    
+    /**
+     * Start debugging.
+     */
+    @Override
+    public synchronized void launch()
+    {
+        // This could be either an initial launch (selfRestart == false) or
+        // a restart (selfRestart == true and machineLoader != null). In the
+        // latter case, there's no need to create a new machine loader, as
+        // that's pre-done in close(), below.
+
+        if (vmRef != null) {
+            throw new IllegalStateException("JdiDebugger.launch() was called but the debugger was already loaded");
+        }
+
+        if (machineLoader != null && !selfRestart) {
+            // Attempt to restart VM while already restarting - ignored,
+            // except when self-restarting, seeing as the new machine loader
+            // has already been created in that case.
+            return;
+        }
+
+        autoRestart = true;
+
+        // start the MachineLoader (a separate thread) to load the
+        // remote virtual machine in the background
+
+        if (!selfRestart) {
+            // if selfRestart == true, this has already been done
+            machineLoader = new MachineLoaderThread();
+        }
+        selfRestart = false;
+        // lower priority to improve GUI response time
+        machineLoader.setPriority(loaderPriority);
+        machineLoader.start();
+    }
+
+    /**
+     * Close this VM, possibly restart it.
+     */
+    @Override
+    public synchronized void close(boolean restart)
+    {
+        // There are essentially three states the remote process could be in:
+        // started, stopping, or launching. It will not already be stopped
+        // as this only occurs when the project is closed.
+        //
+        // Following conditions are true in each state:
+        //
+        // Started: vmRunning = true.
+        //
+        // Stopping:  (for restart)
+        //            vmRunning = false. selfRestart = true.
+        //            machineLoader != null.
+        //                   - or -
+        //            (for permanent close)
+        //            vmRunning = false. selfRestart = false.
+        //            machineLoader == null.
+        //
+        // Launching: vmRunning = false. selfRestart = false.
+        //              machineLoader != null.
+
+        if (vmRef != null) {
+            // The process is already started. We want to stop it (and
+            // possibly to then restart it).
+            autoRestart = restart;
+            selfRestart = restart;
+
+            // Create the new machine loader thread. That way any operation
+            // on the VM between now and the time the new machine has finished
+            // loading, can sleep until the new machine is ready.
+            if (selfRestart) {
+                machineLoader = new MachineLoaderThread();
+            }
+
+            // kill the remote debugger process
+            vmRef.close();
+
+            // we will eventually get a vmDisconnect event and end up in
+            // method vmDisconnect() (below)
+        }
+        // The state is either "launching" or "stopping for restart". In either
+        // case, if restart parameter == true, no further action is necessary. If
+        // restart is false, we need to make sure no relaunch occurs (or it is
+        // halted immediately).
+        else if (!restart) {
+            autoRestart = false;
+            selfRestart = false;
+            machineLoader = null;
+        }
+    }
+
+    /**
+     * Add a listener for DebuggerEvents
+     * 
+     * @param l
+     *            the DebuggerListener to add
+     */
+    public int addDebuggerListener(DebuggerListener l)
+    {
+        synchronized (listenerList) {
+            listenerList.add(l);
+            return machineState;
+        }
+    }
+
+    /**
+     * Remove a listener for DebuggerEvents.
+     * 
+     * @param l
+     *            the DebuggerListener to remove
+     */
+    public void removeDebuggerListener(DebuggerListener l)
+    {
+        synchronized (listenerList) {
+            listenerList.remove(l);
+        }
+    }
+    
+    /**
+     * Get a copy of the listener list.
+     */
+    private DebuggerListener [] getListeners()
+    {
+        synchronized (listenerList) {
+            return listenerList.toArray(new DebuggerListener[listenerList.size()]);
+        }
+    }
+
+    /**
+     * Guess a suitable name for an object about to be put on the object bench.
+     * 
+     * @param className
+     *            the fully qualified name of the class of object
+     * @return a String suitable as a name for an object on the object bench.
+     */
+    public String guessNewName(String className)
+    {
+        // className can have array brackets at the end which is not suitable
+        // for an identifier. We'll strip them out
+        className = className.replace('[', ' ').replace(']', ' ').trim();
+
+        String baseName = JavaNames.getBase(className);
+
+        // truncate long names to OBJ_NAME_LENGTH plus _instanceNum
+        int stringEndIndex = baseName.length() > Invoker.OBJ_NAME_LENGTH ? Invoker.OBJ_NAME_LENGTH : baseName.length();
+
+        String newName = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1, stringEndIndex);
+
+        int num = 1;
+
+        synchronized(this) {
+            while (usedNames.contains(newName + num))
+                num++;
+        }
+
+        return newName + num;
+    }
+    
+    
+    public String guessNewName(DebuggerObject obj)       
+    {
+        String name = null;
+        DebuggerClass cls = obj.getClassRef();
+        
+        if(cls.isEnum()) {
+            Value val = obj.getObjectReference();
+            name = JdiUtils.getJdiUtils().getValueString(val);
+        }
+        
+        if(name == null) {
+            name = cls.getName();
+        }
+        
+        return guessNewName(name);
+    }
+   
+    /**
+     * Create a class loader in the debugger.
+     * @param bpClassLoader the class loader that should be used to load the user classes in the remote VM.
+     */
+    public synchronized void newClassLoader(BPClassLoader bpClassLoader)
+    {
+        // lastProjectClassLoader is used if there is a VM restart
+        if (bpClassLoader != null) {
+            lastProjectClassLoader = bpClassLoader;
+        }
+        else {
+            return;
+        }
+    
+        VMReference vmr = getVMNoWait();
+        if (vmr != null) {
+            usedNames.clear();
+            try {
+                vmr.clearAllBreakpoints();
+                vmr.newClassLoader(bpClassLoader.getURLs());
+            }
+            catch (VMDisconnectedException vmde) {}
+        }
+    }
+
+    /**
+     * Remove all breakpoints in the given class.
+     */
+    public void removeBreakpointsForClass(String className)
+    {
+        VMReference vmr = getVMNoWait();
+        if (vmr != null) {
+            vmr.clearBreakpointsForClass(className);
+        }
+    }
+    
+    /**
+     * Add a debugger object into the project scope.
+     * 
+     * @param newInstanceName
+     *            the name of the object dob the object itself
+     * @return true if the object could be added with this name, false if there
+     *         was a name clash.
+     */
+    public boolean addObject(String scopeId, String newInstanceName, DebuggerObject dob)
+    {
+        VMReference vmr = getVMNoWait();
+        if (vmr != null) {
+            vmr.addObject(scopeId, newInstanceName, ((JdiObject) dob).getObjectReference());
+            synchronized (this) {
+                usedNames.add(newInstanceName);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Remove an object from a package scope (when removed from object bench).
+     */
+    public void removeObject(String scopeId, String instanceName)
+    {
+        VMReference vmr = getVMNoWait();
+        if (vmr != null) {
+            vmr.removeObject(scopeId, instanceName);
+        }
+    }
+
+    /**
+     * Return the debugger objects that exist in the debugger.
+     * 
+     * @return a Map of (String name, DebuggerObject obj) entries
+     */
+    public Map<String, DebuggerObject> getObjects()
+    {
+        throw new IllegalStateException("not implemented");
+        // the returned array consists of double the number of objects
+        // they alternate, name, object, name, object
+        // ie.
+        // arrayRef[0] = a field name 0 (StringReference)
+        // arrayRef[1] = a field value 0 (ObjectReference)
+        // arrayRef[2] = a field name 1 (StringReference)
+        // arrayRef[3] = a field value 1 (ObjectReference)
+        //
+    }
+    
+    /**
+     * Return the machine status; one of the "machine state" constants:
+     * NOTREADY, IDLE, RUNNING, or SUSPENDED.
+     */
+    public int getStatus()
+    {
+        return machineState;
+    }
+    
+    /*
+     * @see bluej.debugger.Debugger#getMirror(java.lang.String)
+     */
+    public DebuggerObject getMirror(String value)
+    {
+        VMReference vmr = getVM();
+        if (vmr != null) {
+            try {
+                return JdiObject.getDebuggerObject(vmr.getMirror(value));
+            }
+            catch (VMDisconnectedException vde) { }
+            catch (VMOutOfMemoryException vmoome) { }
+        }
+        return null;
+    }
+
+    /**
+     * Return the text of the last exception.
+     */
+    public ExceptionDescription getException()
+    {
+        return lastException;
+    }
+
+    /**
+     * List all threads being debugged as a TreeModel.
+     * 
+     * @return A tree model of all the threads.
+     */
+    public DebuggerThreadTreeModel getThreadTreeModel()
+    {
+        return treeModel;
+    }
+
+    // ------ Following methods run code on server thread in debug VM ------
+    //
+    // These methods synchronise on serverThreadLock.
+
+    /**
+     * Run the setUp() method of a test class and return the created objects.
+     * 
+     * @param className
+     *            the fully qualified name of the class
+     * @return a Map of (String name, DebuggerObject obj) entries
+     *         null if an error occurs (such as VM termination)
+     */
+    public Map<String, DebuggerObject> runTestSetUp(String className)
+    {
+        ArrayReference arrayRef = null;
+        Map<String, DebuggerObject> returnMap = new HashMap<String, DebuggerObject>();
+        
+        VMReference vmr = getVM();
+        try {
+            synchronized (serverThreadLock) {
+                if (vmr != null) {
+                    arrayRef = (ArrayReference) vmr.invokeTestSetup(className);
+                }
+                
+                // the returned array consists of double the number of fields created by
+                // running test setup plus one extra slot
+                // they alternate, fieldname, fieldvalue, fieldname, fieldvalue
+                // ie.
+                // arrayRef[0] = a field name 0 (StringReference)
+                // arrayRef[1] = a field value 0 (ObjectReference)
+                // arrayRef[2] = a field name 1 (StringReference)
+                // arrayRef[3] = a field value 1 (ObjectReference)
+                // with the last slot being reserved for the ObjectReference of the actual 
+                // test object. This is used to extract (potentially generic) fields.
+                // we could return a Map from RUN_TEST_SETUP but then we'd have to use
+                // JDI reflection to make method calls on Map in order to extract the values
+                
+                if (arrayRef != null) {
+                    
+                    // The test case object
+                    ObjectReference testObject = (ObjectReference)arrayRef.getValue(arrayRef.length()-1);
+                    // get the associated JdiObject so that we can get potentially generic fields 
+                    // from the test case.
+                    JdiObject jdiTestObject = JdiObject.getDebuggerObject(testObject);
+                    
+                    // last slot in array is test case object so it does not get touched here
+                    // our iteration boundary is therefore one less than array length
+                    for (int i = 0; i < arrayRef.length() - 1; i += 2) {
+                        String fieldName = ((StringReference) arrayRef.getValue(i)).value();
+                        Field testField = testObject.referenceType().fieldByName(fieldName);            
+                        returnMap.put(fieldName, JdiObject
+                                .getDebuggerObject((ObjectReference) arrayRef.getValue(i + 1), testField, jdiTestObject));
+                    }
+                }
+            }
+        }
+        catch (InvocationException e) {
+            // what to do here??
+            return null;
+        }
+        catch (VMDisconnectedException e) {
+            return null;
+        }
+        
+        // the resulting map consists of entries (String fieldName, JdiObject
+        // obj)
+        return returnMap;
+    }
+
+    /**
+     * Run a single test method in a test class and return the result.
+     * 
+     * @param className
+     *            the fully qualified name of the class
+     * @param methodName
+     *            the name of the method
+     * @return a DebuggerTestResult object
+     */
+    public DebuggerTestResult runTestMethod(String className, String methodName)
+    {
+        ArrayReference arrayRef = null;
+
+        try {
+            VMReference vmr = getVM();
+            synchronized (serverThreadLock) {
+                if (vmr != null) {
+                    arrayRef = (ArrayReference) vmr.invokeRunTest(className, methodName);
+                }
+                
+                if (arrayRef == null || arrayRef.length() == 0) {
+                    return new JdiTestResultError(className, methodName, "VM returned unknown result", "", null, 0);
+                }
+                
+                int runTimeMs = Integer.parseInt(((StringReference) arrayRef.getValue(0)).value());
+                
+                if (arrayRef != null && arrayRef.length() > 5) {
+                    String failureType = ((StringReference) arrayRef.getValue(7)).value();
+                    String exMsg = ((StringReference) arrayRef.getValue(1)).value();
+                    String traceMsg = ((StringReference) arrayRef.getValue(2)).value();
+                    
+                    String failureClass = ((StringReference) arrayRef.getValue(3)).value();
+                    String failureSource = ((StringReference) arrayRef.getValue(4)).value();
+                    String failureMethod = ((StringReference) arrayRef.getValue(5)).value();
+                    int lineNo = Integer.parseInt(((StringReference) arrayRef.getValue(6)).value());
+                    SourceLocation failPoint = new SourceLocation(failureClass, failureSource, failureMethod, lineNo);
+                    
+                    if (failureType.equals("failure")) {
+                        return new JdiTestResultFailure(className, methodName, exMsg, traceMsg, failPoint, runTimeMs);
+                    }
+                    else {
+                        return new JdiTestResultError(className, methodName, exMsg, traceMsg, failPoint, runTimeMs);
+                    }
+                    
+                } else if (arrayRef != null && arrayRef.length() == 1) {
+                    // Success - extract the run time in mS
+                    return new JdiTestResult(className, methodName, runTimeMs);
+                }
+            }
+        }
+        catch (InvocationException ie) {
+            // what to do here??
+            return new JdiTestResultError(className, methodName, "Internal invocation error", "", null, 0);
+        }
+        catch (VMDisconnectedException vmde) {
+            return new JdiTestResultError(className, methodName, "VM restarted", "", null, 0);
+        }
+        
+        // should never get here
+        return new JdiTestResultError(className, methodName, "VM returned unknown result", "", null, 0);
+    }
+
+    /**
+     * Dispose all top level windows in the remote machine.
+     */
+    public void disposeWindows()
+    {
+        VMReference vmr = getVMNoWait();
+
+        try {
+            synchronized (serverThreadLock) {
+            if (vmr != null)
+                vmr.disposeWindows();
+            }
+        }
+        catch (VMDisconnectedException e) {}
+    }
+
+    /**
+     * "Start" a class (i.e. invoke its main method)
+     * 
+     * @param classname
+     *            the class to start
+     */
+    public DebuggerResult runClassMain(String className)
+        throws ClassNotFoundException
+    {
+        VMReference vmr = getVM();
+        synchronized (serverThreadLock) {
+            if (vmr != null) {
+                return vmr.runShellClass(className);
+            }
+            else {
+                return null;
+            }
+        }
+    }
+    
+    /**
+     * Construct a class instance using the default constructor.
+     */
+    public DebuggerResult instantiateClass(String className)
+    {
+        VMReference vmr = getVM();
+        if (vmr != null) {
+            synchronized (serverThreadLock) {
+                return vmr.instantiateClass(className);
+            }
+        }
+        else {
+            return new DebuggerResult(Debugger.TERMINATED);
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.debugger.Debugger#instantiateClass(java.lang.String, java.lang.String[], bluej.debugger.DebuggerObject[])
+     */
+    public DebuggerResult instantiateClass(String className, String[] paramTypes, DebuggerObject[] args)
+    {
+        // If there are no arguments, use the default constructor
+        if (paramTypes == null || args == null || paramTypes.length == 0 || args.length == 0) {
+            return instantiateClass(className);
+        }
+        
+        VMReference vmr = getVM();
+        if (vmr != null) {
+            // Convert the args array from DebuggerObject[] to ObjectReference[]
+            ObjectReference [] orArgs = new ObjectReference[args.length];
+            for (int i = 0; i < args.length; i++) {
+                JdiObject jdiObject = (JdiObject) args[i];
+                orArgs[i] = jdiObject.getObjectReference(); 
+            }
+            
+            synchronized (serverThreadLock) {
+                return vmr.instantiateClass(className, paramTypes, orArgs);
+            }
+        }
+        else {
+            return new DebuggerResult(Debugger.TERMINATED);
+        }
+    }
+    
+    /*
+     * @see bluej.debugger.Debugger#getClass(java.lang.String, boolean)
+     */
+    public DebuggerClass getClass(String className, boolean initialize)
+        throws ClassNotFoundException
+    {
+        VMReference vmr = getVM();
+        if (vmr == null) {
+            throw new ClassNotFoundException("Virtual machine terminated.");
+        }
+            
+        ReferenceType classMirror;
+        synchronized (serverThreadLock) {
+            // machineState can only be changed *to* RUNNING while the serverThreadLock is held, so
+            // this check is safe:
+            if (initialize && machineState != Debugger.RUNNING) {
+                classMirror = vmr.loadInitClass(className);
+            }
+            else {
+                classMirror = vmr.loadClass(className);
+            }
+        }
+
+        return new JdiClass(classMirror);
+    }
+
+    // ----- end server thread methods -----
+    
+    /**
+     * notify all listeners that have registered interest for
+     * notification on this event type.
+     */ 
+    private void fireTargetEvent(DebuggerEvent ce, boolean skipUpdate)
+    {
+        // Guaranteed to return a non-null array
+        DebuggerListener[] listeners = getListeners();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length - 1; i >= 0; i --) {
+            listeners[i].processDebuggerEvent(ce, skipUpdate);
+        }
+    }
+    
+    void raiseStateChangeEvent(int newState)
+    {
+        // It might look this method should be synchronized, but it shouldn't,
+        // because state change is effectively serialized by VMEventHandler (except
+        // in some cases where it is known that no VM is running).
+        
+        if (newState != machineState) {
+            
+            // Going from SUSPENDED to any other state must ass through RUNNING
+            if (machineState == SUSPENDED && newState != RUNNING) {
+                doStateChange(SUSPENDED, RUNNING);
+            }
+            
+            // If going from RUNNING state to NOTREADY state, first pass
+            // through IDLE state
+            if (machineState == RUNNING && newState == NOTREADY) {
+                doStateChange(RUNNING, IDLE);
+            }
+            
+            doStateChange(machineState, newState);
+        }
+    }
+    
+    private void doStateChange(int oldState, int newState)
+    {
+        DebuggerListener[] ll;
+        synchronized (listenerList) {
+            ll = listenerList.toArray(new DebuggerListener[listenerList.size()]);
+            machineState = newState;
+        }
+        
+        for (DebuggerListener l : ll) {
+            l.processDebuggerEvent(new DebuggerEvent(this, DebuggerEvent.DEBUGGER_STATECHANGED,
+                    oldState, newState), false);
+        }
+    }
+
+    // ==== code for active debugging: setting breakpoints, stepping, etc ===
+
+    /**
+     * Set/clear a breakpoint at a specified line in a class.
+     * 
+     * @param className
+     *            The class in which to set/clear the breakpoint.
+     * @param line
+     *            The line number of the breakpoint.
+     * @param set
+     *            True to set, false to clear a breakpoint.
+     * 
+     * @return null if there was no problem, or an error string
+     */
+    public String toggleBreakpoint(String className, int line, boolean set, Map<String, String> properties)
+    {
+        // Debug.message("[toggleBreakpoint]: " + className + " line " + line);
+
+        VMReference vmr = getVM();
+        try {
+            if (vmr != null) {
+                if (set) {
+                    return vmr.setBreakpoint(className, line, properties);
+                }
+                else {
+                    return vmr.clearBreakpoint(className, line);
+                }
+            }
+            else {
+                return "VM terminated.";
+            }
+        }
+        catch (Exception e) {
+            Debug.reportError("breakpoint error: " + e);
+            e.printStackTrace(System.out);
+            return Config.getString("debugger.jdiDebugger.internalErrorMsg");
+        }
+    }
+    
+    /*
+     * @see bluej.debugger.Debugger#toggleBreakpoint(java.lang.String, java.lang.String, boolean, java.util.Map)
+     */
+    public String toggleBreakpoint(String className, String method, boolean set, Map<String, String> properties)
+    {
+        VMReference vmr = getVM();
+        try {
+            if (vmr != null) {
+                if (set) {
+                    return vmr.setBreakpoint(className, method, properties);
+                }
+                else {
+                    return vmr.clearBreakpoint(className, method);
+                }
+            }
+            else {
+                return "VM terminated.";
+            }
+        }
+        catch (Exception e) {
+            Debug.reportError("breakpoint error: " + e);
+            e.printStackTrace(System.out);
+            return Config.getString("debugger.jdiDebugger.internalErrorMsg");
+        }
+    }
+    
+    /*
+     * @see bluej.debugger.Debugger#toggleBreakpoint(bluej.debugger.DebuggerClass, java.lang.String, boolean, java.util.Map)
+     */
+    public String toggleBreakpoint(DebuggerClass debuggerClass, String method, boolean set, Map<String, String> properties)
+    {
+        VMReference vmr = getVM();
+        try {
+            if (vmr != null) {
+                JdiClass jdiClass = (JdiClass) debuggerClass;
+                if (set) {
+                    return vmr.setBreakpoint(jdiClass.remoteClass, method, properties);
+                }
+                else {
+                    return vmr.clearBreakpoint(jdiClass.remoteClass, method);
+                }
+            }
+            else {
+                return "VM terminated.";
+            }
+        }
+        catch (Exception e) {
+            Debug.reportError("breakpoint error: " + e);
+            e.printStackTrace(System.out);
+            return Config.getString("debugger.jdiDebugger.internalErrorMsg");
+        }
+    }
+
+
+    /**
+     * Called by VMReference when a breakpoint/step is encountered in the
+     * debugger VM.
+     * 
+     * @param tr   the thread in which code hit the breakpoint/step
+     * @param bp   true for a breakpoint, false for a step
+     */
+    public void breakpoint(final ThreadReference tr, final int debuggerEventType, boolean skipUpdate, DebuggerEvent.BreakpointProperties props)
+    {
+        final JdiThread breakThread = allThreads.find(tr);
+        if (false == skipUpdate) {
+            treeModel.syncExec(new Runnable() {
+                public void run()
+                {
+                    JdiThreadNode jtn = treeModel.findThreadNode(tr);
+                    // if the thread at the breakpoint is not currently displayed,
+                    // display it now.
+                    if (jtn == null) {
+                        JdiThreadNode root = treeModel.getThreadRoot();
+                        treeModel.insertNodeInto(new JdiThreadNode(breakThread), root, 0);
+                    }
+                    else {
+                        treeModel.nodeChanged(jtn);
+                    }
+                }
+            });
+        }
+
+        fireTargetEvent(new DebuggerEvent(this, debuggerEventType, breakThread, props), skipUpdate);
+    }
+    
+    /**
+     * Screen a breakpoint/step event through interested listeners.
+     * 
+     * @param thread  The thread which hit the breakpoint/step event.
+     * @param breakpoint  True if this is a breakpoint; false if a step. Note that both can occur
+     *                    simultaneously, in which case both are screened individually.
+     * @param props   The breakpoint properties (if any).
+     * @return   true if the event is screened, that is, the GUI should not be updated because the
+     *                result of the event is temporary.
+     */
+    public boolean screenBreakpoint(ThreadReference thread, int debuggerEventType,
+            DebuggerEvent.BreakpointProperties props)
+    {
+        JdiThread breakThread = allThreads.find(thread);
+        breakThread.stopped();
+        
+        DebuggerEvent event = new DebuggerEvent(this, debuggerEventType, breakThread, props);
+        
+        boolean done = false;
+        // Guaranteed to return a non-null array
+        DebuggerListener[] listeners = getListeners();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length - 1; i >= 0; i--) {
+            done = done || listeners[i].examineDebuggerEvent(event);
+        }
+        return done;
+    }
+
+    // - event handling
+
+    /**
+     * Called by VMReference when the machine disconnects. The disconnect event
+     * follows a machine 'exit' event.
+     */
+    synchronized void vmDisconnect()
+    {
+        if (autoRestart) {
+            
+            allThreads.clear();
+            
+            // It's possible to receive vmDisconnect before we're even aware that
+            // we're running. We can ignore it in that case. Synchronization insures
+            // that valid disconnect events are never lost.
+            if (vmRef != null) {
+                // Indicate to the launch procedure that we are not in a launch 
+                // (see launch()).
+                //
+                // In the case of a self-restart, a new machine loader has only
+                // just been set-up, so don't trash it now!
+                if (!selfRestart) {
+                    machineLoader = new MachineLoaderThread();
+                }
+                selfRestart = true;
+                
+                vmRef.closeIO();
+                vmRef = null;
+                
+                raiseStateChangeEvent(Debugger.NOTREADY);
+
+                launch();
+                
+                usedNames.clear();
+                treeModel.syncExec(new Runnable() {
+                    public void run()
+                    {
+                        treeModel.setRoot(new JdiThreadNode());
+                        treeModel.reload();
+                    }
+                });
+            }
+        }
+    }
+
+    /**
+     * Called by VMReference when a thread is started in the debugger VM.
+     * 
+     * Use this event to keep our thread tree model up to date. Currently we
+     * ignore the thread group and construct all threads at the same level.
+     */
+    void threadStart(final ThreadReference tr)
+    {
+        final JdiThread newThread = new JdiThread(this, tr);
+        allThreads.add(newThread);
+        treeModel.syncExec(new Runnable() {
+            public void run()
+            {
+                displayThread(newThread);
+            }
+        });
+    }
+
+    /**
+     * Called by VMReference when a thread dies in the debugger VM.
+     * 
+     * Use this event to keep our thread tree model up to date.
+     */
+    void threadDeath(final ThreadReference tr)
+    {
+        allThreads.removeThread(tr);
+        treeModel.syncExec(new Runnable() {
+            public void run()
+            {
+                JdiThreadNode jtn = treeModel.findThreadNode(tr);
+                if (jtn != null) {
+                    treeModel.removeNodeFromParent(jtn);
+                }
+            }
+        });
+    }
+
+    /**
+     * Set or clear the option to hide system threads. This method also updates
+     * the current display if necessary.
+     */
+    public void hideSystemThreads(boolean hide)
+    {
+        if (hideSystemThreads == hide)
+            return;
+
+        hideSystemThreads = hide;
+        updateThreadDisplay();
+    }
+
+    /**
+     * Re-build the treeModel for the currently displayed threads using the
+     * allThreads set and the 'hideSystemThreads' flag.
+     */
+    private void updateThreadDisplay()
+    {
+        treeModel.setRoot(new JdiThreadNode());
+
+        for (Iterator<JdiThread> it = allThreads.iterator(); it.hasNext();) {
+            JdiThread currentThread = (JdiThread) it.next();
+            displayThread(currentThread);
+        }
+
+        treeModel.reload();
+    }
+
+    /**
+     * Add the given thread to the displayed threads if appropriate. System
+     * threads are displayed conditional on the 'hideSystemThreads' flag.
+     */
+    private void displayThread(JdiThread newThread)
+    {
+        if (!hideSystemThreads || !newThread.isKnownSystemThread()) {
+            JdiThreadNode root = treeModel.getThreadRoot();
+            treeModel.insertNodeInto(new JdiThreadNode(newThread), root, 0);
+        }
+    }
+
+    // -- support methods --
+
+    /**
+     * Get the VM, waiting for it to finish loading first (if necessary). In
+     * rare cases, when the project has been closed, this may return null.
+     * 
+     * @return the VM reference.
+     */
+    private VMReference getVM()
+    {
+        MachineLoaderThread mlt = machineLoader;
+        if (mlt == null) {
+            return null;
+        }
+        else {
+            return mlt.getVM();
+        }
+    }
+    
+    /**
+     * Get the VM if available, but don't wait for it (to finish loading).
+     * 
+     * @return  The VMReference or null if it's not available.
+     */
+    private VMReference getVMNoWait()
+    {
+        // Store a single value of machineLoader in a local variable to avoid
+        // synchronization issues.
+        MachineLoaderThread mlt = machineLoader;
+        if (mlt == null)
+            return null;
+        else
+            return mlt.getVMNoWait();
+    }
+
+    /**
+     * A thread which loads a new instance of the debugger.
+     */
+    class MachineLoaderThread extends Thread
+    {
+        MachineLoaderThread()
+        {}
+
+        public void run()
+        {
+            try {
+                VMReference newVM = new VMReference(JdiDebugger.this, terminal, startingDirectory, libraries);
+
+                BPClassLoader lastLoader;
+                synchronized(JdiDebugger.this) {
+                    if (! autoRestart) {
+                        newVM.close();
+                        JdiDebugger.this.notifyAll();
+                        return;
+                    }
+                    lastLoader = lastProjectClassLoader;
+                }
+                
+                // Do this outside of the synchronized blocks, mainly to avoid holding
+                // the monitor unnecessarily:
+                newVM.newClassLoader(lastLoader.getURLs());
+
+                synchronized(JdiDebugger.this) {
+                    vmRef = newVM;
+                }
+            }
+            catch (JdiVmCreationException e) {
+                raiseStateChangeEvent(Debugger.LAUNCH_FAILED);
+            }
+
+            // wake any internal getVM() calls that
+            // are waiting for us to finish
+            synchronized(JdiDebugger.this) {
+                JdiDebugger.this.notifyAll();
+            }
+        }
+
+        private VMReference getVM()
+        {
+            synchronized (JdiDebugger.this) {
+                // We can't just rely on synchronization, since it's possible that
+                // getVM() may creep in before run() begins execution. That's why
+                // we use notify()/wait().
+                while (vmRef == null && autoRestart) {
+                    try {
+                        JdiDebugger.this.wait();
+                    }
+                    catch (InterruptedException e) {}
+                }
+                    
+                return vmRef;
+            }
+        }
+        
+        /**
+         * Get the VM reference, without waiting for it to start. If no VM has started,
+         * this returns null.
+         */
+        private VMReference getVMNoWait()
+        {
+            synchronized (JdiDebugger.this) {
+                return vmRef;
+            }
+        }
+    }
+
+    /**
+     * Emit an event (to listeners) due to a thread being halted.
+     */
+    void emitThreadHaltEvent(JdiThread thread)
+    {
+        vmRef.emitThreadEvent(thread, true);
+    }
+    
+    /**
+     * Emit an event (to listeners) due to a thread being resumed.
+     */
+    void emitThreadResumedEvent(JdiThread thread)
+    {
+        vmRef.emitThreadEvent(thread, false);
+    }
+    
+    /**
+     * A thread has become halted; inform listeners.
+     */
+    void threadHalted(final JdiThread thread)
+    {
+        DebuggerEvent event = new DebuggerEvent(this, DebuggerEvent.THREAD_HALT_UNKNOWN, thread, null);
+        
+        boolean skipUpdate = false;
+        // Guaranteed to return a non-null array
+        DebuggerListener[] listeners = getListeners();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length - 1; i >= 0; i--) {
+            skipUpdate |= listeners[i].examineDebuggerEvent(event);
+        }
+        
+        if (! skipUpdate) {
+            treeModel.syncExec(new Runnable() {
+                public void run()
+                {
+                    JdiThreadNode threadNode = treeModel.findThreadNode(thread.getRemoteThread());
+                    if (threadNode != null) {
+                        treeModel.nodeChanged(threadNode);
+                    }
+                }
+            });
+        }
+        
+        fireTargetEvent(event, skipUpdate);
+    }
+    
+    /**
+     * A thread has been resumed; inform listeners.
+     */
+    void threadResumed(final JdiThread thread)
+    {
+        DebuggerEvent event = new DebuggerEvent(this, DebuggerEvent.THREAD_CONTINUE, thread, null);
+        
+        boolean skipUpdate = false;
+        // Guaranteed to return a non-null array
+        DebuggerListener [] listeners = getListeners();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length - 2; i >= 0; i -= 2) {
+            skipUpdate |= listeners[i].examineDebuggerEvent(event);
+        }
+
+        if (! skipUpdate) {
+            treeModel.syncExec(new Runnable() {
+                public void run()
+                {
+                    JdiThreadNode threadNode = treeModel.findThreadNode(thread.getRemoteThread());
+                    if (threadNode != null) {
+                        treeModel.nodeChanged(threadNode);
+                    }
+                }
+            });
+        }
+        
+        fireTargetEvent(event, skipUpdate);
+    }
+
+    /**
+     * The server thread has been resumed: updated its internal isSuspended status,
+     * but no need to fire listeners
+     * @param serverThread
+     */
+    public void serverThreadResumed(ThreadReference serverThread)
+    {
+        allThreads.find(serverThread).notifyResumed();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiField.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiField.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cdd79084141f04768959268ad6813896dfcaa40
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiField.java
@@ -0,0 +1,125 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.JavaType;
+
+import com.sun.jdi.Field;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.Value;
+
+/**
+ * An implement of DebuggerField using the Java Debug Interface (JDI).
+ * 
+ * @author Davin McCall
+ */
+public class JdiField extends DebuggerField
+{
+    private Field field;
+    private JdiObject object;
+    private boolean hidden;
+    
+    public JdiField(Field field, JdiObject object, boolean hidden)
+    {
+        this.field = field;
+        this.object = object;
+        this.hidden = hidden;
+    }
+
+    @Override
+    public String getName()
+    {
+        return field.name();
+    }
+
+    @Override
+    public JavaType getType()
+    {
+        if (object != null) {
+            return JdiReflective.fromField(field, object);
+        }
+        else {
+            return JdiReflective.fromField(field);
+        }
+    }
+
+    @Override
+    public int getModifiers()
+    {
+        return field.modifiers();
+    }
+
+    @Override
+    public String getValueString()
+    {
+        Value value;
+        if (object != null) {
+            value = object.obj.getValue(field);
+        }
+        else {
+            value = field.declaringType().getValue(field);
+        }
+
+        return JdiUtils.getJdiUtils().getValueString(value);
+    }
+
+    @Override
+    public DebuggerObject getValueObject(JavaType expectedType)
+    {
+        Value value;
+        if (object != null) {
+            value = object.obj.getValue(field);
+        }
+        else {
+            value = field.declaringType().getValue(field);
+        }
+        
+        if (value == null) {
+            return JdiObject.getDebuggerObject(null);
+        }
+        
+        if (value instanceof ObjectReference) {
+            ObjectReference or = (ObjectReference) value;
+            if (expectedType == null) {
+                expectedType = getType();
+            }
+            return JdiObject.getDebuggerObject(or, expectedType);
+        }
+        
+        return null;
+    }
+
+    @Override
+    public DebuggerClass getDeclaringClass()
+    {
+        return new JdiClass(field.declaringType());
+    }
+    
+    @Override
+    public boolean isHidden()
+    {
+        return hidden;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiObject.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..34dace3ad9ac17c4c9f2a0f3fc2907b8ee323caf
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiObject.java
@@ -0,0 +1,314 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+import com.sun.jdi.ArrayReference;
+import com.sun.jdi.Field;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+
+/**
+ * Represents an object running on the user (remote) machine, together with an optional generic
+ * type of the object.
+ *
+ * @author  Michael Kolling
+ */
+public class JdiObject extends DebuggerObject
+{
+    /**
+     *  Factory method that returns instances of JdiObjects.
+     *
+     *  @param  obj  the remote object this encapsulates (may be null)
+     *  @return      a new JdiObject or a new JdiArray object if
+     *               remote object is an array
+     */
+    public static JdiObject getDebuggerObject(ObjectReference obj)
+    {
+        if (obj instanceof ArrayReference) {
+            return new JdiArray((ArrayReference) obj);
+        }
+        else {
+            return new JdiObject(obj);
+        }
+    }
+    
+    public static JdiObject getDebuggerObject(ObjectReference obj, JavaType expectedType)
+    {
+        if( obj instanceof ArrayReference ) {
+            return new JdiArray((ArrayReference) obj, expectedType);
+        }
+        else {
+            if( expectedType instanceof GenTypeClass ) {
+                return new JdiObject(obj, (GenTypeClass)expectedType);
+            }
+            else {
+                return new JdiObject(obj);
+            }
+        }
+    }
+
+    /**
+     * Get a JdiObject from a field. 
+     * @param obj    Represents the value of the field.
+     * @param field  The field.
+     * @param parent The parent object containing the field.
+     * @return
+     */
+    public static JdiObject getDebuggerObject(ObjectReference obj, Field field, JdiObject parent)
+    {
+        JavaType expectedType = JdiReflective.fromField(field, parent);
+        if (obj instanceof ArrayReference) {
+            return new JdiArray((ArrayReference) obj, expectedType);
+        }
+        
+        if (expectedType.asClass() != null) {
+            return new JdiObject(obj, expectedType.asClass());
+        }
+        
+        return new JdiObject(obj);
+    }
+    
+    
+    // -- instance methods --
+
+    ObjectReference obj;  // the remote object represented
+    GenTypeClass genType = null; // the generic type, if known
+    List<Field> fields;
+    
+    // used by JdiArray.
+    protected JdiObject()
+    {
+    }
+
+    /**
+     *  Constructor is private so that instances need to use getJdiObject
+     *  factory method.
+     *
+     *  @param  obj  the remote debugger object (Jdi code) this encapsulates.
+     */
+    private JdiObject(ObjectReference obj)
+    {
+        this.obj = obj;
+        if (obj != null) {
+            obj.disableCollection();
+            getRemoteFields();
+        }
+    }
+
+    private JdiObject(ObjectReference obj, GenTypeClass expectedType)
+    {
+        this.obj = obj;
+        if (obj != null) {
+            obj.disableCollection();
+            getRemoteFields();
+            Reflective reflective = new JdiReflective(obj.referenceType());
+            if( expectedType.isGeneric() ) {
+                genType = expectedType.mapToDerived(reflective);
+            }
+        }
+    }
+    
+    @Override
+    protected void finalize()
+    {
+        if (obj != null) {
+            obj.enableCollection();
+        }
+    }
+    
+    @Override
+    public String toString()
+    {
+        return JdiUtils.getJdiUtils().getValueString(obj);
+    }
+    
+    /*
+     * Get the (raw) name of the class of this object.
+     */
+    @Override
+    public String getClassName()
+    {
+        if (obj == null) {
+            return "";
+        }
+        else {
+            return obj.referenceType().name();
+        }
+    }
+
+    /*
+     * Get the class of this object.
+     */
+    @Override
+    public DebuggerClass getClassRef()
+    {
+        if (obj == null) {
+            return null;
+        }
+        else {
+            return new JdiClass(obj.referenceType());
+        }
+    }
+    
+    @Override
+    public GenTypeClass getGenType()
+    {
+        if(genType != null) {
+            return genType;
+        }
+        else if (obj != null) {
+            Reflective r = new JdiReflective(obj.referenceType());
+            return new GenTypeClass(r);
+        }
+        else {
+            return null;
+        }
+    }
+    
+    /**
+     *  Return true if this object is an array. This is always false, since
+     *  arrays are wropped in the subclass "JdiArray".
+     *
+     *@return    The Array value
+     */
+    @Override
+    public boolean isArray()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isNullObject()
+    {
+        return obj == null;
+    }
+
+    /**
+     *  Return the number of object fields.
+     *
+     *@return    The InstanceFieldCount value
+     */
+    @Override
+    public int getElementCount()
+    {
+        return -1;
+    }
+    
+    @Override
+    public JavaType getElementType()
+    {
+        return null;
+    }
+
+    @Override
+    public DebuggerObject getElementObject(int index)
+    {
+        return null;
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return null;
+    }
+    
+    @Override
+    public ObjectReference getObjectReference()
+    {
+        return obj;
+    }
+    
+    @Override
+    public List<DebuggerField> getFields()
+    {
+        List<Field> visibleFields = obj.referenceType().visibleFields();
+        List<DebuggerField> rlist = new ArrayList<DebuggerField>(fields.size());
+        for (Field field : fields) {
+            if (! checkIgnoreField(field)) {
+                boolean visible = visibleFields.remove(field);
+                rlist.add(new JdiField(field, this, !visible));
+            }
+        }
+        return rlist;
+    }
+
+    private boolean checkIgnoreField(Field f)
+    {
+        return (f.name().indexOf('$') >= 0);
+    }
+
+    /**
+     *  Get the list of fields for this object.
+     */
+    protected void getRemoteFields()
+    {
+        if (obj != null) {
+            ReferenceType cls = obj.referenceType();
+            if (cls != null) {
+                fields = cls.allFields();
+                return;
+            }
+        }
+        // either null object or unavailable fields
+        // lets give them an empty list of fields
+        fields = new ArrayList<Field>();
+    }
+
+    /**
+     * Base our object equality on the object that we are referring
+     * to in the remote VM.
+     */
+    @Override
+    public boolean equals(Object o)
+    {
+        if(this == o) {
+            return true;
+        }
+        if((o == null) || (o.getClass() != this.getClass())) {
+            return false;
+        }
+
+        // object must be JdiObject at this point
+        JdiObject test = (JdiObject)o;
+        return this.obj.equals(test.obj);
+    }
+
+    /**
+     * Base our hashcode on the hashcode of the object that we are
+     * referring to in the remote VM.
+     */
+    @Override
+    public int hashCode()
+    {
+        return obj.hashCode();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiReflective.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiReflective.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd9e76a0cb778c5e0600bf215e80d0fd0e8d9a0d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiReflective.java
@@ -0,0 +1,1052 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.util.*;
+
+import bluej.debugger.gentype.*;
+import bluej.utility.Debug;
+
+import com.sun.jdi.*;
+
+/**
+ * A Reflective for Jdi classes.
+ * 
+ * @see Reflective.
+ * 
+ * @author Davin McCall
+ */
+public class JdiReflective extends Reflective
+{
+    // For a loaded type, we have a ReferenceType.
+    private ReferenceType rclass = null;
+
+    // If the type has not been loaded, we know only it's name, and the
+    // type from which we discovered the reference to it:
+    protected String name = null;
+    private ClassLoaderReference sourceLoader = null;
+    private VirtualMachine sourceVM = null;
+
+    /**
+     * Constructor - loaded type
+     */
+    public JdiReflective(ReferenceType rclass)
+    {
+        super();
+        this.rclass = rclass;
+        if (rclass == null) {
+            Debug.message("JdiReflective: null ReferenceType?");
+            throw new NullPointerException();
+        }
+    }
+
+    /**
+     * Constructor - type not loaded yet; source (parent) object available.
+     * 
+     * @param name
+     *            The fully qualified type name
+     * @param sourceType
+     *            The type from which a reference to this type was obtained
+     */
+    public JdiReflective(String name, ReferenceType sourceType)
+    {
+        this.name = name;
+        this.sourceLoader = sourceType.classLoader();
+        this.sourceVM = sourceType.virtualMachine();
+    }
+
+    /**
+     * Constructor - type may not yet be loaded; class loader available.
+     * 
+     * @param name
+     *            The fully qualified type name
+     * @param classLoader
+     *            The class loader used to load this type
+     * @param vm
+     *            The virtual machine reference
+     */
+    public JdiReflective(String name, ClassLoaderReference classLoader, VirtualMachine vm)
+    {
+        this.name = name;
+        this.sourceLoader = classLoader;
+        this.sourceVM = vm;
+    }
+    
+    /**
+     * Get the JDI ReferenceType this reflective represents.
+     */
+    public ReferenceType getJdiType()
+    {
+        checkLoaded();
+        return rclass;
+    }
+    
+    @Override
+    public Reflective getRelativeClass(String name)
+    {
+        if (rclass != null) {
+            return new JdiReflective(name, rclass);
+        }
+        else {
+            return new JdiReflective(name, sourceLoader, sourceVM);
+        }
+    }
+
+    /**
+     * Try to make sure we have a valid reference to the actual type
+     */
+    protected void checkLoaded()
+    {
+        if (rclass == null) {
+            rclass = findClass(name, sourceLoader, sourceVM);
+            if (rclass == null) {
+                Debug.message("Attempt to use unloaded type: " + name);
+                Debug.message("  name = " +  name + ", sourceLoader = " + sourceLoader);
+                Debug.message("  (in JdiReflective.checkLoaded()");
+                return;
+            }
+            name = null;
+            sourceLoader = null;
+            sourceVM = null;
+        }
+    }
+
+    public String getName()
+    {
+        if (name != null) {
+            return name;
+        }
+        
+        if (rclass.signature().startsWith("[")) {
+            return rclass.signature().replace('/', '.');
+        }
+        else {
+            return rclass.name();
+        }
+    }
+    
+    @Override
+    public boolean isInterface()
+    {
+        checkLoaded();
+        return rclass instanceof InterfaceType;
+    }
+    
+    @Override
+    public boolean isStatic()
+    {
+        checkLoaded();
+        return rclass.isStatic();
+    }
+    
+    @Override
+    public boolean isPublic()
+    {
+        checkLoaded();
+        return rclass.isPublic();
+    }
+
+    public Reflective getArrayOf()
+    {
+        if (rclass != null) {
+            return new JdiArrayReflective(new GenTypeClass(this), rclass);
+        }
+        else {
+            return new JdiArrayReflective(new GenTypeClass(this), sourceLoader, sourceVM);
+        }
+    }
+    
+    public List<GenTypeDeclTpar> getTypeParams()
+    {
+        // Make sure we are loaded and a generic signature is present.
+        checkLoaded();
+        String gensig = JdiUtils.getJdiUtils().genericSignature(rclass);
+        if (gensig == null)
+            return Collections.emptyList();
+        
+        // Read the type parameters from the generic signature.
+        StringIterator s = new StringIterator(gensig);
+        return getTypeParams(s);
+    }
+
+    /**
+     * Get the type parameters of this class, as a list of GenTypeDeclTpar,
+     * using a pre-existing string iterator to process the generic signature.
+     *  
+     * @param s  A string iterator, currently at the beginning of the generic
+     *           signature for this class. On return, the iterator will be
+     *           positioned after the type parameters in the signature, at the
+     *           beginning of the class name.
+     * 
+     * @return  A list of GenTypeDeclTpar, representing the type parameters of
+     *          this class.
+     */
+    private List<GenTypeDeclTpar> getTypeParams(StringIterator s)
+    {
+        List<GenTypeDeclTpar> rlist = new ArrayList<GenTypeDeclTpar>();
+
+        char c = s.peek();
+        if (c != '<')
+            return rlist;
+
+        // go through each type parameter, assign it the type from our
+        // params list.
+        s.next();
+        while (c != '>') {
+            String paramName = readClassName(s);
+            if (s.current() != ':') {
+                Debug.message("getTypeParams : no ':' following type parameter name in super signature?? got "
+                        + s.current());
+                Debug.message("signature was: " + s.getString());
+                return Collections.emptyList();
+            }
+            // '::' indicates lower bound is an interface. Ignore.
+            if (s.peek() == ':')
+                s.next();
+
+            // multiple bounds appear as T:bound1;:bound2; ... etc
+            ArrayList<GenTypeSolid> bounds = new ArrayList<GenTypeSolid>(3);
+            while (s.current() == ':') {
+                bounds.add((GenTypeSolid) typeFromSignature(s, null, rclass));
+                
+                //we don't want the next char to be eaten...
+                if (s.peek() == ':')
+                    s.next();
+            }
+            rlist.add(new GenTypeDeclTpar(paramName, bounds.toArray(new GenTypeSolid [0])));
+            c = s.peek();
+        }
+        s.next();
+        return rlist;
+    }
+    
+    public List<Reflective> getSuperTypesR()
+    {
+        checkLoaded();
+        if (rclass instanceof ClassType) {
+            List<Reflective> l = new LinkedList<Reflective>();
+            Iterator<InterfaceType> i = ((ClassType) rclass).interfaces().iterator();
+            while (i.hasNext())
+                l.add(new JdiReflective(i.next()));
+            if (((ClassType) rclass).superclass() != null)
+                l.add(new JdiReflective(((ClassType) rclass).superclass()));
+            return l;
+        }
+        else if (rclass instanceof InterfaceType) {
+            // interface
+            List<Reflective> l = new LinkedList<Reflective>();
+            Iterator<InterfaceType> i = ((InterfaceType) rclass).superinterfaces().iterator();
+            while (i.hasNext())
+                l.add(new JdiReflective((ReferenceType) i.next()));
+            
+            // interfaces with no direct superinterfaces have a supertype of Object
+            if (l.isEmpty()) {
+                l.add(new JdiReflective("java.lang.Object", this.rclass));
+            }
+            
+            return l;
+        }
+        else
+            return new LinkedList<Reflective>();
+    }
+
+    public List<GenTypeClass> getSuperTypes()
+    {
+        checkLoaded();
+        List<GenTypeClass> rlist = new ArrayList<GenTypeClass>();
+
+        if (JdiUtils.getJdiUtils().genericSignature(rclass) == null) {
+            if (rclass instanceof ClassType) {
+                ClassType ctClass = (ClassType) rclass;
+
+                // superclass
+                ClassType superclass = ctClass.superclass();
+                if (superclass != null) {
+                    Reflective r = new JdiReflective(ctClass.superclass());
+                    rlist.add(new GenTypeClass(r));
+                }
+
+                // interfaces
+                List<InterfaceType> interfaces = ctClass.interfaces();
+                for (Iterator<InterfaceType> i = interfaces.iterator(); i.hasNext();) {
+                    Reflective r = new JdiReflective(i.next());
+                    rlist.add(new GenTypeClass(r));
+                }
+                return rlist;
+            }
+            else {
+                // rclass must be an InterfaceType
+                InterfaceType itClass = (InterfaceType) rclass;
+
+                List<InterfaceType> interfaces = itClass.superinterfaces();
+                for (Iterator<InterfaceType> i = interfaces.iterator(); i.hasNext();) {
+                    Reflective r = new JdiReflective(i.next());
+                    rlist.add(new GenTypeClass(r));
+                }
+                
+                // interfaces with no direct superinterfaces have a supertype of Object
+                if (rlist.isEmpty()) {
+                    rlist.add(new GenTypeClass(new JdiReflective("java.lang.Object", this.rclass)));
+                }
+
+                return rlist;
+            }
+        }
+
+        // A generic signature for a type looks something like:
+        //    <..type params..>Lbase/class<...>;...interfaces...
+        // First, skip over the type params in the supertype:
+
+        StringIterator s = new StringIterator(JdiUtils.getJdiUtils().genericSignature(rclass));
+        List<GenTypeDeclTpar> l = getTypeParams(s);
+        Map<String,GenTypeDeclTpar> declTpars = new HashMap<String,GenTypeDeclTpar>();
+        for (Iterator<GenTypeDeclTpar> i = l.iterator(); i.hasNext(); ) {
+            GenTypeDeclTpar declTpar = (GenTypeDeclTpar) i.next();
+            declTpars.put(declTpar.getTparName(), declTpar); 
+        }
+        
+        // go through each base type in turn.
+        while (s.hasNext()) {
+            // We now have a base.
+            GenTypeClass t = typeFromSignature(s, declTpars, rclass).asClass();
+            rlist.add(t);
+        }
+        return rlist;
+    }
+    
+    public boolean isAssignableFrom(Reflective r)
+    {
+        if (this.equals(r))
+            return true;
+        
+        // Any reference type, including arrays, can be assigned to Object
+        if (getName().equals("java.lang.Object"))
+            return true;
+        
+        if (r instanceof JdiReflective) {
+            JdiReflective jr = (JdiReflective) r;
+            
+            jr.checkLoaded();
+            return checkAssignability(rclass, jr.rclass);
+        }
+        else
+            return false;
+    }
+    
+    /**
+     * Check that type b is assingable to a variable of type a.
+     */
+    private static boolean checkAssignability(ReferenceType a, ReferenceType b)
+    {
+        while (true)
+        {
+            if (a instanceof ClassType) {
+                if (b instanceof InterfaceType) {
+                    List<InterfaceType> l = ((ClassType)a).allInterfaces();
+                    return l.contains(b);
+                }
+                else if (b instanceof ClassType) {
+                    ClassType classType = (ClassType) a;
+                    
+                    while (classType != null) {
+                        if (b.equals(classType))
+                            return true;
+                        classType = classType.superclass();
+                    }
+                }
+                return false;
+            }
+            else if (a instanceof InterfaceType) {
+                if (! (b instanceof InterfaceType))
+                    return false;
+                
+                List<InterfaceType> l = new LinkedList<InterfaceType>(); 
+                l.addAll(((InterfaceType) a).superinterfaces());
+                while (! l.isEmpty()) {
+                    // get the first superinterface in the list
+                    InterfaceType it = (InterfaceType) l.get(0);
+                    if (a.equals(it))
+                        return true;
+                    
+                    l.addAll(it.superinterfaces());
+                    l.remove(0);
+                }
+                return false;
+            }
+            else if (a instanceof ArrayType) {
+                if (! (b instanceof ArrayType))
+                    return false;
+                
+                try {
+                    Type an = ((ArrayType) a).componentType();
+                    Type bn = ((ArrayType) b).componentType();
+                
+                    if (an instanceof ReferenceType && bn instanceof ReferenceType) {
+                        a = (ReferenceType) an;
+                        b = (ReferenceType) bn;
+                    }
+                    else
+                        return false;
+                }
+                catch (ClassNotLoadedException cnle) {
+                    return false;
+                }
+            }
+            else
+                // unknown type
+                return false;
+        }
+    }
+
+    /**
+     * Find a class by name, using the given class loader.
+     * 
+     * @param name
+     *            The name of the class to find
+     * @param lclass
+     *            The loading class. The class loader of this class is used to
+     *            locate the desired class.
+     * @return A ClassType object representing the found class (or null)
+     */
+    private static ReferenceType findClass(String name, ClassLoaderReference cl, VirtualMachine vm)
+    {
+        if (cl != null) {
+            // See if the desired class was initiated by our class loader.
+            Iterator<ReferenceType> i = cl.visibleClasses().iterator();
+            while (i.hasNext()) {
+                ReferenceType ct = (ReferenceType) i.next();
+                if (ct.name().equals(name))
+                    return ct;
+            }
+        }
+        else {
+            // A null classloader means the bootstrap class loader was used.
+            // So look for the class with the correct name which was loaded
+            // by the bootstrap loader.
+            Iterator<ReferenceType> i = vm.classesByName(name).iterator();
+            while (i.hasNext()) {
+                ReferenceType ct = (ReferenceType) i.next();
+                if (ct.classLoader() == null)
+                    return ct;
+            }
+        }
+        
+        // Try and load the class.
+        VMReference vmr = VMReference.getVmForMachine(vm);
+        if (vmr != null) {
+           return vmr.loadClass(name, cl);
+        }
+        
+        return null;
+    }
+
+    /**
+     * Read a class name or type parameter name from a signature string.
+     * 
+     * @param i
+     *            An iterator into the string
+     * @return the fully qualified class name
+     */
+    private static String readClassName(StringIterator i)
+    {
+        char c = i.next();
+        String r = new String();
+        while (c != '<' && c != ';' && c != ':') {
+            r += (c == '/') ? '.' : c;
+            c = i.next();
+        }
+        return r;
+    }
+
+    /**
+     * Generate a GenType structure from a type specification found in a
+     * signature string, optionally mapping type parameter names to their actual
+     * types.
+     * 
+     * @param i
+     *            a StringIterator through the signature string
+     * @param tparams
+     *            a mapping of type parameter names to types (or null)
+     * @param parent
+     *            the type in which the signature string is embedded. The class
+     *            loader of this type is used to locate embedded types.
+     * @return The GenType structure determined from the signature.
+     */
+    private static GenTypeParameter fromSignature(StringIterator i,
+            Map<String,? extends GenTypeParameter> tparams, ReferenceType parent)
+    {
+        char c = i.peek();
+        if (c == '*') {
+            // '*' represents an unbounded '?'. For instance, List<?>
+            // has signature: Ljava/lang/list<*>;
+            i.next();
+            JdiReflective objRef = new JdiReflective("java.lang.Object", parent);
+            GenTypeClass objClass = new GenTypeClass(objRef);
+            return new GenTypeUnbounded(objClass);
+        }
+        if (c == '+') {
+            // ? extends ...
+            // The bound must be a solid, but it's possible that tparams map
+            // a type parameter (solid) to a wildcard (non-solid).
+            i.next();
+            GenTypeSolid t = (GenTypeSolid) typeFromSignature(i, null, parent);
+            if (tparams != null) {
+                return new GenTypeExtends(t).mapTparsToTypes(tparams);
+            }
+            else {
+                return new GenTypeExtends(t);
+            }
+        }
+        if (c == '-') {
+            // ? super ...
+            // Likewise as for extends.
+            i.next();
+            GenTypeSolid t = (GenTypeSolid) fromSignature(i, null, parent);
+            if (tparams != null) {
+                return new GenTypeSuper(t).mapTparsToTypes(tparams);
+            }
+            else {
+                return new GenTypeSuper(t);
+            }
+        }
+        
+        return typeFromSignature(i, tparams, parent);
+    }
+    
+    /**
+     * Derive a type from a type signature.
+     * @param i   An iterator through the signature
+     * @param tparams  The type parameters of the parent type (the type from where this signature comes);
+     *                 may be null.
+     * @param parent   The parent type
+     */
+    public static JavaType typeFromSignature(StringIterator i,
+            Map<String,? extends GenTypeParameter> tparams, ReferenceType parent)
+    {
+        char c = i.next();
+        if (c == '[') {
+            // array
+            JavaType t = typeFromSignature(i, tparams, parent);
+            return t.getArray();
+        }
+        if (c == 'T') {
+            // type parameter
+            String tname = readClassName(i);
+            if (tparams != null && tparams.get(tname) != null) {
+                return tparams.get(tname).getCapture();
+            }
+            else {
+                return new GenTypeTpar(tname);
+            }
+        }
+        if (c == 'I') {
+            // integer
+            return JavaPrimitiveType.getInt();
+        }
+        if (c == 'C') {
+            // character
+            return JavaPrimitiveType.getChar();
+        }
+        if (c == 'Z') {
+            // boolean
+            return JavaPrimitiveType.getBoolean();
+        }
+        if (c == 'B') {
+            // byte
+            return JavaPrimitiveType.getByte();
+        }
+        if (c == 'S') {
+            // short
+            return JavaPrimitiveType.getShort();
+        }
+        if (c == 'J') {
+            // long
+            return JavaPrimitiveType.getLong();
+        }
+        if (c == 'F') {
+            // float
+            return JavaPrimitiveType.getFloat();
+        }
+        if (c == 'D') {
+            // double
+            return JavaPrimitiveType.getDouble();
+        }
+        if (c == 'V') {
+            return JavaPrimitiveType.getVoid();
+        }
+
+        if (c != 'L') {
+            Debug.message("Generic signature begins without 'L'?? (got " + c + ")");
+        }
+
+        String basename = readClassName(i);
+        Reflective reflective = new JdiReflective(basename, parent);
+        c = i.current();
+        if (c == ';')
+            return new GenTypeClass(reflective, (List<GenTypeParameter>) null);
+
+        if (c != '<') {
+            Debug.message("Generic signature: expected '<', got '" + c + "' ??");
+            return null;
+        }
+
+        List<GenTypeParameter> params = new ArrayList<GenTypeParameter>();
+        do {
+            GenTypeParameter ptype = fromSignature(i, tparams, parent);
+            if (ptype == null) {
+                return null;
+            }
+            params.add(ptype);
+        } while (i.peek() != '>');
+        i.next(); // fetch the '>'
+        c = i.next(); // fetch the trailing ';' or '.'
+        
+        GenTypeClass result = new GenTypeClass(reflective, params);
+
+        // if c is now '.', we have an inner class
+        if (c == '.') {
+            return innerFromSignature(i, basename, result, tparams, parent);
+        }
+        
+        // otherwise assume we have ';'
+        return result;
+    }
+
+    
+    private static GenTypeClass innerFromSignature(StringIterator i, String outerName, GenTypeClass outer,
+            Map<String,? extends GenTypeParameter> tparams, ReferenceType parent)
+    {
+        String basename = readClassName(i);
+        String innerName = outerName + '$' + basename;
+        Reflective reflective = new JdiReflective(innerName, parent);
+            
+        char c = i.current();
+        if (c == ';')
+            return new GenTypeClass(reflective, (List<GenTypeParameter>) null, outer);
+        
+        if (c == '<') {
+            List<GenTypeParameter> params = new ArrayList<GenTypeParameter>();
+            do {
+                GenTypeParameter ptype = fromSignature(i, tparams, parent);
+                if (ptype == null) {
+                    return null;
+                }
+                params.add(ptype);
+            } while (i.peek() != '>');
+            i.next(); // fetch the '>'
+            c = i.next(); // fetch the trailing ';' or '.'
+            
+            GenTypeClass result = new GenTypeClass(reflective, params, outer);
+            
+            // if c is now '.', we have an inner class
+            if (c == '.')
+                return innerFromSignature(i, innerName, result, tparams, parent);
+
+            return result;
+        }
+        else {
+            Debug.message("Generic signature: expected '<', got '" + c + "' ??");
+            return null;
+        }
+    }
+
+    private static JavaType getNonGenericType(String typeName, Type t, ClassLoaderReference clr, VirtualMachine vm)
+    {
+        if (t instanceof BooleanType)
+            return JavaPrimitiveType.getBoolean();
+        else if (t instanceof ByteType)
+            return JavaPrimitiveType.getByte();
+        else if (t instanceof CharType)
+            return JavaPrimitiveType.getChar();
+        else if (t instanceof DoubleType)
+            return JavaPrimitiveType.getDouble();
+        else if (t instanceof FloatType)
+            return JavaPrimitiveType.getFloat();
+        else if (t instanceof IntegerType)
+            return JavaPrimitiveType.getInt();
+        else if (t instanceof LongType)
+            return JavaPrimitiveType.getLong();
+        else if (t instanceof ShortType)
+            return JavaPrimitiveType.getShort();
+        else {
+            // Sometimes, we get a class which doesn't really exist
+            // eg. as a type argument to a field.
+            if (t == null) {
+                return new TextType(typeName);
+            }
+            
+            // The class may or may not be loaded.
+            String tname = t.signature();
+            if (tname.startsWith("[")) {
+                JavaType arrayType = typeFromSignature(new StringIterator(tname), null, (ReferenceType) t);
+                return arrayType;
+            }
+            else {
+                tname = t.name();
+            }
+            Reflective ref = new JdiReflective(tname, clr, vm);
+            return new GenTypeClass(ref, (List<GenTypeParameter>) null);
+        }
+    }
+
+    /**
+     * Convert a type name (as returned from JdiField.typeName() and so on) to a binary name
+     * that can be passed to a classloader.
+     */
+    private static String typeNameToBinaryName(String typeName)
+    {
+        int arrIndex = typeName.indexOf('[');
+        if (arrIndex == -1) {
+            return typeName;
+        }
+        
+        String binName = "L" + typeName.substring(0, arrIndex) + ";";
+        do {
+            binName = "[" + binName;
+            arrIndex = typeName.indexOf('[', arrIndex + 1);
+        } while (arrIndex != -1);
+        
+        return binName;
+    }
+    
+    /**
+     * Determine the complete declared type of an instance field.
+     * 
+     * @param f
+     *            The field
+     * @param parent
+     *            The object in which the field is located
+     * @return The type of the field value
+     */
+    public static JavaType fromField(Field f, JdiObject parent)
+    {
+        Type t = null;
+
+        // For a field whose value is unset/null, the corresponding class
+        // type may not have been loaded. In this case "f.type()" throws a
+        // ClassNotLoadedException.
+
+        try {
+            t = f.type();
+        }
+        catch (ClassNotLoadedException cnle) {
+            t = findClass(typeNameToBinaryName(f.typeName()), f.declaringType().classLoader(), f.virtualMachine());
+        }
+
+        final String gensig = JdiUtils.getJdiUtils().genericSignature(f);
+
+        // check for primitive type, or raw type
+        //if (gensig == null && (rt == null || rt.genericSignature() != null))
+        if (gensig == null) {
+            return getNonGenericType(f.typeName(), t, parent.obj.referenceType().classLoader(), parent.obj
+                    .virtualMachine());
+        }
+        
+        // generic version.
+        GenTypeClass genType = parent.getGenType();
+        
+        // Map from containing object type to the type in which the field was
+        // declared. Then extract the type parameter mappings.
+        Map<String,GenTypeParameter> tparams = genType.mapToSuper(f.declaringType().name()).getMap();
+        if (tparams == null) {
+            // raw parent
+            Reflective r = new JdiReflective(f.typeName(), parent.obj.referenceType());
+            return new GenTypeClass(r);
+        }
+        
+        StringIterator iterator = new StringIterator(gensig);
+
+        // Parse the signature, using the determined tpar mappings.
+        return typeFromSignature(iterator, tparams, parent.obj.referenceType());
+    }
+
+    /**
+     * Determine the complete type of a class field.
+     * 
+     * @param f
+     *            The field
+     * @param parent
+     *            The object in which the field is located
+     * @return The type of the field value
+     */
+    public static JavaType fromField(Field f)
+    {
+        Type t = null;
+        ReferenceType parent = f.declaringType();
+
+        // For a field whose value is unset/null, the corresponding class
+        // type may not have been loaded. In this case "f.type()" throws a
+        // ClassNotLoadedException.
+
+        try {
+            t = f.type();
+        }
+        catch (ClassNotLoadedException cnle) {
+            t = findClass(typeNameToBinaryName(f.typeName()), f.declaringType().classLoader(), f.virtualMachine());
+        }
+
+        final String gensig = JdiUtils.getJdiUtils().genericSignature(f);
+
+        if (gensig == null) {
+            return getNonGenericType(f.typeName(), t, parent.classLoader(), parent.virtualMachine());
+        }
+
+        // if the generic signature wasn't null, get the type from it.
+        StringIterator iterator = new StringIterator(gensig);
+        return typeFromSignature(iterator, null, parent);
+    }
+
+    /**
+     * Determine the complete type of a local variable,
+     * 
+     * @param t
+     *            The type as returned by getType() on the variable, or null if that threw
+     *            a ClassNotLoadedException
+     * @param genericSignature
+     *            The generic signature of the variable
+     * @param typeName
+     *            The name of the variable type
+     * @param declaringType
+     *            The declaring type of the variable
+     * @return The type of the field value
+     */
+    public static JavaType fromLocalVar(Type t, String genericSignature, String typeName, ReferenceType declaringType)
+    {
+        if (t == null) {
+            t = findClass(typeNameToBinaryName(typeName), declaringType.classLoader(), declaringType.virtualMachine());
+        }
+        
+        if (genericSignature == null) {
+            return getNonGenericType(typeName, t, declaringType.classLoader(), declaringType.virtualMachine());
+        }
+
+        // if the generic signature wasn't null, get the type from it.
+        StringIterator iterator = new StringIterator(genericSignature);
+        Map<String,GenTypeParameter> tparams = new HashMap<String,GenTypeParameter>();
+        addDefaultParamBases(tparams, new JdiReflective(declaringType));
+        return typeFromSignature(iterator, tparams, declaringType);
+    }
+    
+    /**
+     * Determine the complete type of a local variable,
+     * 
+     * @param sf
+     *            The stack frame containing the variable
+     * @param var
+     *            The local variable
+     * @return The type of the field value
+     */
+    public static JavaType fromLocalVar(StackFrame sf, LocalVariable var)
+    {
+        Type t = null;
+        
+        // For a variable whose value is unset/null, the corresponding class
+        // type may not have been loaded. In this case "var.type()" throws a
+        // ClassNotLoadedException.
+
+        Location l = sf.location();
+        ReferenceType declType = l.declaringType();
+
+        try {
+            t = var.type();
+        }
+        catch (ClassNotLoadedException cnle) {
+            t = findClass(typeNameToBinaryName(var.typeName()), declType.classLoader(), sf.virtualMachine());
+        }
+
+        final String gensig = JdiUtils.getJdiUtils().genericSignature(var);
+
+        if (gensig == null) {
+            return getNonGenericType(var.typeName(), t, declType.classLoader(), sf.virtualMachine());
+        }
+
+        // if the generic signature wasn't null, get the type from it.
+        StringIterator iterator = new StringIterator(gensig);
+        Map<String,GenTypeParameter> tparams = new HashMap<String,GenTypeParameter>();
+        addDefaultParamBases(tparams, new JdiReflective(declType));
+        return typeFromSignature(iterator, tparams, declType);
+    }
+
+    /**
+     * For all type parameters which don't already occur in the given Map,
+     * add them in as the "default" given by the class definition. For instance
+     * with List&lt;T&gt;, add in the mapping "T : ? extends Object".
+     * @param tparams       The map (String -> GenTypeClass)
+     * @param declaringType the type for which to add default mappings
+     */
+    private static void addDefaultParamBases(Map<String,GenTypeParameter> tparams,
+            JdiReflective declaringType)
+    {
+        while (declaringType != null) {
+            Iterator<GenTypeDeclTpar> i = declaringType.getTypeParams().iterator();
+            
+            while( i.hasNext() ) {
+                GenTypeDeclTpar tpar = i.next();
+                
+                String paramName = tpar.getTparName();
+                
+                GenTypeSolid [] ubounds = tpar.upperBounds();
+                GenTypeWildcard type = new GenTypeWildcard(ubounds, new GenTypeSolid[0]);
+                if( ! tparams.containsKey(paramName)) {
+                    tparams.put(paramName, type);
+                }
+            }
+            declaringType = declaringType.getOuterType();
+        }
+    }
+    
+    /**
+     * Get the reflective representing the outer class of this reflective,
+     * or null if none.
+     */
+    private JdiReflective getOuterType()
+    {
+        checkLoaded();
+        String myName = getName();
+        int x = myName.indexOf('$');
+        if (x != -1 && ! rclass.isStatic()) {
+            String outerName = myName.substring(0, x);
+            return (JdiReflective) getRelativeClass(outerName);
+        }
+        else
+            return null;
+    }
+    
+    @Override
+    public Map<String,FieldReflective> getDeclaredFields()
+    {
+        checkLoaded();
+        List<Field> fields = rclass.fields();
+        Map<String,FieldReflective> rfields = new HashMap<String,FieldReflective>();
+        
+        for (Field field : fields) {
+            String genSig = field.genericSignature();
+            if (genSig == null) {
+                genSig = field.signature();
+            }
+            
+            StringIterator i = new StringIterator(genSig);
+            JavaType ftype = typeFromSignature(i, null, rclass);
+            FieldReflective fref = new FieldReflective(field.name(),
+                    ftype, field.modifiers());
+            rfields.put(field.name(), fref);
+        }
+        
+        return rfields;
+    }
+    
+    @Override
+    public Map<String,Set<MethodReflective>> getDeclaredMethods()
+    {
+        checkLoaded();
+        List<Method> methods = rclass.methods();
+        Map<String,Set<MethodReflective>> methodMap = new HashMap<String,Set<MethodReflective>>();
+        
+        for (Method method : methods) {
+            if (method.isSynthetic()) {
+                continue;
+            }
+            
+            // Process the string signature to determine return and param types
+            String genSig = method.genericSignature();
+            if (genSig == null) {
+                genSig = method.signature();
+            }
+            
+            StringIterator i = new StringIterator(genSig);
+            List<GenTypeDeclTpar> tparTypes = getTypeParams(i);
+
+            char c = i.next();
+            if (c != '(') {
+                continue;
+            }
+            
+            List<JavaType> paramTypes = new ArrayList<JavaType>();
+            while (i.peek() != ')') {
+                paramTypes.add(typeFromSignature(i, null, rclass));
+            }
+            
+            i.next(); // skip ')'
+            JavaType returnType = typeFromSignature(i, null, rclass);
+            
+            boolean isVarArgs = method.isVarArgs();
+            int modifiers = method.modifiers();
+            
+            MethodReflective mr = new MethodReflective(method.name(), returnType, tparTypes,
+                    paramTypes, this, isVarArgs, modifiers);
+            
+            Set<MethodReflective> mset = methodMap.get(mr.getName());
+            if (mset == null) {
+                mset = new HashSet<MethodReflective>();
+                methodMap.put(mr.getName(), mset);
+            }
+            
+            mset.add(mr);
+        }
+        
+        return methodMap;
+    }
+    
+    @Override
+    public List<Reflective> getInners()
+    {
+        return Collections.emptyList(); // not implemented
+    }
+    
+    static class StringIterator
+    {
+        int i = 0;
+        String s;
+
+        public StringIterator(String s)
+        {
+            this.s = s;
+            if (s == null)
+                Debug.message("StringIterator with null string??");
+        }
+
+        public char current()
+        {
+            return s.charAt(i - 1);
+        }
+
+        public char next()
+        {
+            return s.charAt(i++);
+        }
+
+        public char peek()
+        {
+            return s.charAt(i);
+        }
+
+        public boolean hasNext()
+        {
+            return i < s.length();
+        }
+        
+        public String getString()
+        {
+            return s;
+        }
+    };
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiTestResult.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiTestResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..31ddc82dfa6fdf10cbda254295cc1e0f92433944
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiTestResult.java
@@ -0,0 +1,165 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.io.*;
+
+import bluej.debugger.DebuggerTestResult;
+import bluej.debugger.SourceLocation;
+
+/**
+ * Represents the result of running a single test method.
+ */
+public class JdiTestResult extends DebuggerTestResult
+{
+    protected String className;
+    protected String methodName;
+    protected String exceptionMsg, traceMsg;  // null if no failure
+    protected int runTimeMs;
+
+    JdiTestResult(String className, String methodName, int runTimeMs)
+    {
+        if (className == null || methodName == null)
+            throw new NullPointerException("constructing JdiTestResult");
+
+        this.className = className;
+        this.methodName = methodName;
+        this.runTimeMs = runTimeMs;
+
+        this.exceptionMsg = null;
+        this.traceMsg = null;
+    }
+    
+    public String getQualifiedClassName()
+    {
+        return className;
+    }
+    
+    public String getMethodName()
+    {
+        return methodName;
+    }
+
+    /**
+     * @see bluej.debugger.DebuggerTestResult#getExceptionMessage()
+     */
+    public String getExceptionMessage()
+    {
+        throw new IllegalStateException("getting Exception message from successful test");
+    }
+
+    /**
+     * 
+     * 
+     * @see bluej.debugger.DebuggerTestResult#getRunTimeMs()
+     */
+    public int getRunTimeMs()
+    {
+        return runTimeMs;
+    }
+
+    /**
+     * 
+     * @see bluej.debugger.DebuggerTestResult#getTrace()
+     */
+    public String getTrace()
+    {
+        throw new IllegalStateException("getting stack trace from successful test");
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.debugger.DebuggerTestResult#getExceptionLocation()
+     */
+    public SourceLocation getExceptionLocation()
+    {
+        throw new IllegalStateException("getting stack trace from successful test");
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.debugger.DebuggerTestResult#isError()
+     */
+    public boolean isError()
+    {
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.debugger.DebuggerTestResult#isFailure()
+     */
+    public boolean isFailure()
+    {
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.debugger.DebuggerTestResult#isSuccess()
+     */
+    public boolean isSuccess()
+    {
+        return true;
+    }
+
+    /**
+     * Filters stack frames from internal JUnit classes
+     */
+    public static String getFilteredTrace(String stack)
+    {
+        StringWriter sw= new StringWriter();
+        PrintWriter pw= new PrintWriter(sw);
+        StringReader sr= new StringReader(stack);
+        BufferedReader br= new BufferedReader(sr);
+
+        String line;
+        try {
+            while ((line= br.readLine()) != null) {
+                if (!filterLine(line))
+                    pw.println(line);
+            }
+        } catch (Exception IOException) {
+            return stack; // return the stack unfiltered
+        }
+        return sw.toString();
+    }
+
+    static boolean filterLine(String line)
+    {
+        String[] patterns= new String[] {
+                "junit.framework.TestCase",
+                "junit.framework.TestResult",
+                "junit.framework.TestSuite",
+                "junit.framework.Assert.", // don't filter AssertionFailure
+                "junit.swingui.TestRunner",
+                "junit.awtui.TestRunner",
+                "junit.textui.TestRunner",
+                "org.junit.runner",
+                "org.junit.internal",
+                "sun.reflect.",
+                "bluej.",
+                "java.lang.reflect.Method.invoke("
+        };
+        for (int i= 0; i < patterns.length; i++) {
+            if (line.indexOf(patterns[i]) > 0)
+                return true;
+        }
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiTestResultError.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiTestResultError.java
new file mode 100644
index 0000000000000000000000000000000000000000..500c5f755e43e6292bc9e83f791272e73bb9bb96
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiTestResultError.java
@@ -0,0 +1,84 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import bluej.debugger.SourceLocation;
+
+/**
+ * Represents the result of running a single test method.
+ */
+public class JdiTestResultError extends JdiTestResult
+{
+    SourceLocation failPoint;
+
+    JdiTestResultError(String className, String methodName, String exceptionMsg, String traceMsg, SourceLocation failPoint, int runTimeMs)
+    {
+        super(className, methodName, runTimeMs);
+
+        this.exceptionMsg = exceptionMsg;
+
+        if (traceMsg != null) {
+            this.traceMsg = getFilteredTrace(traceMsg);
+        }
+        else {
+            this.traceMsg = null;
+        }
+
+        this.failPoint = failPoint;
+    }
+    
+    @Override
+    public String getExceptionMessage()
+    {
+        return exceptionMsg;
+    }
+
+    @Override
+    public String getTrace()
+    {
+        return traceMsg;
+    }
+    
+    @Override
+    public SourceLocation getExceptionLocation()
+    {
+        return failPoint;
+    }
+
+    @Override
+    public boolean isError()
+    {
+        return true;
+    }
+
+    @Override
+    public boolean isFailure()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isSuccess()
+    {
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiTestResultFailure.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiTestResultFailure.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1c42ba4a2bc1ec52ef560ddb5485e3dc1f38f66
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiTestResultFailure.java
@@ -0,0 +1,88 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import bluej.debugger.SourceLocation;
+
+/**
+ * Represents the result of running a single test method.
+ */
+public class JdiTestResultFailure extends JdiTestResult
+{
+    SourceLocation failPoint;
+    
+    /**
+     * Construct a new test failure result.
+     */
+    JdiTestResultFailure(String className, String methodName, String exceptionMsg, String traceMsg,
+            SourceLocation failPoint, int runTimeMs)
+    {
+        super(className, methodName, runTimeMs);
+
+        this.exceptionMsg = exceptionMsg;
+
+        if (traceMsg != null) {
+            this.traceMsg = getFilteredTrace(traceMsg);
+        }
+        else {
+            this.traceMsg = null;
+        }
+
+        this.failPoint = failPoint;
+    }
+    
+    @Override
+    public String getExceptionMessage()
+    {
+        return exceptionMsg;
+    }
+
+    @Override
+    public String getTrace()
+    {
+        return traceMsg;
+    }
+    
+    @Override
+    public SourceLocation getExceptionLocation()
+    {
+        return failPoint;
+    }
+
+    @Override
+    public boolean isError()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isFailure()
+    {
+        return true;
+    }
+
+    @Override
+    public boolean isSuccess()
+    {
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThread.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d44909077c157bfe2a43a4b9fb553b5c12f4375
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThread.java
@@ -0,0 +1,655 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.util.*;
+
+import bluej.Config;
+import bluej.debugger.*;
+import bluej.debugger.gentype.JavaType;
+import bluej.utility.Debug;
+
+import com.sun.jdi.*;
+import com.sun.jdi.request.EventRequestManager;
+import com.sun.jdi.request.StepRequest;
+
+/**
+ * This class represents a thread running on the remote virtual machine.
+ *
+ * @author  Michael Kolling
+ */
+class JdiThread extends DebuggerThread
+{
+    static final String statusFinished = Config.getString("debugger.threadstatus.finished");
+    static final String statusBreakpoint = Config.getString("debugger.threadstatus.breakpoint");
+    static final String statusStopped = Config.getString("debugger.threadstatus.stopped");
+    static final String statusMonitor = Config.getString("debugger.threadstatus.monitor");
+    static final String statusNotStarted = Config.getString("debugger.threadstatus.notstarted");
+    static final String statusRunning = Config.getString("debugger.threadstatus.running");
+    static final String statusSleeping = Config.getString("debugger.threadstatus.sleeping");
+    static final String statusUnknown = Config.getString("debugger.threadstatus.unknown");
+    static final String statusWaiting = Config.getString("debugger.threadstatus.waiting");
+    static final String statusZombie = Config.getString("debugger.threadstatus.zombie");
+
+    /** a list of classes to exclude from source display */
+    private static List<String> excludes;
+
+    private static List<String> getExcludes()
+    {
+        if (excludes == null) {
+            setExcludes("java.*, javax.*, sun.*, com.sun.*");
+        }
+        return excludes;
+    }
+
+    private static void setExcludes(String excludeString)
+    {
+        StringTokenizer t = new StringTokenizer(excludeString, " ,;");
+        List<String> list = new ArrayList<String>();
+        while (t.hasMoreTokens()) {
+            list.add(t.nextToken());
+        }
+        excludes = list;
+    }
+
+    static void addExcludesToRequest(StepRequest request)
+    {
+        Iterator<String> iter = getExcludes().iterator();
+        while (iter.hasNext()) {
+            String pattern = iter.next();
+            request.addClassExclusionFilter(pattern);
+        }
+    }
+
+    /** the reference to the remote thread */
+    private ThreadReference rt;
+    
+    /** We track suspension status internally */
+    private boolean isSuspended;
+    
+    /*
+     * Note that we have to track suspension status internally, because JDI will happily
+     * tell us that a thread is suspended when, in fact, it is suspended only because of some
+     * VM event which suspends every thread (ThreadStart / ThreadDeath).
+     */
+    
+    // stores a stack frame that was selected for this
+    // thread (selection is done for debugging)
+    private int selectedFrame;
+   
+    private EventRequestManager eventReqMgr;
+    
+    private JdiDebugger debugger;
+
+    // ---- instance: ----
+
+    public JdiThread(JdiDebugger debugger, ThreadReference rt)
+    {
+        this.rt = rt;
+        this.debugger = debugger;
+
+        selectedFrame = 0;      // unless specified otherwise, assume we want
+                                //  to see the top level frame
+    }
+
+    /** 
+     * Return the name of this thread.
+     */
+    public String getName()
+    {
+        String name = null;
+        try {
+            name = rt.name();
+        }
+        catch(Exception e) {
+            // ignore it
+        }
+        return name;
+    }
+
+    /** 
+     * Return the reference to the thread object in the remote machine.
+     */
+    ThreadReference getRemoteThread()
+    {
+        return rt;
+    }
+
+    /** 
+     * Return the current status of this thread.
+     */
+    public String getStatus()
+    {
+        try {
+            if (rt.isAtBreakpoint()) {
+                if(VMReference.isAtMainBreakpoint(rt)) {
+                    return statusFinished;
+                }
+                else {
+                    return statusBreakpoint;
+                }
+            }
+                        
+            if(rt.isSuspended()) {
+                return statusStopped;
+            }
+
+            int status = rt.status();
+            switch(status) {
+             case ThreadReference.THREAD_STATUS_MONITOR:
+                return statusMonitor;
+             case ThreadReference.THREAD_STATUS_NOT_STARTED:
+                return statusNotStarted;
+             case ThreadReference.THREAD_STATUS_RUNNING:
+                return statusRunning;
+             case ThreadReference.THREAD_STATUS_SLEEPING:
+                return statusSleeping;
+             case ThreadReference.THREAD_STATUS_UNKNOWN:
+                return statusUnknown;
+             case ThreadReference.THREAD_STATUS_WAIT:
+                return statusWaiting;
+             case ThreadReference.THREAD_STATUS_ZOMBIE:
+                return statusZombie;
+            }
+        }
+        catch(Exception e) {
+            return "???";
+        }
+        return null;
+    }
+
+    /**
+     * Return true if this is a user thread that is in idle state
+     * (finished).
+     */
+    public boolean isFinished()
+    {
+        try {
+            return  rt.isAtBreakpoint() && VMReference.isAtMainBreakpoint(rt);
+        }
+        catch (VMDisconnectedException vmde) {
+            return true;
+        }
+    }
+
+    /**
+     * Return true if this thread is currently suspended.
+     */
+    public boolean isSuspended()
+    {
+        return isSuspended;
+    }
+
+    /** 
+     * Return true if this thread is currently at a breakpoint.
+     */
+    public boolean isAtBreakpoint()
+    {
+        return rt.isAtBreakpoint();
+    }
+
+    /** 
+     * Return the class this thread was executing in when the
+     * specified stack frame was active.
+     */
+    public String getClass(int frameNo)
+    {
+        try {
+            return rt.frame(frameNo).location().declaringType().name();
+        }
+        catch(Exception e) {
+            return "<error finding type at frame " + frameNo +">";
+        }
+    }
+
+    /** 
+     * Return the source name of the class this thread was 
+     * executing in when the specified stack frame was active.
+     */
+    public String getClassSourceName(int frameNo)
+    {
+        try {
+            return rt.frame(frameNo).location().sourceName();
+        }
+        catch(Exception e) {
+            return "<no source at frame no " + frameNo +">";
+        }
+    }
+
+    /** 
+     * Return the line number in the source where this thread was 
+     * executing when the specified stack frame was active.
+     */
+    public int getLineNumber(int frameNo)
+    {
+        try {
+            return rt.frame(frameNo).location().lineNumber();
+        }
+        catch(Exception e) {
+            return 1;
+        }
+    }
+
+    // name of the threadgroup that contains user threads
+    static final String MAIN_THREADGROUP = "main";
+
+    public boolean isKnownSystemThread()
+    {
+        // A finished thread will have a null thread group.
+        try {
+            ThreadGroupReference tgr = rt.threadGroup();
+            if(tgr == null || ! tgr.name().equals(MAIN_THREADGROUP)) {
+                return true;
+            }
+
+            String name = rt.name();
+            if(name.startsWith("AWT-") ||
+                    name.equals("DestroyJavaVM") ||
+                    name.equals("BlueJ worker thread") ||
+                    name.equals("Timer Queue") ||
+                    name.equals("Screen Updater") ||
+                    name.startsWith("SunToolkit.") ||
+                    name.startsWith("Native Carbon") ||
+                    name.equals("Java2D Disposer")) {
+                return true;
+            }
+
+            return false;
+        }
+        catch (VMDisconnectedException vmde) {
+            return false;
+        }
+        catch (ObjectCollectedException oce) {
+            return true;
+        }
+    }
+
+    /**
+     * Get strings showing the current stack frames. Ignore everything
+     * including the __SHELL class and below.
+     *
+     * <p>The thread must be suspended to do this. Otherwise an empty list
+     * is returned.
+     *
+     * @return  A List of SourceLocations
+     */
+    public List<SourceLocation> getStack()
+    {
+        return getStack(rt);
+    }
+
+    /**
+     * Get strings showing the current stack frames. Ignore everything
+     * including the __SHELL class and below.
+     *
+     * <p>The thread must be suspended to do this. Otherwise an empty list
+     * is returned.
+     * 
+     * @return  A List of SourceLocations
+     */
+    public static List<SourceLocation> getStack(ThreadReference thr)
+    {
+        try {
+            if(thr.isSuspended()) {
+                List<SourceLocation> stack = new ArrayList<SourceLocation>();
+                List<StackFrame> frames = thr.frames();
+
+                for(int i = 0; i < frames.size(); i++) {
+                    StackFrame f = (StackFrame)frames.get(i);
+                    Location loc = f.location();
+                    String className = loc.declaringType().name();
+                    
+                    String fileName = null;
+                    try {
+                        fileName = loc.sourceName();
+                    }
+                    catch(AbsentInformationException e) { }
+                    String methodName = loc.method().name();
+                    int lineNumber = loc.lineNumber();
+
+                    stack.add(new SourceLocation(className, fileName,
+                                                 methodName, lineNumber));
+                }
+                return stack;
+            }
+        }
+        catch (VMDisconnectedException vmde) {
+            // Finished, no trace
+        }
+        catch(IncompatibleThreadStateException e) {
+            // this is possible if the thread state changes after
+            // our check for its suspended state
+            // lets just return an empty List
+        }
+        catch(InvalidStackFrameException isfe) {
+            // same here
+        }
+        return new ArrayList<SourceLocation>();
+    }
+
+
+    /**
+     * Return strings listing the local variables.
+     *
+     * The thread must be suspended to do this. Otherwise an empty List
+     * is returned.
+     */
+    public List<String> getLocalVariables(int frameNo)
+    {
+        try {
+            if(rt.isSuspended()) {
+                StackFrame frame = rt.frame(frameNo);
+                List<LocalVariable> vars = frame.visibleVariables();
+                List<String> localVars = new ArrayList<String>();
+                
+                // To work around a JDI bug (probably related to the other one described
+                // below) we collect information we need about the variables on the
+                // stack frame before we do anything which might cause types to be
+                // loaded:
+                
+                List<String> localVals = new ArrayList<String>();
+                List<Type> localTypes = new ArrayList<Type>();
+                List<String> genericSigs = new ArrayList<String>();
+                List<String> typeNames = new ArrayList<String>();
+                ReferenceType declaringType = frame.location().declaringType();
+                
+                for(int i = 0; i < vars.size(); i++) {
+                    LocalVariable var = vars.get(i);
+                    String val = JdiUtils.getJdiUtils().getValueString(frame.getValue(var));
+                    localVals.add(val);
+                    
+                    try {
+                        localTypes.add(var.type());
+                    }
+                    catch (ClassNotLoadedException cnle) {
+                        localTypes.add(null);
+                    }
+                    
+                    genericSigs.add(var.genericSignature());
+                    typeNames.add(var.typeName());
+                }
+                
+                for(int i = 0; i < vars.size(); i++) {
+                    LocalVariable var = vars.get(i);
+
+                    // Add "type name = value" to the list
+                    JavaType vartype = JdiReflective.fromLocalVar(localTypes.get(i), genericSigs.get(i),
+                            typeNames.get(i), declaringType);
+                    localVars.add(vartype.toString(true) + " " + var.name()
+                            + " = " + localVals.get(i));
+                }
+                return localVars;
+            }
+        }
+        catch (IncompatibleThreadStateException itse) { }
+        catch (AbsentInformationException ase) { }
+        catch (VMDisconnectedException vmde) { }
+        catch (InvalidStackFrameException e) {
+            // This shouldn't happen, as we've checked the thread status, 
+            // but it does, apparently; seems like a JDK bug.
+            // Probably related to: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6644945
+            // Occurs (at least) in JDK 1.6.0_25.
+            try {
+                Thread.sleep(100);
+                return getLocalVariables(frameNo);
+            }
+            catch (InterruptedException ie) {}
+        }
+        return new ArrayList<String>();
+    }
+
+    /**
+     * Return true if the identified slot on the stack contains an object.
+     */
+    public boolean varIsObject(int frameNo, int index)
+    {
+        try {
+            if(rt.isSuspended()) {
+                StackFrame frame = rt.frame(frameNo);
+                List<LocalVariable> vars = frame.visibleVariables();
+                LocalVariable var = vars.get(index);
+                Value val = frame.getValue(var);
+                return (val instanceof ObjectReference);
+            }
+            else
+                return false;
+        }
+        catch(Exception e) {
+            // nothing can be done...
+            Debug.reportError("could not get local variable info: " + e);
+        }
+        return false;
+    }
+
+    /**
+     * Return an object from this thread's stack. The variable must contain
+     * an object.
+     */
+    public DebuggerObject getStackObject(int frameNo, int index)
+    {
+        try {
+            if(rt.isSuspended()) {
+                StackFrame frame = rt.frame(frameNo);
+                List<LocalVariable> vars = frame.visibleVariables();
+                LocalVariable var = vars.get(index);
+                JavaType vartype = JdiReflective.fromLocalVar(frame, var);
+                ObjectReference val = (ObjectReference)frame.getValue(var);
+                return JdiObject.getDebuggerObject(val, vartype);
+            }
+            else
+                return null;
+        }
+        catch(Exception e) {
+            // nothing can be done...
+            Debug.reportError("could not get local variable info: " + e);
+        }
+        return null;
+    }
+
+    @Override
+    public DebuggerObject getCurrentObject(int frameNo)
+    {
+        try {
+            if(rt.isSuspended()) {
+                StackFrame frame = rt.frame(frameNo);
+                return JdiObject.getDebuggerObject(frame.thisObject());
+            }
+        }
+        catch (IncompatibleThreadStateException e) { }
+        catch (VMDisconnectedException vmde) { }
+        catch (InvalidStackFrameException ise) { } // thread was resumed elsewhere
+        return JdiObject.getDebuggerObject(null);
+    }
+
+    @Override
+    public DebuggerClass getCurrentClass(int frameNo)
+    {
+        try {
+            if(rt.isSuspended()) {
+                StackFrame frame = rt.frame(frameNo);
+                return new JdiClass(frame.location().declaringType());
+            }
+        }
+        catch (IncompatibleThreadStateException e) { }
+        catch (VMDisconnectedException vmde) { }
+        return null;
+    }
+
+    /** 
+     * Specify a frame as the currently selected frame in this thread.
+     */
+    public void setSelectedFrame(int frame)
+    {
+        selectedFrame = frame;
+    }
+
+    /** 
+     * Return the selected frame in this thread.
+     */
+    public int getSelectedFrame()
+    {
+        return selectedFrame;
+    }
+
+    /**
+     * Halt this thread.
+     */
+    public synchronized void halt()
+    {
+        try {
+            if (! isSuspended) {
+                rt.suspend();
+                debugger.emitThreadHaltEvent(this);
+                isSuspended = true;
+            }
+        }
+        catch (VMDisconnectedException vmde) {}
+    }
+
+    /**
+     * Continue a previously halted thread.
+     */
+    public synchronized void cont()
+    {
+        try {
+            if (isSuspended) {
+                debugger.emitThreadResumedEvent(this);
+                rt.resume();
+                isSuspended = false;
+            }
+        }
+        catch (VMDisconnectedException vmde) {}
+    }
+
+    /**
+     * Inform the JdiThread that the underlying thread has been suspended due to
+     * (for example) hitting a breakpoint.
+     */
+    public void stopped()
+    {
+        isSuspended = true;
+    }
+    
+    /**
+     * Make this thread step a single line.
+     */
+    public void step()
+    {
+        doStep(StepRequest.STEP_OVER);
+    }
+
+    public void stepInto()
+    {
+        doStep(StepRequest.STEP_INTO);
+    }
+
+    /**
+     * Return the JDI ThreadReference which this JdiThread wraps.
+     */
+    public ThreadReference getThreadReference()
+    {
+        return rt;
+    }
+    
+    private void doStep(int depth)
+    {
+        clearPreviousStep(rt);
+        StepRequest request = eventReqMgr.createStepRequest(rt,
+                                             StepRequest.STEP_LINE, depth);
+        addExcludesToRequest(request);
+
+        // Make sure the step event is done only once
+        request.addCountFilter(1);
+        request.putProperty(VMEventHandler.DONT_RESUME, "yes");
+        request.enable();
+
+        synchronized (this) {
+            isSuspended = false;
+        }
+        rt.resume();
+    }
+
+    /**
+     * A previously set step may not have completed yet - find out and
+     * if it is so, remove it.
+     */
+    private void clearPreviousStep(ThreadReference thread)
+    {
+        if(eventReqMgr == null)
+            getEventRequestManager();
+
+        List<StepRequest> requests = eventReqMgr.stepRequests();
+        Iterator<StepRequest> iter = requests.iterator();
+
+        while (iter.hasNext()) {
+            StepRequest request = iter.next();
+
+            if (request != null && request.thread() != null) {
+                if (request.thread().equals(thread)) {
+                    eventReqMgr.deleteEventRequest(request);
+                    // we must break here because now we
+                    // have deleted the step event, the
+                    // list iterator is invalid
+                    // our assumption is that we can have at
+                    // most one step event for this thread
+                    // in the system.
+                    break;
+                }
+            }
+        }
+    }
+
+    private void getEventRequestManager()
+    {
+        eventReqMgr = rt.virtualMachine().eventRequestManager();
+    }
+    
+    public String toString()
+    {
+        try {
+            return getName() + " (" + getStatus() + ")";
+            //return getName() + " (" + getStatus() + ") " + rt.threadGroup().name();  // for debugging
+        }
+        catch (ObjectCollectedException oce)
+        {
+            return "collected";
+        }
+    }
+    
+    public boolean sameThread(DebuggerThread dt)
+    {
+        if (dt != null && dt instanceof JdiThread) {
+            return getThreadReference().uniqueID() == ((JdiThread)dt).getThreadReference().uniqueID();
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Called when we are the serverThread, to let us know we've been resumed
+     * (and should update our internal status accordingly)
+     */
+    public void notifyResumed()
+    {
+        isSuspended = false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThreadNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThreadNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f32fb3f1f1348ac0e6cac026f3dbb0ee99b0afa
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThreadNode.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
+import com.sun.jdi.*;
+
+/**
+ * A tree node for the JDI thread tree.
+ */
+class JdiThreadNode extends DefaultMutableTreeNode
+{
+    public JdiThreadNode()
+    {
+    }
+
+    public JdiThreadNode(ThreadGroupReference tgr)
+    {
+        setUserObject(tgr);
+    }
+
+    public JdiThreadNode(JdiThread jt)
+    {
+        setUserObject(jt);	
+    }
+
+    public boolean getAllowsChildren()
+    {
+        return (getUserObject() == null) || (getUserObject() instanceof ThreadGroupReference);
+    }
+
+    public String toString()
+    {
+        if (getUserObject() != null) {
+            try {
+                return getUserObject().toString();
+            }
+            catch (ObjectCollectedException oce) {
+                return "collected";
+            }
+        }
+
+        return "All Threads";
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThreadSet.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThreadSet.java
new file mode 100644
index 0000000000000000000000000000000000000000..86667ff199f85fb2e2ae8c493b0cebcaf3147e4e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThreadSet.java
@@ -0,0 +1,75 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.util.*;
+
+import bluej.utility.Debug;
+
+import com.sun.jdi.ThreadReference;
+
+/**
+ * A wrapper around a TreeSet that helps us
+ * store JdiThreads.
+ * 
+ * @author  Michael Kolling
+ */
+public class JdiThreadSet extends HashSet<JdiThread>
+{
+    /**
+     * Construct an empty thread set.
+     * 
+     */
+    public JdiThreadSet()
+    {
+        super();
+    }
+
+    /**
+     * Find the thread in the set representing the thread reference specified.
+     */
+    public JdiThread find(ThreadReference thread)
+    {
+        for(Iterator<JdiThread> it=iterator(); it.hasNext(); ) {
+            JdiThread currentThread = (JdiThread)it.next();
+            if(currentThread.getRemoteThread().equals(thread)) {
+                return currentThread;
+            }
+        }
+        Debug.reportError("Encountered thread not in ThreadSet!");
+        return null;
+    }
+
+    /**
+     * Remove the given thread from the set.
+     */
+    public void removeThread(ThreadReference thread)
+    {
+        for(Iterator<JdiThread> it=iterator(); it.hasNext(); ) {
+            if(((JdiThread)it.next()).getRemoteThread().equals(thread)) {
+                it.remove();
+                return;
+            }
+        }
+        Debug.reportError("Unknown thread died!");
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThreadTreeModel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThreadTreeModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..d530a0b2a2a587ca749fbd782f9a75f9fbb6c7b5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiThreadTreeModel.java
@@ -0,0 +1,170 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.util.Enumeration;
+
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
+
+import bluej.debugger.DebuggerThread;
+import bluej.debugger.DebuggerThreadTreeModel;
+
+import com.sun.jdi.ThreadGroupReference;
+import com.sun.jdi.ThreadReference;
+
+/**
+ * A wrapper around DefaultTreeModel that helps us store JdiThreads.
+ * 
+ * Our tree stores the data we are interested in the userObject field of the
+ * TreeNode (in our tree this type is called JdiThreadNode). The data can either
+ * be null (for the root), a ThreadGroupReference (for thread groups) or a
+ * JdiThread object (for actual threads).
+ * 
+ * @author Andrew Patterson
+ * @version $Id: JdiThreadTreeModel.java 8085 2010-08-17 03:21:40Z davmac $
+ */
+public class JdiThreadTreeModel extends DefaultTreeModel
+    implements DebuggerThreadTreeModel
+{
+    private SyncMechanism syncer;
+
+    /**
+     * Construct a tree model holding threads.
+     * 
+     * @param root
+     */
+    public JdiThreadTreeModel(JdiThreadNode root)
+    {
+        super(root, true);
+        syncer = new SyncMechanism() {
+            public void invokeLater(Runnable r)
+            {
+                synchronized (getRoot()) {
+                    r.run();
+                }
+            }
+        };
+    }
+
+    /**
+     * Set the synchronisation method used to control access to the tree model.
+     * This can be used to enforce Swing threading safety.
+     */
+    public void setSyncMechanism(SyncMechanism s)
+    {
+        syncer = s;
+    }
+
+    /**
+     * Invoke some code via the the installed synchronization method.
+     * 
+     * @param r
+     *            The code to invoke in a synchronized fashion
+     */
+    public void syncExec(Runnable r)
+    {
+        syncer.invokeLater(r);
+    }
+
+    /**
+     * Return the DebuggerThread object stored in a tree node.
+     * 
+     * @param node
+     *            an object of type JdiThreadNode.
+     * @returns the user object of the node typecast to a DebuggerThread object
+     *          or null if this node does not contain a DebuggerThread.
+     */
+    public DebuggerThread getNodeAsDebuggerThread(Object node)
+    {
+        Object o = ((JdiThreadNode) node).getUserObject();
+        if (o instanceof JdiThread) {
+            return (JdiThread) o;
+
+        }
+        return null;
+    }
+
+    public TreePath findNodeForThread(DebuggerThread thr)
+    {
+        return new TreePath(findThreadNode(((JdiThread) thr).getRemoteThread()).getPath());
+    }
+
+    /**
+     * Return the root node as a JdiThreadNode.
+     */
+    JdiThreadNode getThreadRoot()
+    {
+        return (JdiThreadNode) getRoot();
+    }
+
+    /**
+     * Find a node in the tree holding a particular ThreadGroupReference.
+     * 
+     * @param tgr
+     *            the ThreadGroupReference to look for.
+     * @return the JdiThreadNode holding the tgr or null if one does not exist.
+     */
+    JdiThreadNode findThreadNode(ThreadGroupReference tgr)
+    {
+        Enumeration<?> en = getThreadRoot().breadthFirstEnumeration();
+
+        while (en.hasMoreElements()) {
+            JdiThreadNode n = (JdiThreadNode) en.nextElement();
+
+            Object o = n.getUserObject();
+            if (o instanceof ThreadGroupReference) {
+                ThreadGroupReference otgr = (ThreadGroupReference) o;
+
+                if (otgr.equals(tgr))
+                    return n;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Find a node in the tree holding a particular ThreadReference.
+     * 
+     * @param tgr
+     *            the ThreadReference to look for.
+     * @return the JdiThreadNode holding the tr or null if one does not exist.
+     */
+    JdiThreadNode findThreadNode(ThreadReference tr)
+    {
+        Enumeration<?> en = getThreadRoot().breadthFirstEnumeration();
+
+        while (en.hasMoreElements()) {
+            JdiThreadNode n = (JdiThreadNode) en.nextElement();
+
+            Object o = n.getUserObject();
+            if (o instanceof JdiThread) {
+                JdiThread jt = (JdiThread) o;
+
+                if (jt.getRemoteThread().equals(tr))
+                    return n;
+            }
+        }
+
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiUtils.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..e77a663fb1f897f903d47b491cb1270b89fa8530
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiUtils.java
@@ -0,0 +1,116 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import bluej.Config;
+import bluej.debugger.DebuggerObject;
+import bluej.utility.JavaUtils;
+
+import com.sun.jdi.CharValue;
+import com.sun.jdi.ClassType;
+import com.sun.jdi.Field;
+import com.sun.jdi.LocalVariable;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.StringReference;
+import com.sun.jdi.Value;
+
+/**
+ * Utility methods for Jdi. Used to abstract away differences between java
+ * 1.4 and 1.5
+ * 
+ * @author Davin McCall
+ */
+public abstract class JdiUtils
+{
+    private static JdiUtils jutils = null;
+    private static final String nullLabel = "null";
+    
+    /**
+     * Factory method. Returns a JdiUtils object.
+     * @return an object supporting the approriate feature set
+     */
+    public static JdiUtils getJdiUtils()
+    {
+        if( jutils != null )
+            return jutils;
+        if( Config.isJava15() ) {
+            try {
+                Class<?> J15Class = Class.forName("bluej.debugger.jdi.JdiUtils15");
+                jutils = (JdiUtils)J15Class.newInstance();
+            }
+            catch(ClassNotFoundException cnfe) { }
+            catch(IllegalAccessException iae) { }
+            catch(InstantiationException ie) { }
+        }
+        else
+            jutils = new JdiUtils14();
+        return jutils;
+    }
+
+    abstract public boolean hasGenericSig(ObjectReference obj);
+    
+    abstract public String genericSignature(Field f);
+    
+    abstract public String genericSignature(ReferenceType rt);
+    
+    abstract public String genericSignature(LocalVariable lv);
+    
+    abstract public boolean isEnum(ClassType ct);
+    
+    /**
+     * Return the value of a field as as string.
+     * 
+     * <p>Values are represented differently depending on their type:
+     * <ul>
+     * <li>A String value is represented as a valid Java string expression.
+     * <li>A null value is represented as "null".
+     * <li>An Enum value is represented as the name of the Enum constant.
+     * <li>Any other object reference is represented as "&lt;object reference&gt;".
+     * <li>A primitive value is represented as the value itself.
+     * </ul>
+     *
+     * @see bluej.debugger.DebuggerObject#getInstanceFields(boolean, java.util.Map)
+     */
+    public String getValueString(Value val)
+    {
+        if (val == null) {
+            return nullLabel;
+        }
+        else if (val instanceof StringReference) {
+            return "\"" + JavaUtils.escapeString(((StringReference) val).value()) + "\"";
+        }
+        else if (val.type() instanceof ClassType && isEnum((ClassType) val.type())) {
+            ClassType type = (ClassType) val.type();
+            Field nameField = type.fieldByName("name");
+            String name = ((StringReference) ((ObjectReference) val).getValue(nameField)).value();
+            return name;
+        }
+        else if (val instanceof ObjectReference) {
+            return DebuggerObject.OBJECT_REFERENCE;
+        }
+        else if (val instanceof CharValue) {
+            return "\'" + JavaUtils.escapeString(val.toString()) + "\'";
+        }
+        return val.toString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiUtils14.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiUtils14.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b5df81fdeb31c9dbac0bbb2af1b5b5a819ff588
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiUtils14.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import com.sun.jdi.ClassType;
+import com.sun.jdi.Field;
+import com.sun.jdi.LocalVariable;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+
+/*
+ * Jdi utilities, java 1.4 version.
+ *  
+ * @author Davin McCall
+ * @version $Id: JdiUtils14.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class JdiUtils14 extends JdiUtils {
+
+    public boolean hasGenericSig(ObjectReference obj)
+    {
+        return false;
+    }
+    
+    public String genericSignature(Field f)
+    {
+        return null;
+    }
+    
+    public String genericSignature(ReferenceType rt)
+    {
+        return null;
+    }
+    
+    public String genericSignature(LocalVariable lv)
+    {
+        return null;
+    }
+    
+    public boolean isEnum(ClassType ct)
+    {
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiUtils15.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiUtils15.java
new file mode 100644
index 0000000000000000000000000000000000000000..c2e994f639f025fab3f41c7952852433caf26aa4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiUtils15.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import com.sun.jdi.ClassType;
+import com.sun.jdi.Field;
+import com.sun.jdi.LocalVariable;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+
+/*
+ * Jdi Utilities, java 1.5 version.
+ * 
+ * @author Davin McCall
+ * @version $Id: JdiUtils15.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class JdiUtils15 extends JdiUtils
+{
+    public boolean hasGenericSig(ObjectReference obj)
+    {
+        return obj.referenceType().genericSignature() != null;
+    }
+
+    public String genericSignature(Field f)
+    {
+        return f.genericSignature();
+    }
+
+    public String genericSignature(ReferenceType rt)
+    {
+        return rt.genericSignature();
+    }
+
+    public String genericSignature(LocalVariable lv)
+    {
+        return lv.genericSignature();
+    }
+    
+    public boolean isEnum(ClassType ct)
+    {
+        return ct.isEnum();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiVmCreationException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiVmCreationException.java
new file mode 100644
index 0000000000000000000000000000000000000000..29601684fd150ba7b5d10c57f900cd97bad23cb3
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/JdiVmCreationException.java
@@ -0,0 +1,31 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+/**
+ * Is thrown when the creation of the debug WM fails.
+ * @author Kasper Fisker
+ * @version $Id: JdiVmCreationException.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class JdiVmCreationException extends Exception {
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/NetworkTest.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/NetworkTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c7b787735473f4582042f0060a37e9d29f15527
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/NetworkTest.java
@@ -0,0 +1,171 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kölling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import bluej.utility.Debug;
+
+/**
+ * A network test which logs diagnostics information.
+ *  
+ * @author Davin McCall
+ */
+public class NetworkTest
+{
+    public static void doTest()
+    {
+        Debug.message("Commencing network test...");
+        
+        InetAddress lhost = null;
+        InetAddress[] lhostByName = new InetAddress[0];
+        
+        try {
+            lhost = InetAddress.getLocalHost();
+            Debug.message("Local host address = " + lhost.getHostAddress());
+            Debug.message("Local host ip = " + lhost.getHostAddress());
+
+            lhostByName = InetAddress.getAllByName("localhost");
+            Debug.message("Addresses for 'localhost':");
+            for (InetAddress name : lhostByName) {
+                Debug.message(" -> " + name.getHostAddress());
+            }
+            Debug.message("(end of list).");
+        }
+        catch (UnknownHostException uhe) {
+            Debug.message("(!!) UnknownHostException when getting local host address!");
+        }
+        
+        Debug.message("Creating unbound server socket...");
+        try {
+            ServerSocket ss = new ServerSocket();
+            Debug.message("Successful.");
+            try {
+                ss.close();
+            }
+            catch (IOException ioe) {}
+        }
+        catch (IOException ioe) {
+            Debug.message("(!!) Creation of server socket failed; message=" + ioe.getMessage());
+            Debug.message("(!!) Exception class: " + ioe.getClass().getName());
+        }
+
+        InetAddress loop4addr = null;
+        InetAddress loop6addr = null;
+        
+        try {
+            loop4addr = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
+            testServerAddress(loop4addr);
+        }
+        catch (UnknownHostException uhe) {
+            Debug.message("(!!) 127.0.0.1 is unknown host: " + uhe.getMessage());
+        }
+
+        try {
+            loop6addr = InetAddress.getByAddress(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, 0, 0, 0, 0, 1});
+            testServerAddress(loop6addr);
+        }
+        catch (UnknownHostException uhe) {
+            Debug.message("(!!) ::1 is unknown host: " + uhe.getMessage());
+        }
+        
+        if (lhost != null && !lhost.equals(loop4addr) && !lhost.equals(loop6addr)) {
+            testServerAddress(lhost);
+        }
+        
+        for (InetAddress name : lhostByName) {
+            if (!name.equals(loop4addr) && !name.equals(loop6addr) && !name.equals(lhost)) {
+                testServerAddress(name);
+            }
+        }        
+        
+        Debug.message("Network test complete.");
+    }
+    
+    /**
+     * Try to listen on a particular address, and connect to the server socket.
+     */
+    private static void testServerAddress(final InetAddress loopAddr)
+    {
+        Debug.message("Creating server socket bound to " + loopAddr.getHostAddress() + "...");
+        try {
+            final ServerSocket ss = new ServerSocket(0, 50, loopAddr);
+            Debug.message("Successful.");
+            
+            Thread t = new Thread() {
+                @Override
+                public void run()
+                {
+                    try {
+                        Debug.message("Attempting to connect to " + loopAddr.getHostAddress() + ":" + ss.getLocalPort() + " with NO_PROXY...");
+                        Socket s = new Socket(Proxy.NO_PROXY);
+                        s.setSoTimeout(300);
+                        s.connect(new InetSocketAddress(loopAddr, ss.getLocalPort()));
+                        Debug.message("Successful.");
+                        
+                        Debug.message("Attempting to connect to " + loopAddr.getHostAddress() + ":" + ss.getLocalPort() + "...");
+                        s = new Socket();
+                        s.setSoTimeout(300);
+                        s.connect(new InetSocketAddress(loopAddr, ss.getLocalPort()));
+                        Debug.message("Successful.");
+                    }
+                    catch (IOException ioe) {
+                        Debug.message("(!!) Couldn't connect to local address: " + ioe.getMessage());
+                        Debug.message("(!!) Exception class: " + ioe.getClass().getName());
+                    }
+                }
+            };
+            
+            t.start();
+            ss.setSoTimeout(500); // wait for half a second max
+            try {
+                ss.accept();
+                ss.accept();
+            }
+            catch (IOException ioe) {
+                Debug.message("(!!) Couldn't accept connection: " + ioe.getMessage());
+                Debug.message("(!!) Exception class: " + ioe.getClass().getName());
+            }
+            
+            try {
+                t.join(500);
+            }
+            catch (InterruptedException ie) {}
+            
+            try {
+                ss.close();
+            }
+            catch (IOException ioe) {}
+        }
+        catch (IOException ioe) {
+            Debug.message("(!!) Creation of server socket failed; message=" + ioe.getMessage());
+            Debug.message("(!!) Exception class: " + ioe.getClass().getName());
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/VMEventHandler.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/VMEventHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..61202d4e7ba66f862fedf9f2989130be47485277
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/VMEventHandler.java
@@ -0,0 +1,319 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+import bluej.debugger.DebuggerEvent;
+
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.VirtualMachine;
+import com.sun.jdi.event.BreakpointEvent;
+import com.sun.jdi.event.ClassPrepareEvent;
+import com.sun.jdi.event.Event;
+import com.sun.jdi.event.EventIterator;
+import com.sun.jdi.event.EventQueue;
+import com.sun.jdi.event.EventSet;
+import com.sun.jdi.event.ExceptionEvent;
+import com.sun.jdi.event.LocatableEvent;
+import com.sun.jdi.event.StepEvent;
+import com.sun.jdi.event.ThreadDeathEvent;
+import com.sun.jdi.event.ThreadStartEvent;
+import com.sun.jdi.event.VMDeathEvent;
+import com.sun.jdi.event.VMDisconnectEvent;
+import com.sun.jdi.event.VMStartEvent;
+import com.sun.jdi.request.EventRequest;
+import com.sun.jdi.request.StepRequest;
+
+/**
+ * Event handler class to handle events coming from the remote VM.
+ *
+ * @author  Michael Kolling
+ */
+class VMEventHandler extends Thread
+{
+    final static String DONT_RESUME = "dontResume";
+    
+    private VMReference vm;
+    private EventQueue queue;
+    private boolean queueEmpty;
+    
+    /**
+     * A class to represent a thread halted/resumed event.
+     */
+    private class ThreadEvent
+    {
+        ThreadEvent(JdiThread thread, boolean state)
+        {
+            this.thread = thread;
+            this.state = state;
+        }
+        JdiThread thread;
+        boolean state; // true for halted, false for continued
+    }
+    
+    private Queue<ThreadEvent> haltedThreads = new LinkedList<ThreadEvent>();
+    
+    volatile boolean exiting = false;
+    
+    VMEventHandler(VMReference vm, VirtualMachine vmm)
+    {
+        super("vm-event-handler");
+        this.vm = vm;
+        queue = vmm.eventQueue();
+        start();  // will execute our own run method
+    }
+    
+    public void run()
+    {
+        while (!exiting) {
+            try {
+                // get the next event
+                // NOTE: use 1 as the timeout, because 0 just waits indefinitely,
+                //  contrary to documentation.
+                EventSet eventSet = queue.remove(1);
+                
+                if (eventSet == null) {
+                    // If no event is currently available, signal anyone waiting for
+                    // the queue to empty, and then block until an event arrives
+                    synchronized (this) {
+                        queueEmpty = true;
+                        notifyAll();
+                    }
+                    
+                    // In case a thread event was issued while queueEmpty was still false,
+                    // we should process it now:
+                    handleThreadEvents();
+
+                    try {
+                        eventSet = queue.remove();
+                    }
+                    catch (InterruptedException ie) {
+                        handleThreadEvents();
+                        continue;
+                    }
+                    
+                    synchronized (this) {
+                        isInterrupted(); // clear the interrupt flag;
+                        // we need to do this in a synchronized context
+                        queueEmpty = false;
+                    }
+                }
+                else {
+                    handleThreadEvents();
+                }
+                
+                // From the JDK documentation
+                // The events that are grouped in an EventSet are restricted in the following ways:
+                //   * Always singleton sets:
+                //     o VMStartEvent
+                //     o VMDisconnectEvent 
+                //   * Only with other VMDeathEvents:
+                //     o VMDeathEvent 
+                //   * Only with other ThreadStartEvents for the same thread:
+                //     o ThreadStartEvent 
+                //   * Only with other ThreadDeathEvents for the same thread:
+                //     o ThreadDeathEvent 
+                //   * Only with other ClassPrepareEvents for the same class:
+                //     o ClassPrepareEvent 
+                //   * Only with other ClassUnloadEvents for the same class:
+                //     o ClassUnloadEvent 
+                //   * Only with other AccessWatchpointEvents for the same field access:
+                //     o AccessWatchpointEvent 
+                //   * Only with other ModificationWatchpointEvents for the same field modification:
+                //     o ModificationWatchpointEvent 
+                //   * Only with other ExceptionEvents for the same exception occurrence:
+                //     o ExceptionEvent 
+                //   * Only with other MethodExitEvents for the same method exit:
+                //     o MethodExitEvent 
+                //   * Only with other members of this group, at the same location and in the same thread:
+                //     o BreakpointEvent
+                //     o StepEvent
+                //     o MethodEntryEvent 
+                
+                boolean addToSuspendCount = true;
+                
+                // iterate through all events in the set
+                EventIterator it = eventSet.eventIterator();
+                
+                boolean examineSaidSkipUpdates = false;
+                boolean gotBPEvent = false;
+                
+                while (it.hasNext()) {
+                    Event ev = it.nextEvent();
+                    
+                    examineSaidSkipUpdates |= screenEvent(ev);
+                    
+                    // for breakpoint and step events, we may want
+                    // to leave the relevant thread suspended. If the dontResume
+                    // property for the event is set, then lets do this.
+                    if(ev.request() != null) {
+                        if(addToSuspendCount && ev.request().getProperty(DONT_RESUME) != null) {
+                            if(ev instanceof LocatableEvent) {
+                                LocatableEvent le = (LocatableEvent) ev;
+                                le.thread().suspend();
+                                addToSuspendCount = false;
+                                // a step and breakpoint can be hit at the same
+                                // time - make sure to only suspend once
+                                gotBPEvent |= (ev instanceof BreakpointEvent);
+                            }
+                        }
+                    }
+                }
+            
+                // Now go through again to do proper processing:
+                it = eventSet.eventIterator();
+                while (it.hasNext()) {
+                    Event ev = it.nextEvent();
+                    
+                    // do some processing with this event
+                    // this calls back into VMReference
+                    handleEvent(ev, examineSaidSkipUpdates, gotBPEvent);
+                }
+                
+                // resume the VM
+                eventSet.resume();
+            }
+            catch (InterruptedException exc) { }
+            catch (VMDisconnectedException discExc) { exiting = true; }
+        }
+    }
+    
+    /**
+     * Deliver thread halted/resumed events.
+     */
+    private synchronized void handleThreadEvents()
+    {
+        ThreadEvent halted = haltedThreads.poll();
+        while (halted != null) {
+            if (halted.state) {
+                vm.threadHaltedEvent(halted.thread);
+            }
+            else {
+                vm.threadResumedEvent(halted.thread);
+            }
+            halted = haltedThreads.poll();
+        }
+    }
+    
+    /**
+     * Emit a thread halted/resumed event.
+     * 
+     * @param thr   The thread for which the event occurred
+     * @param halted  True if the thread was halted, false if resumed
+     */
+    public synchronized void emitThreadEvent(JdiThread thr, boolean halted)
+    {
+        haltedThreads.add(new ThreadEvent(thr, halted));
+        if (queueEmpty) {
+            // The VM event handler thread is either waiting for an event,
+            // or it has just pulled one but has yet to set queueEmpty = false,
+            // which it will only do while synched.
+            interrupt();
+        }
+    }
+    
+    /**
+     * Wait until the event queue is empty (all pending events have been dispatched).
+     */
+    public void waitQueueEmpty()
+    {
+        synchronized (this) {
+            try {
+                while (! queueEmpty) {
+                    wait();
+                }
+            }
+            catch (InterruptedException ie) {}
+        }
+    }
+    
+    private static int getStepType(StepEvent ev)
+    {
+        EventRequest req = ev.request();
+        if (req instanceof StepRequest)
+        {
+            int stepDepth = ((StepRequest)req).depth();
+            
+            if (stepDepth == StepRequest.STEP_INTO)
+                return DebuggerEvent.THREAD_HALT_STEP_INTO;
+            else if (stepDepth == StepRequest.STEP_OVER)
+                return DebuggerEvent.THREAD_HALT_STEP_OVER;
+            // Otherwise, fall-through:
+        }
+        
+        return DebuggerEvent.THREAD_HALT_UNKNOWN;
+    }
+    
+    private boolean screenEvent(Event event)
+    {
+        if (event instanceof BreakpointEvent) {
+            return vm.screenBreakpointEvent((LocatableEvent)event, DebuggerEvent.THREAD_BREAKPOINT);
+        } else if (event instanceof StepEvent) {
+            return vm.screenBreakpointEvent((LocatableEvent)event, getStepType((StepEvent)event));
+        }
+        return false;
+    }
+        
+    private void handleEvent(Event event, boolean skipUpdate, boolean gotBP)
+    {
+        if (event instanceof VMStartEvent) {
+            vm.vmStartEvent((VMStartEvent) event);
+        } else if (event instanceof VMDeathEvent) {
+            // vm.vmExitEvent();
+        } else if (event instanceof VMDisconnectEvent) {
+            vm.vmDisconnectEvent();
+        } else if (event instanceof ExceptionEvent) {
+            vm.exceptionEvent((ExceptionEvent)event);
+        } else if (event instanceof BreakpointEvent) {
+            vm.breakpointEvent((LocatableEvent)event, DebuggerEvent.THREAD_BREAKPOINT, skipUpdate);
+        } else if (event instanceof StepEvent) {
+            // If we get a step and hit a breakpoint at the same time,
+            // we only report the breakpoint.
+            if (! gotBP) {
+                vm.breakpointEvent((LocatableEvent)event, getStepType((StepEvent)event), skipUpdate);
+            }
+        } else if (event instanceof ThreadStartEvent) {
+            vm.threadStartEvent((ThreadStartEvent)event);
+        } else if (event instanceof ThreadDeathEvent) {
+            vm.threadDeathEvent((ThreadDeathEvent)event);
+        } else if (event instanceof ClassPrepareEvent) {
+            classPrepareEvent(event);
+        } else {
+            //Debug.message("[VM event] unhandled: " + event);
+        }
+    }
+    
+    private boolean classPrepareEvent(Event event)
+    {
+        ClassPrepareEvent cle = (ClassPrepareEvent)event;
+        ReferenceType refType = cle.referenceType();
+        
+        if(refType.name().equals(VMReference.SERVER_CLASSNAME)) {
+            vm.serverClassPrepared();
+        }
+        return true;
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/VMReference.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/VMReference.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1331e45b809b95abadcc3e59eb42b3901cf2f95
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugger/jdi/VMReference.java
@@ -0,0 +1,2165 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugger.jdi;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.InetAddress;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import bluej.Boot;
+import bluej.Config;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerEvent;
+import bluej.debugger.DebuggerEvent.BreakpointProperties;
+import bluej.debugger.DebuggerResult;
+import bluej.debugger.DebuggerTerminal;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugger.SourceLocation;
+import bluej.runtime.ExecServer;
+import bluej.utility.Debug;
+import bluej.utility.Utility;
+
+import com.sun.jdi.AbsentInformationException;
+import com.sun.jdi.ArrayReference;
+import com.sun.jdi.ArrayType;
+import com.sun.jdi.Bootstrap;
+import com.sun.jdi.ClassLoaderReference;
+import com.sun.jdi.ClassNotLoadedException;
+import com.sun.jdi.ClassObjectReference;
+import com.sun.jdi.ClassType;
+import com.sun.jdi.Field;
+import com.sun.jdi.IncompatibleThreadStateException;
+import com.sun.jdi.IntegerValue;
+import com.sun.jdi.InvalidTypeException;
+import com.sun.jdi.InvocationException;
+import com.sun.jdi.Location;
+import com.sun.jdi.Method;
+import com.sun.jdi.ObjectCollectedException;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.StringReference;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.VMMismatchException;
+import com.sun.jdi.Value;
+import com.sun.jdi.VirtualMachine;
+import com.sun.jdi.VirtualMachineManager;
+import com.sun.jdi.connect.Connector;
+import com.sun.jdi.connect.Connector.Argument;
+import com.sun.jdi.connect.ListeningConnector;
+import com.sun.jdi.event.ExceptionEvent;
+import com.sun.jdi.event.LocatableEvent;
+import com.sun.jdi.event.ThreadDeathEvent;
+import com.sun.jdi.event.ThreadStartEvent;
+import com.sun.jdi.event.VMStartEvent;
+import com.sun.jdi.request.BreakpointRequest;
+import com.sun.jdi.request.ClassPrepareRequest;
+import com.sun.jdi.request.EventRequest;
+import com.sun.jdi.request.EventRequestManager;
+
+/**
+ * A class implementing the execution and debugging primitives needed by BlueJ.
+ * 
+ * <p>Execution and debugging is implemented here on a second ("remote") virtual
+ * machine, which gets started from here via the JDI interface.
+ * 
+ * <p>The startup process is as follows:
+ * 
+ * <ol>
+ * <li>Debugger spawns a MachineLoaderThread which begins to load the debug vm
+ *    Any access to the debugger during this time uses getVM() which waits
+ *    for the machine to be loaded.
+ *    (see JdiDebugger.MachineLoaderThread).
+ * <li>The MachineLoaderThread creates a VMReference representing the vm. The
+ *    VMReference in turn creates a VMEventHandler to receive events from the
+ *    debug VM.
+ * <li>A "ClassPrepared" event is received telling BlueJ that the ExecServer
+ *    class has been loaded. At this point, breakpoints are set in certain
+ *    places within the server class. Execution in the debug VM continues.
+ * <li>The ExecServer "main" method spawns two threads. One is the "server"
+ *    thread used to run user code. The "worker" thread is used for helper
+ *    functions which do not execute user code paths. Both threads hit the
+ *    breakpoints which have been set. This causes a breakpoint event to occur.
+ * <li>The breakpoint events are trapped. When the server thread hits the
+ *    "vmStarted" breakpoint, the VM is considered to be started.
+ * </ol>
+ * 
+ * <p>We can now execute commands on the remote VM by invoking methods using the
+ * server thread (which is suspended at the breakpoint). 
+ * 
+ * <p>Non-user code used by BlueJ is run a separate "worker" thread.
+ * 
+ * @author Michael Kolling
+ */
+class VMReference
+{
+    // the class name of the execution server class running on the remote VM
+    static final String SERVER_CLASSNAME = ExecServer.class.getName();
+
+    // the name of the method used to suspend the ExecServer
+    static final String SERVER_STARTED_METHOD_NAME = "vmStarted";
+
+    // the name of the method used to suspend the ExecServer
+    static final String SERVER_SUSPEND_METHOD_NAME = "vmSuspend";
+
+    // A map which can be used to map instances of VirtualMachine to VMReference 
+    private static Map<VirtualMachine, VMReference> vmToReferenceMap = new HashMap<VirtualMachine, VMReference>();
+    
+    // ==== instance data ====
+
+    // we have a tight coupling between us and the JdiDebugger
+    // that creates us
+    private JdiDebugger owner = null;
+
+    // The remote virtual machine and process we are referring to
+    private VirtualMachine machine = null;
+    private Process remoteVMprocess = null;
+
+    // The handler for virtual machine events
+    private VMEventHandler eventHandler = null;
+
+    // the class reference to ExecServer
+    private ClassType serverClass = null;
+
+    // the thread running inside the ExecServer
+    private ThreadReference serverThread = null;
+    private boolean serverThreadStarted = false;
+
+    // the worker thread running inside the ExecServer
+    private ThreadReference workerThread = null;
+    private boolean workerThreadReady = false;
+    private boolean workerThreadReserved = false;
+
+    // a record of the threads we start up for
+    // redirecting ExecServer streams
+    private IOHandlerThread inputStreamRedirector = null;
+    private IOHandlerThread outputStreamRedirector = null;
+    private IOHandlerThread errorStreamRedirector = null;
+
+    // the current class loader in the ExecServer
+    private ClassLoaderReference currentLoader = null;
+
+    private int exitStatus;
+    private ExceptionDescription lastException;
+    
+    // array index of memory transport parameter 
+    private int transportIndex = 0;
+    
+    private boolean isDefaultEncoding = true;
+    private String streamEncoding = null;
+
+    /**
+     * Launch a remote debug VM using a TCP/IP socket.
+     * 
+     * @param initDir
+     *            the directory to have as a current directory in the remote VM
+     * @param libraries
+     *            libraries to be added to the VM startup classpath
+     * @param mgr
+     *            the virtual machine manager
+     * @return an instance of a VirtualMachine or null if there was an error
+     */
+    public VirtualMachine localhostSocketLaunch(File initDir, URL[] libraries, DebuggerTerminal term,
+            VirtualMachineManager mgr)
+    {
+        final int CONNECT_TRIES = 2; // try to connect max of 5 times
+        final int CONNECT_WAIT = 500; // wait half a sec between each connect
+
+        String [] launchParams;
+
+        // launch the VM using the runtime classpath.
+        Boot boot = Boot.getInstance();
+        File [] filesPath = Utility.urlsToFiles(boot.getRuntimeUserClassPath());
+        File [] libraryPaths = Utility.urlsToFiles(libraries);
+        File [] classPath = new File[filesPath.length + libraryPaths.length];
+        System.arraycopy(filesPath, 0, classPath, 0, filesPath.length);
+        System.arraycopy(libraryPaths, 0, classPath, filesPath.length, libraryPaths.length);
+        String allClassPath = Utility.toClasspathString(classPath);
+        
+        ArrayList<String> paramList = new ArrayList<String>(10);
+        paramList.add(Config.getJDKExecutablePath(null, "java"));
+        
+        //check if any vm args are specified in Config, at the moment these
+        //are only Locale options: user.language and user.country
+        
+        paramList.addAll(Config.getDebugVMArgs());
+        
+        paramList.add("-classpath");
+        paramList.add(allClassPath);
+        if (Config.isMacOS()) {
+            paramList.add("-Xdock:icon=" + Config.getBlueJIconPath() + "/" + Config.getVMIconsName());
+            paramList.add("-Xdock:name=" + Config.getVMDockName());
+        }
+        
+        // Index for where the transport parameter is to be added
+        transportIndex = paramList.size();
+        paramList.add(SERVER_CLASSNAME);
+        
+        // set output encoding if specified, default is to use system default
+        // this gets passed to ExecServer's main as an arg which can then be 
+        // used to specify encoding
+        streamEncoding = Config.getPropString("bluej.terminal.encoding", null);
+        isDefaultEncoding = (streamEncoding == null);
+        if(!isDefaultEncoding) {
+            paramList.add(streamEncoding);
+        }
+        
+        String transport = Config.getPropString("bluej.vm.transport", "dt_socket");
+        
+        List<ListeningConnector> connectors = new ArrayList<ListeningConnector>(mgr.listeningConnectors());
+
+        // find the known connectors - order them by preference:
+        Iterator<ListeningConnector> it = connectors.iterator();
+        while (it.hasNext()) {
+            ListeningConnector c = it.next();
+            if (c.transport().name().equals(transport)) {
+                // We've found the preferred connector
+                it.remove();
+                connectors.add(0, c);
+                break;
+            }
+        }
+        
+        Throwable [] failureReasons = new Throwable[connectors.size()];
+        
+        for (int i = 0; i < CONNECT_TRIES; i++) {
+            for (int j = 0; j < connectors.size(); j++) {
+                ListeningConnector connector = connectors.get(j);
+                try {
+                    // Set up connection arguments
+                    Map<String, Argument> arguments = connector.defaultArguments();
+                    Connector.Argument timeoutArg = arguments.get("timeout");
+                    if (timeoutArg != null) {
+                        // The timeout appears to be in milliseconds.
+                        // The default is apparently no timeout.
+                        timeoutArg.setValue("5000");
+                    }
+                    
+                    // Make sure the local address is localhost, not the
+                    // machine name, as using the machine name causes problems on some systems
+                    // when the network is disconnected (because the machine name binds to
+                    // the network IP, not to localhost):
+                    String listenAddress = null;
+                    if (connector.transport().name().equals("dt_socket") && arguments.containsKey("localAddress"))
+                    {
+                        listenAddress = InetAddress.getByName(null).getHostAddress();
+                        arguments.get("localAddress").setValue(listenAddress);
+                    }
+                    
+                    // Listening connectors can only listen on one address at a time -
+                    // Synchronize to prevent problems.
+                    synchronized (connector) {
+                        String address = connector.startListening(arguments);
+                        if (listenAddress != null) {
+                            // It seems the address name returned by connector.startListening(...) may be the host name,
+                            // even though we specifically asked for localhost. So here we'll force it to the localhost
+                            // IP address:
+                            int colonIndex = address.lastIndexOf(':');
+                            if (colonIndex != -1) {
+                                address = listenAddress + address.substring(colonIndex);
+                            }
+                        }
+                        Debug.log("" + System.currentTimeMillis() + ": Listening for JDWP connection on address: " + address);
+                        paramList.add(transportIndex, "-agentlib:jdwp=transport=" + connector.transport().name()
+                                + ",address=" + address);
+                        launchParams = paramList.toArray(new String[paramList.size()]);
+                        paramList.remove(transportIndex);
+                        
+                        try {
+                            remoteVMprocess = launchVM(initDir, launchParams);
+                        }
+                        catch (Throwable t) {
+                            connector.stopListening(arguments);
+                            throw t;
+                        }
+
+                        try {
+                            machine = connector.accept(arguments);
+                            redirectToTerminal(term);
+                        }
+                        catch (Throwable t) {
+                            // failed to connect.
+                            closeIO();
+                            try {
+                                // Ask for the exit value, since that allows us to test
+                                // whether the process has already exited.
+                                int exitCode = remoteVMprocess.exitValue();
+                                Debug.log("" + System.currentTimeMillis() + ": remote VM process has prematurely terminated with exit code: " + exitCode);
+                                drainOutput();
+                            }
+                            catch (IllegalThreadStateException itse) {}
+                            remoteVMprocess.destroy();
+                            remoteVMprocess = null;
+                            throw t;
+                        }
+                        finally {
+                            connector.stopListening(arguments);
+                        }
+                    }
+                    
+                    Debug.log("Connected to debug VM via " + connector.transport().name() + " transport...");
+                    setupEventHandling();
+                    if (waitForStartup()) {
+                        Debug.log("Communication with debug VM fully established.");
+                        return machine;
+                    }
+                    else {
+                        Debug.log("Error: Debug VM not signalling startup.");
+                    }
+                }
+                catch(Throwable t) {
+                    failureReasons[j] = t;
+                }
+            }
+            
+            // Do a small wait between connection attempts
+            try {
+                if (i != CONNECT_TRIES - 1) {
+                    Thread.sleep(CONNECT_WAIT);
+                }
+            }
+            catch (InterruptedException ie) { break; }
+        }
+
+        // failed to connect
+        Writer dbgStream = Debug.getDebugStream();
+        synchronized (dbgStream) {
+            Debug.message("" + System.currentTimeMillis() + ": Failed to connect to debug VM. Reasons follow:");
+            for (int i = 0; i < connectors.size(); i++) {
+                Debug.message(connectors.get(i).transport().name() + " transport:");
+                PrintWriter pw = new PrintWriter(dbgStream);
+                failureReasons[i].printStackTrace(pw);
+                pw.flush();
+            }
+        }
+
+        NetworkTest.doTest();
+        
+        return null;
+    }
+    
+    /**
+     * Read and log anything that the remote VM process output before it died.
+     */
+    private void drainOutput()
+    {
+        InputStreamReader stdout = new InputStreamReader(remoteVMprocess.getInputStream());
+        char charBuf[] = new char[2048];
+        
+        try {
+            int numRead = stdout.read(charBuf);
+            if (numRead != -1) {
+                String output = new String(charBuf, 0, numRead);
+                Debug.message("Output from remote process stdout: " + output);
+            }
+            
+            InputStreamReader stderr = new InputStreamReader(remoteVMprocess.getErrorStream());
+            numRead = stderr.read(charBuf);
+            if (numRead != -1) {
+                String output = new String(charBuf, 0, numRead);
+                Debug.message("Output from remote process stderr: " + output);
+            }
+        }
+        catch (IOException ioe) {
+            Debug.message("IOException while trying to draing stdout/stderr of remote process: " + ioe.getMessage());
+        }
+    }
+    
+    private void setupEventHandling()
+    {
+        // indicate the events we want to receive
+        EventRequestManager erm = machine.eventRequestManager();
+        erm.createExceptionRequest(null, false, true).enable();
+        erm.createClassPrepareRequest().enable();
+        
+        EventRequest tsr = erm.createThreadStartRequest();
+        tsr.setSuspendPolicy(EventRequest.SUSPEND_NONE);
+        tsr.enable();
+        
+        tsr = erm.createThreadDeathRequest();
+        tsr.setSuspendPolicy(EventRequest.SUSPEND_NONE);
+        tsr.enable();
+
+        // start the VM event handler (will handle the VMStartEvent
+        // which will set the machine running)
+        eventHandler = new VMEventHandler(this, machine);
+    }
+
+    /**
+     * Launch the debug VM and set up the I/O connectors to the terminal.
+     * @param initDir   the directory which the vm should be started in
+     * @param params    the parameters (including executable as first param)
+     * @param line      a buffer which receives the first line of output from
+     *                  the debug vm process
+     * @param term      the terminal to connect to process I/O
+     */
+    private Process launchVM(File initDir, String [] params)
+        throws IOException
+    {    
+        Process vmProcess = Runtime.getRuntime().exec(params, null, initDir);
+        BufferedReader bro = new BufferedReader(new InputStreamReader(vmProcess.getInputStream()));
+        BufferedReader bre = new BufferedReader(new InputStreamReader(vmProcess.getErrorStream()));
+        
+        // grab anything else the VM spits out before we try to connect to it.
+        try {
+            
+            StringBuffer extraOut = new StringBuffer();
+            StringBuffer extraErr = new StringBuffer();
+            // Two streams to check: standard output and standard error
+                
+            char [] buf = new char[1024];
+            Thread.sleep(200); // A little extra time for initial output
+            for (int i = 0; i < 5; i++) {
+                Thread.sleep(200);
+                
+                // discontinue if no data available or stream closed
+                boolean keepReading = false;
+                if (bro.ready()) {
+                    int len = bro.read(buf);
+                    if (len != -1) {
+                        extraOut.append(buf, 0, len);
+                    }
+                    keepReading = true;
+                }
+                if (bre.ready()) {
+                    int len = bre.read(buf);
+                    if (len != -1) {
+                        extraErr.append(buf, 0, len);
+                    }
+                    keepReading = true;
+                }
+                
+                if (! keepReading) {
+                    break;
+                }
+            }
+            if (extraOut.length() != 0) {
+                Debug.message("Extra output from debug VM on launch:" + extraOut);
+            }
+            if (extraErr.length() != 0) {
+                Debug.message("Error output from debug VM on launch:" + extraErr);
+            }
+        }
+        catch (InterruptedException ie) {}
+        
+        
+        return vmProcess;
+    }
+    
+    /**
+     * Redirect input, output and error streams of the remote process to the terminal.
+     */
+    private void redirectToTerminal(DebuggerTerminal term) throws UnsupportedEncodingException
+    {
+        Process vmProcess = remoteVMprocess;
+        
+        // redirect standard streams from process to Terminal
+        // error stream System.err
+        Reader errorReader = null;
+        // output stream System.out
+        Reader outReader = null;
+        // input stream System.in
+        Writer inputWriter = null;
+        
+        if(isDefaultEncoding) {
+            errorReader = new InputStreamReader(vmProcess.getErrorStream());
+            outReader = new InputStreamReader(vmProcess.getInputStream());
+            inputWriter = new OutputStreamWriter(vmProcess.getOutputStream());            
+        }
+        // if specified in bluej.defs
+        else {
+            errorReader = new InputStreamReader(vmProcess.getErrorStream(), streamEncoding); 
+            outReader = new InputStreamReader(vmProcess.getInputStream(), streamEncoding);
+            inputWriter = new OutputStreamWriter(vmProcess.getOutputStream(), streamEncoding);
+        }
+        
+        errorStreamRedirector = redirectIOStream(errorReader, term.getErrorWriter());
+        outputStreamRedirector = redirectIOStream(outReader, term.getWriter());
+        inputStreamRedirector = redirectIOStream(term.getReader(), inputWriter);
+    }
+
+    /**
+     * Create the second virtual machine and start the execution server (class
+     * ExecServer) on that machine.
+     */
+    public VMReference(JdiDebugger owner, DebuggerTerminal term, File initialDirectory, URL[] libraries)
+        throws JdiVmCreationException
+    {
+        this.owner = owner;
+        
+        // machine will be suspended at startup
+        machine = localhostSocketLaunch(initialDirectory, libraries, term, Bootstrap.virtualMachineManager());
+        //machine = null; //uncomment to simulate inabilty to create debug VM
+        
+        if (machine == null) {
+            throw new JdiVmCreationException();
+        }
+        
+        // Add our machine into the map
+        vmToReferenceMap.put(machine, this);
+    }
+
+    /**
+     * Wait for all our virtual machine initialisation to occur.
+     */
+    public synchronized boolean waitForStartup()
+    {
+        serverThreadStartWait();
+        
+        if (! setupServerConnection(machine)) {
+            return false;
+        }
+        
+        return true;
+    }
+
+    /**
+     * Close down this virtual machine.
+     */
+    public synchronized void close()
+    {
+        if (machine != null) {
+            closeIO();
+            // cause the debug VM to exit when disposed
+            try {
+                setStaticFieldValue(serverClass, ExecServer.WORKER_ACTION_NAME, machine.mirrorOf(ExecServer.EXIT_VM));
+                machine.dispose();
+            }
+            catch(VMDisconnectedException vmde) {}
+        }
+    }
+
+    /**
+     * Close I/O redirectors.
+     */
+    public void closeIO()
+    {
+        // close our IO redirectors
+        if (inputStreamRedirector != null) {
+            inputStreamRedirector.close();
+            inputStreamRedirector.interrupt();
+        }
+
+        if (errorStreamRedirector != null) {
+            errorStreamRedirector.close();
+            errorStreamRedirector.interrupt();
+        }
+
+        if (outputStreamRedirector != null) {
+            outputStreamRedirector.close();
+            outputStreamRedirector.interrupt();
+        }
+    }
+
+    /**
+     * This method is called by the VMEventHandler when the execution server
+     * class (ExecServer) has been loaded into the VM. We use this to set a
+     * breakpoint in the server class. This is really still part of the
+     * initialisation process.
+     */
+    void serverClassPrepared()
+    {
+        // remove the "class prepare" event request (not needed anymore)
+
+        EventRequestManager erm = machine.eventRequestManager();
+        List<ClassPrepareRequest> list = erm.classPrepareRequests();
+        erm.deleteEventRequests(list);
+
+        try {
+            serverClass = (ClassType) findClassByName(SERVER_CLASSNAME, null);
+        }
+        catch (ClassNotFoundException cnfe) {
+            throw new IllegalStateException("can't find class " + SERVER_CLASSNAME + " in debug virtual machine");
+        }
+
+        // add the breakpoints (these may be cleared later on and so will
+        // need to be readded)
+        serverClassAddBreakpoints();
+    }
+    
+    private Location findMethodLocation(ReferenceType classType, String methodName)
+    {
+        Method method = findMethodByName(classType, methodName);
+        if (method == null) {
+            throw new IllegalStateException("can't find method " + classType.name() + "."
+                    + methodName);
+        }
+        return method.location();
+    }
+
+    /**
+     * This breakpoint is used to stop the server process to make it wait for
+     * our task signals. (We later use the suspended process to perform our task
+     * requests.)
+     */
+    private void serverClassAddBreakpoints()
+    {
+        EventRequestManager erm = machine.eventRequestManager();
+
+        // set a breakpoint in the vm started method
+        {
+            BreakpointRequest serverBreakpoint = erm.createBreakpointRequest(findMethodLocation(serverClass, SERVER_STARTED_METHOD_NAME));
+            serverBreakpoint.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+            // the presence of this property indicates to breakEvent that we are
+            // a special type of breakpoint
+            serverBreakpoint.putProperty(SERVER_STARTED_METHOD_NAME, "yes");
+            serverBreakpoint.putProperty(VMEventHandler.DONT_RESUME, "yes");
+            serverBreakpoint.putProperty(Debugger.PERSIST_BREAKPOINT_PROPERTY, "yes");
+            serverBreakpoint.enable();
+        }
+
+        // set a breakpoint in the suspend method
+        {
+            BreakpointRequest workerBreakpoint = erm.createBreakpointRequest(findMethodLocation(serverClass, SERVER_SUSPEND_METHOD_NAME));
+            workerBreakpoint.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+            // the presence of this property indicates to breakEvent that we are
+            // a special type of breakpoint
+            workerBreakpoint.putProperty(SERVER_SUSPEND_METHOD_NAME, "yes");
+            // the presence of this property indicates that we should not
+            // be restarted after receiving this event
+            workerBreakpoint.putProperty(VMEventHandler.DONT_RESUME, "yes");
+            workerBreakpoint.putProperty(Debugger.PERSIST_BREAKPOINT_PROPERTY, "yes");
+            workerBreakpoint.enable();
+        }
+
+    }
+
+    /**
+     * Find the components on the remote VM that we need to talk to it: the
+     * execServer object, the performTaskMethod, and the serverThread. These
+     * three variables (mirrors to the remote entities) are set up here. This
+     * needs to be done only once.
+     */
+    private boolean setupServerConnection(VirtualMachine vm)
+    {
+        if (serverClass == null) {
+            Debug.reportError("server class not initialised!");
+            return false;
+        }
+
+        // get our main server thread
+        // serverThread = (ThreadReference) getStaticFieldObject(serverClass, ExecServer.MAIN_THREAD_NAME);
+
+        // get our worker thread
+        workerThread = (ThreadReference) getStaticFieldObject(serverClass, ExecServer.WORKER_THREAD_NAME);
+
+        if (serverThread == null || workerThread == null) {
+            Debug.reportError("Cannot find fields on remote VM");
+            return false;
+        }
+
+        //Debug.message(" connection to remote VM established");
+        return true;
+    }
+
+    // -- all methods below here are for after the VM has started up
+
+    /**
+     * Instruct the remote machine to construct a new class loader and return its
+     * reference.
+     * 
+     * May throw VMDisconnectedException.
+     * 
+     * @param urls  the classpath as an array of URL
+     */
+    ClassLoaderReference newClassLoader(URL [] urls)
+    {
+        synchronized(workerThread) {
+            workerThreadReadyWait();
+            workerThreadReserved = true;
+            setStaticFieldValue(serverClass, ExecServer.WORKER_ACTION_NAME, machine.mirrorOf(ExecServer.NEW_LOADER));
+            
+            StringBuffer newcpath = new StringBuffer(200);
+            for (int index = 0; index < urls.length; index++) {
+                newcpath.append ( urls[index].toString());
+                newcpath.append ('\n');
+            }
+            
+            setStaticFieldObject(serverClass, ExecServer.CLASSPATH_NAME, newcpath.toString());
+            
+            workerThreadReady = false;
+            workerThread.resume();
+            workerThreadFinishWait();
+            
+            currentLoader = (ClassLoaderReference) getStaticFieldObject(serverClass, ExecServer.WORKER_RETURN_NAME);
+            workerThreadReserved = false;
+            workerThread.notify();
+            
+            return currentLoader;
+        }
+    }
+    
+    /**
+     * Get an ObjectReference mirroring a String. May throw
+     * VMDisconnectedException, VMOutOfMemoryException.
+     * 
+     * @param value  The string to mirror on the remote VM.
+     * @return       The mirror object
+     */
+    public StringReference getMirror(String value)
+    {
+        return machine.mirrorOf(value);
+    }
+    
+    /**
+     * Load a class in the remote machine and return its reference. Note that
+     * this function never returns null.
+     * 
+     * @return a Reference to the class mirrored in the remote VM
+     * @throws ClassNotFoundException  if the remote class can't be loaded
+     */
+    ReferenceType loadClass(String className)
+        throws ClassNotFoundException
+    {
+        ReferenceType rt = loadClass(className, null);
+        if (rt == null) {
+            throw new ClassNotFoundException(className);
+        }
+        return rt;
+    }
+    
+    /**
+     * Load a class in the remote VM using the given class loader.
+     * @param className  The name of the class to load
+     * @param clr        The remote classloader reference to use, or null to use
+     *                   the current established project classloader
+     * @return     A reference to the loaded class, or null if the class could not be loaded.
+     */
+    ReferenceType loadClass(String className, ClassLoaderReference clr)
+    {
+        synchronized(workerThread) {
+            workerThreadReadyWait();
+            workerThreadReserved = true;
+            setStaticFieldValue(serverClass, ExecServer.CLASSLOADER_NAME, clr);
+            setStaticFieldValue(serverClass, ExecServer.WORKER_ACTION_NAME, machine.mirrorOf(ExecServer.LOAD_CLASS));
+            setStaticFieldObject(serverClass, ExecServer.CLASSNAME_NAME, className);
+            
+            workerThreadReady = false;
+            workerThread.resume();
+            workerThreadFinishWait();
+            
+            ClassObjectReference robject = (ClassObjectReference) getStaticFieldObject(serverClass, ExecServer.WORKER_RETURN_NAME);
+            workerThreadReserved = false;
+            workerThread.notify();
+            
+            if (robject == null) {
+                return null;
+            }
+            
+            return robject.reflectedType();
+        }
+    }
+    
+    /**
+     * Load and initialize a class in the remote machine, and return a reference to it.
+     * Initialization causes static initializer assignments and blocks to be executed in
+     * the remote machine. This method will not return until all such blocks have completed
+     * execution.
+     * 
+     * @param className  The name of the class to load
+     * @return           A reference to the class
+     * @throws ClassNotFoundException  If the class could not be found
+     */
+    ReferenceType loadInitClass(String className)
+        throws ClassNotFoundException
+    {
+        try {
+            serverThreadStartWait();
+            
+            // Store the class and method to call
+            setStaticFieldObject(serverClass, ExecServer.CLASS_TO_RUN_NAME, className);
+            setStaticFieldValue(serverClass, ExecServer.EXEC_ACTION_NAME, machine.mirrorOf(ExecServer.LOAD_INIT_CLASS));
+            
+            // Resume the thread, wait for it to finish and the new thread to start
+            serverThreadStarted = false;
+            resumeServerThread();
+            serverThreadStartWait();
+            
+            // Get return value
+            ClassObjectReference rval = (ClassObjectReference) getStaticFieldObject(serverClass, ExecServer.METHOD_RETURN_NAME);
+            if (rval == null)
+                throw new ClassNotFoundException("Remote class not found: " + className);
+            
+            // check for and report exceptions which occurred during initialization
+            ObjectReference exception = getStaticFieldObject(serverClass, ExecServer.EXCEPTION_NAME);
+            if (exception != null) {
+                exceptionEvent(new InvocationException(exception));
+            }
+            
+            return rval.reflectedType();
+        }
+        catch (VMDisconnectedException vde) {
+            throw new ClassNotFoundException("Remote class not loaded due to VM termination.");
+        }
+    }
+
+    /**
+     * "Start" a class (i.e. invoke its main method)
+     * 
+     * @param loader
+     *            the class loader to use
+     * @param classname
+     *            the class to start
+     * @param eventParam
+     *            when a BlueJEvent is generated for a breakpoint, this
+     *            parameter is passed as the event parameter
+     */
+    public DebuggerResult runShellClass(String className)
+    {
+        // Calls to this method are protected by serverThreadLock in JdiDebugger
+        
+        // Debug.message("[VMRef] starting " + className);
+        // ** call Shell.run() **
+        try {
+            exitStatus = Debugger.NORMAL_EXIT;
+
+            serverThreadStartWait();
+            
+            // Store the class and method to call
+            setStaticFieldObject(serverClass, ExecServer.CLASS_TO_RUN_NAME, className);
+            setStaticFieldValue(serverClass, ExecServer.EXEC_ACTION_NAME, machine.mirrorOf(ExecServer.EXEC_SHELL));
+            
+            // Resume the thread, wait for it to finish and the new thread to start
+            serverThreadStarted = false;
+            resumeServerThread();
+            serverThreadStartWait();
+            
+            // Get return value and check for exceptions
+            ObjectReference rval = getStaticFieldObject(serverClass, ExecServer.METHOD_RETURN_NAME);
+            if (rval == null) {
+                ObjectReference exception = getStaticFieldObject(serverClass, ExecServer.EXCEPTION_NAME);
+                if (exception != null) {
+                    exceptionEvent(new InvocationException(exception));
+                    return new DebuggerResult(lastException);
+                }
+            }
+            
+            ObjectReference objR = getStaticFieldObject(serverClass, ExecServer.METHOD_RETURN_NAME);
+            JdiObject robj = JdiObject.getDebuggerObject(objR);
+            return new DebuggerResult(robj);
+        }
+        catch (VMDisconnectedException e) {
+            exitStatus = Debugger.TERMINATED;
+            return new DebuggerResult(exitStatus);
+        }
+        catch (Exception e) {
+            // remote invocation failed
+            Debug.reportError("starting shell class failed: " + e);
+            e.printStackTrace();
+            exitStatus = Debugger.EXCEPTION;
+            lastException = new ExceptionDescription("Internal BlueJ error: unexpected exception in remote VM\n" + e);
+        }
+        
+        return new DebuggerResult(lastException);
+    }
+    
+    /**
+     * Invoke the default constructor for some class, and return the resulting object.
+     */
+    public DebuggerResult instantiateClass(String className)
+    {
+        ObjectReference obj = null;
+        exitStatus = Debugger.NORMAL_EXIT;
+        try {
+            obj = invokeConstructor(className);
+        }
+        catch (VMDisconnectedException e) {
+            exitStatus = Debugger.TERMINATED;
+            // return null; // debugger state change handled elsewhere
+            return new DebuggerResult(Debugger.TERMINATED);
+        }
+        catch (Exception e) {
+            // remote invocation failed
+            Debug.reportError("starting shell class failed: " + e);
+            e.printStackTrace();
+            exitStatus = Debugger.EXCEPTION;
+            lastException = new ExceptionDescription("Internal BlueJ error: unexpected exception in remote VM\n" + e);
+        }
+        if (obj == null) {
+            return new DebuggerResult(lastException);
+        }
+        else {
+            return new DebuggerResult(JdiObject.getDebuggerObject(obj));
+        }
+    }
+
+    /**
+     * Invoke a particular constructor with arguments. The parameter types
+     * of the constructor must be supplied (String[]) as well as the
+     * argument values (ObjectReference []).
+     * 
+     * @param className  The name of the class to construct an instance of
+     * @param paramTypes The parameter types of the constructor (class names)
+     * @param args      The argument values to use in the constructor call
+     * 
+     * @return  The newly constructed object (or null if error/exception
+     *          occurs)
+     */
+    public DebuggerResult instantiateClass(String className, String [] paramTypes, ObjectReference [] args)
+    {
+        ObjectReference obj = null;
+        exitStatus = Debugger.NORMAL_EXIT;
+        try {
+            obj = invokeConstructor(className, paramTypes, args);
+        }
+        catch (VMDisconnectedException e) {
+            exitStatus = Debugger.TERMINATED;
+            return new DebuggerResult(exitStatus); // debugger state change handled elsewhere 
+        }
+        catch (Exception e) {
+            // remote invocation failed
+            Debug.reportError("starting shell class failed: " + e);
+            e.printStackTrace();
+            exitStatus = Debugger.EXCEPTION;
+            lastException = new ExceptionDescription("Internal BlueJ error: unexpected exception in remote VM\n" + e);
+        }
+        if (obj == null) {
+            return new DebuggerResult(lastException);
+        }
+        else {
+            return new DebuggerResult(JdiObject.getDebuggerObject(obj));
+        }
+    }
+    
+    /**
+     * Emit a thread halted/resumed event for the given thread.
+     */
+    public void emitThreadEvent(JdiThread thread, boolean halted)
+    {
+        eventHandler.emitThreadEvent(thread, halted);
+    }
+    
+    /**
+     * Return the status of the last invocation. One of (NORMAL_EXIT,
+     * FORCED_EXIT, EXCEPTION, TERMINATED).
+     * 
+     * (?? Question: What is the difference between "FORCED_EXIT" and
+     *  "TERMINATED"? We only seem to use the latter -dm)
+     */
+    public int getExitStatus()
+    {
+        return exitStatus;
+    }
+
+    /**
+     * Return the text of the last exception.
+     */
+    public ExceptionDescription getException()
+    {
+        return lastException;
+    }
+
+    /**
+     * The VM has reached its startup point.
+     */
+    public void vmStartEvent(VMStartEvent vmse)
+    {
+        serverThreadStarted = false;
+    }
+
+    /**
+     * The VM has been disconnected or ended.
+     */
+    public void vmDisconnectEvent()
+    {
+        synchronized (this) {
+            // Do the owner disconnect first, because it is synchronized on
+            // JdiDebugger. This allows machine loader thread to check the exit
+            // status in a meaningful way.
+            owner.vmDisconnect();
+            
+            // If VM disconnect occurs during invocation, the server thread won't
+            // restart in this VM; the method waiting for it to start will hang
+            // indefinitely unless we kick it here.
+            exitStatus = Debugger.TERMINATED;
+            if (!serverThreadStarted) {
+                notifyAll();
+            }
+        }
+        
+        if (workerThread != null) {
+            synchronized (workerThread) {
+                if (!workerThreadReady)
+                    workerThread.notifyAll();
+            }
+        }
+
+        synchronized (vmToReferenceMap) {
+            vmToReferenceMap.remove(machine);
+        }
+    }
+
+    /**
+     * A thread has started.
+     */
+    public void threadStartEvent(ThreadStartEvent tse)
+    {
+        owner.threadStart(tse.thread());
+    }
+
+    /**
+     * A thread has died.
+     */
+    public void threadDeathEvent(ThreadDeathEvent tde)
+    {
+        ThreadReference tr = tde.thread();
+        owner.threadDeath(tr);
+
+        // There appears to be a VM bug related to system.exit() being called
+        // in an invocation thread. The event is only seen as a thread death.
+        // Only affects some platforms/vm versions some of the time.
+        //if (tr == serverThread && serverThreadStarted || tr == workerThread)
+        //    close();
+    }
+    
+    /**
+     * A thread has been suspended (due to a breakpoint, step, or
+     * call to DebuggerThread.halt()).
+     */
+    public void threadHaltedEvent(JdiThread thread)
+    {
+        owner.threadHalted(thread);
+    }
+    
+    /**
+     * A thread has been resumed.
+     */
+    public void threadResumedEvent(JdiThread thread)
+    {
+        owner.threadResumed(thread);
+    }
+
+    /**
+     * An exception has occurred in a thread.
+     * 
+     * It doesn't really make sense to do anything here. Any exception which occurs
+     * in the primary execution thread does not come through here.
+     */
+    public void exceptionEvent(ExceptionEvent exc)
+    {
+        // ObjectReference remoteException = exc.exception();
+
+        // get the exception text
+        // attention: the following depends on the (undocumented) fact that
+        // the internal exception message field is named "detailMessage".
+        
+        // Field msgField = remoteException.referenceType().fieldByName("detailMessage");
+        // StringReference msgVal = (StringReference) remoteException.getValue(msgField);
+
+        // String exceptionText = (msgVal == null ? null : msgVal.value());
+        // String excClass = exc.exception().type().name();
+
+        // List<SourceLocation> stack = JdiThread.getStack(exc.thread());
+    }
+
+    /**
+     * Invoke an arbitrary method on an object, using the worker thread.
+     * If the called method exits via an exception, this method returns null.
+     * 
+     * @param o     The object to invoke the method on
+     * @param m     The method to invoke
+     * @param args  The arguments to pass to the method (List of Values)
+     * @return      The return Value from the method
+     */
+    private Value safeInvoke(ObjectReference o, Method m, List<? extends Value> args)
+    {
+        synchronized (workerThread) {
+            workerThreadReadyWait();
+            Value v = null;
+
+            try {
+                v = o.invokeMethod(workerThread, m, args, ObjectReference.INVOKE_SINGLE_THREADED);
+            }
+            catch (ClassNotLoadedException cnle) {}
+            catch (InvalidTypeException ite) {}
+            catch (IncompatibleThreadStateException itse) {}
+            catch (InvocationException ie) {}
+
+            return v;
+        }
+    }
+    
+    public void exceptionEvent(InvocationException exc)
+    {
+        List<Value> empty = new LinkedList<Value>();
+        
+        ObjectReference remoteException = exc.exception();
+        Field msgField = remoteException.referenceType().fieldByName("detailMessage");
+        StringReference msgVal = (StringReference) remoteException.getValue(msgField);
+        String exceptionText = (msgVal == null ? null : msgVal.value());
+        String excClass = exc.exception().type().name();
+        
+        ReferenceType remoteType = exc.exception().referenceType();
+        List<Method> getStackTraceMethods = remoteType.methodsByName("getStackTrace");
+        Method getStackTrace = (Method)getStackTraceMethods.get(0);
+        ArrayReference stackValue = (ArrayReference)safeInvoke(exc.exception(),  getStackTrace, empty);
+        
+        ObjectReference [] stackt = (ObjectReference [])stackValue.getValues().toArray(new ObjectReference[0]);
+        List<SourceLocation> stack = new LinkedList<SourceLocation>();
+        
+        // "stackt" is now an array of Values. Each Value represents a
+        // "StackTraceElement" object.
+        if (stackt.length > 0) {
+            ReferenceType StackTraceElementType = (ReferenceType)stackt[0].type();
+            Method getClassName = (Method)StackTraceElementType.methodsByName("getClassName").get(0);
+            Method getFileName = (Method)StackTraceElementType.methodsByName("getFileName").get(0);
+            Method getLineNum = (Method)StackTraceElementType.methodsByName("getLineNumber").get(0);
+            Method getMethodName = (Method)StackTraceElementType.methodsByName("getMethodName").get(0);
+            
+            for(int i = 0; i < stackt.length; i++) {
+                Value classNameV = safeInvoke(stackt[i], getClassName, empty);
+                Value fileNameV = safeInvoke(stackt[i], getFileName, empty);
+                Value methodNameV = safeInvoke(stackt[i], getMethodName, empty);
+                Value lineNumV = safeInvoke(stackt[i], getLineNum, empty);
+                
+                String className = ((StringReference)classNameV).value();
+                String fileName = null;
+                if (fileNameV != null) {
+                    fileName = ((StringReference)fileNameV).value();
+                }
+                String methodName = ((StringReference)methodNameV).value();
+                int lineNumber = ((IntegerValue)lineNumV).value();
+                stack.add(new SourceLocation(className,fileName,methodName,lineNumber));
+            }
+        }
+        
+        // stack is a list of SourceLocation (bluej.debugger.SourceLocation)
+        
+        exitStatus = Debugger.EXCEPTION;
+        lastException = new ExceptionDescription(excClass, exceptionText, stack);
+    }
+
+    
+    /**
+     * A breakpoint has been hit or step completed in a thread.
+     */
+    public void breakpointEvent(LocatableEvent event, int debuggerEventType, boolean skipUpdate)
+    {
+        // if the breakpoint is marked as with the SERVER_STARTED property
+        // then this is our own breakpoint that is used to detect when a new
+        // server thread has started (which happens at startup, and when user
+        // code completes execution).
+        if (event.request().getProperty(SERVER_STARTED_METHOD_NAME) != null) {
+            // wake up the waitForStartup() method
+            synchronized (this) {
+                serverThreadStarted = true;
+                serverThread = event.thread();
+                owner.raiseStateChangeEvent(Debugger.IDLE);
+                notifyAll();
+            }
+        }
+        // if the breakpoint is marked with the SERVER_SUSPEND property
+        // then it is the worker thread returning to its breakpoint
+        // after completing some work. We want to leave it suspended here until
+        // it is required to do more work.
+        else if (event.request().getProperty(SERVER_SUSPEND_METHOD_NAME) != null) {
+            
+            if (workerThread == null) {
+                workerThread = event.thread();
+            }
+            
+            synchronized (workerThread) {
+                workerThreadReady = true;
+                workerThread.notifyAll();
+            }
+        }
+        else {
+            // breakpoint set by user in user code
+            if (serverThread.equals(event.thread())) {
+                owner.raiseStateChangeEvent(Debugger.SUSPENDED);
+            }
+            
+            Location location = event.location();
+            String className = location.declaringType().name();
+            String fileName;
+            try {
+                fileName = location.sourceName();
+            }
+            catch (AbsentInformationException e) {
+                fileName = null;
+            }
+
+            // A breakpoint in the shell class or a BlueJ runtime class means that
+            // the user has stepped past the end of their own code
+            if (fileName != null && fileName.startsWith("__SHELL")
+                    || className != null && className.startsWith("bluej.runtime.")) {
+                event.thread().resume();
+                return;
+            }
+
+            // signal the breakpoint/step to the user
+            owner.breakpoint(event.thread(), debuggerEventType, skipUpdate, makeBreakpointProperties(event.request()));
+        }
+    }
+
+    private BreakpointProperties makeBreakpointProperties(final EventRequest request)
+    {
+        if (request == null)
+            return null;
+        else
+            return new DebuggerEvent.BreakpointProperties() {
+                public Object get(Object key)
+                {
+                    return request.getProperty(key);
+                }
+            };
+    }
+
+    public boolean screenBreakpointEvent(LocatableEvent event, int debuggerEventType)
+    {
+        return owner.screenBreakpoint(event.thread(), debuggerEventType, makeBreakpointProperties(event.request()));
+    }
+
+    // ==== code for active debugging: setting breakpoints, stepping, etc ===
+
+    /**
+     * Find and load all classes declared in the same source file as className
+     * and then find the Location object for the source at the line 'line'.
+     */
+    private Location loadClassesAndFindLine(String className, int line)
+    {
+        ReferenceType remoteClass = null;
+        try {
+            remoteClass = loadClass(className);
+        }
+        catch (ClassNotFoundException cnfe) {
+            return null;
+        }
+        List<ReferenceType> allTypesInFile = new ArrayList<ReferenceType>();
+
+        // find all ReferenceType's declared in this source file
+        buildNestedTypes(remoteClass, allTypesInFile);
+
+        Iterator<ReferenceType> it = allTypesInFile.iterator();
+        while (it.hasNext()) {
+            ReferenceType r = it.next();
+
+            try {
+                List<Location> list = r.locationsOfLine(line);
+                if (list.size() > 0)
+                    return (Location) list.get(0);
+            }
+            catch (AbsentInformationException aie) {}
+        }
+        return null;
+    }
+
+    /**
+     * Recursively construct a list of all Types started with rootType and
+     * including all its nested types.
+     * 
+     * @param rootType
+     *            the root to start building at
+     * @param l
+     *            the List to add the reference types to
+     */
+    private void buildNestedTypes(ReferenceType rootType, List<ReferenceType> l)
+    {
+        try {
+            synchronized(workerThread) {
+                workerThreadReadyWait();
+                workerThreadReserved = true;
+                setStaticFieldValue(serverClass, ExecServer.WORKER_ACTION_NAME, machine.mirrorOf(ExecServer.LOAD_ALL));
+                
+                // parameters
+                setStaticFieldObject(serverClass, ExecServer.CLASSNAME_NAME, rootType.name());
+                
+                workerThreadReady = false;
+                workerThread.resume();
+                
+                workerThreadFinishWait();
+                ObjectReference or = getStaticFieldObject(serverClass, ExecServer.WORKER_RETURN_NAME);
+                workerThreadReserved = false;
+                workerThread.notify();
+                
+                ArrayReference inners = (ArrayReference) or;
+                Iterator<Value> i = inners.getValues().iterator();
+                while (i.hasNext()) {
+                    ClassObjectReference cor = (ClassObjectReference) i.next();
+                    ReferenceType rt = cor.reflectedType();
+                    if (rt.isPrepared()) {
+                        l.add(rt);
+                    }
+                }
+            }
+        }
+        catch (VMDisconnectedException vmde) {}
+        catch (VMMismatchException vmmme) {}
+    }
+
+    /**
+     * Set a breakpoint at a specified line in a class.
+     * 
+     * @param className
+     *            The class in which to set the breakpoint.
+     * @param line
+     *            The line number of the breakpoint.
+     * @param properties The collection of properties to set on the breakpoint.  Can be null.
+     * @return null if there was no problem, or an error string
+     */
+    String setBreakpoint(String className, int line, Map<String, String> properties)
+    {
+        Location location = loadClassesAndFindLine(className, line);
+        if (location == null) {
+            return Config.getString("debugger.jdiDebugger.noCodeMsg");
+        }
+        EventRequestManager erm = machine.eventRequestManager();
+        BreakpointRequest bpreq = erm.createBreakpointRequest(location);
+        bpreq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+        bpreq.putProperty(VMEventHandler.DONT_RESUME, "yes");
+        if (properties != null) {
+            for (Map.Entry<String, String> property : properties.entrySet()) {
+                bpreq.putProperty(property.getKey(), property.getValue());
+            }
+        }
+        bpreq.enable();
+
+        return null;
+    }
+
+    String setBreakpoint(ReferenceType classType, int line, Map<String, String> properties)
+    {
+        try {
+            List<Location> locations = classType.locationsOfLine(line);
+            if (locations.isEmpty()) {
+                return Config.getString("debugger.jdiDebugger.noCodeMsg");
+            }
+
+            setBreakpoint(locations.get(0), properties);
+            return null;
+        }
+        catch (AbsentInformationException aie) {
+            return Config.getString("debugger.jdiDebugger.noCodeMsg");
+        }
+    }
+    
+    void setBreakpoint(Location location, Map<String,String> properties)
+    {
+        EventRequestManager erm = machine.eventRequestManager();
+        BreakpointRequest bpreq = erm.createBreakpointRequest(location);
+        bpreq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+        bpreq.putProperty(VMEventHandler.DONT_RESUME, "yes");
+        if (properties != null) {
+            for (Map.Entry<String, String> property : properties.entrySet()) {
+                bpreq.putProperty(property.getKey(), property.getValue());
+            }
+        }
+        bpreq.enable();
+    }
+    
+    // As above but sets the breakpoint on the first line of a given method
+    String setBreakpoint(String className, String methodName, Map<String, String> properties)
+    {
+        try {
+            loadClass(className);
+            ClassType classType = (ClassType)findClassByName(className);
+            Location loc = findMethodLocation(classType, methodName);
+            return setBreakpoint(className, loc.lineNumber(), properties);
+        } catch (ClassNotFoundException e) {
+            return "Could not find class: " + className; 
+        }
+    }
+    
+    String setBreakpoint(ReferenceType classType, String methodName, Map<String, String> properties)
+    {
+        Location loc = findMethodLocation(classType, methodName);
+        setBreakpoint(loc, properties);
+        return null;
+    }    
+    
+
+    /**
+     * Clear all the breakpoints at a specified line in a class.
+     * 
+     * @param className
+     *            The class in which to clear the breakpoints.
+     * @param line
+     *            The line number of the breakpoint.
+     * @return null if there was no problem, or an error string
+     */
+    String clearBreakpoint(String className, int line)
+    {
+        Location location = loadClassesAndFindLine(className, line);
+        if (location == null) {
+            return Config.getString("debugger.jdiDebugger.noCodeMsg");
+        }
+
+        return clearBreakpoint(location);
+    }
+    
+    // As above but clears the breakpoint in a given method (as set by the corresponding setBreakpoint method that takes a method name)
+    String clearBreakpoint(String className, String methodName)
+    {
+        try {
+            ClassType classType = (ClassType)findClassByName(className);
+            Location loc = findMethodLocation(classType, methodName);
+            return clearBreakpoint(loc);
+        }  catch (ClassNotFoundException e) {
+            return "Could not find class: " + className; 
+        }
+    }
+    
+    String clearBreakpoint(ReferenceType classType, String methodName)
+    {
+        Location loc = findMethodLocation(classType, methodName);
+        return clearBreakpoint(loc);
+    }
+    
+    String clearBreakpoint(Location location)
+    {
+        EventRequestManager erm = machine.eventRequestManager();
+        boolean found = false;
+        List<BreakpointRequest> list = erm.breakpointRequests();
+        for (int i = 0; i < list.size(); i++) {
+            BreakpointRequest bp = list.get(i);
+            if (bp.location().equals(location)) {
+                erm.deleteEventRequest(bp);
+                found = true;
+            }
+        }
+        // bp not found
+        if (found) {
+            return null;
+        }
+        else {
+            return Config.getString("debugger.jdiDebugger.noBreakpointMsg");
+        }
+    }
+
+    /**
+     * Return a list of the Locations of user breakpoints in the VM.
+     */
+    public List<Location> getBreakpoints()
+    {
+        // Debug.message("[VMRef] getBreakpoints()");
+
+        EventRequestManager erm = machine.eventRequestManager();
+        List<Location> breaks = new LinkedList<Location>();
+
+        List<BreakpointRequest> allBreakpoints = erm.breakpointRequests();
+        Iterator<BreakpointRequest> it = allBreakpoints.iterator();
+
+        while (it.hasNext()) {
+            BreakpointRequest bp = (BreakpointRequest) it.next();
+
+            if (bp.location().declaringType().classLoader() == currentLoader) {
+                breaks.add(bp.location());
+            }
+        }
+
+        return breaks;
+    }
+    
+    /**
+     * Remove all user breakpoints
+     */
+    public void clearAllBreakpoints()
+    {
+        EventRequestManager erm = machine.eventRequestManager();
+        List<BreakpointRequest> breaks = new LinkedList<BreakpointRequest>();
+
+        List<BreakpointRequest> allBreakpoints = erm.breakpointRequests();
+        Iterator<BreakpointRequest> it = allBreakpoints.iterator();
+
+        while (it.hasNext()) {
+            BreakpointRequest bp = (BreakpointRequest) it.next();
+            if (bp.getProperty(Debugger.PERSIST_BREAKPOINT_PROPERTY) == null) {
+                breaks.add(bp);
+            }
+        }
+
+        erm.deleteEventRequests(breaks);
+    }
+    
+    /**
+     * Remove all breakpoints for the given class.
+     */
+    public void clearBreakpointsForClass(String className)
+    {
+        EventRequestManager erm = machine.eventRequestManager();
+
+        List<BreakpointRequest> allBreakpoints = erm.breakpointRequests();
+        Iterator<BreakpointRequest> it = allBreakpoints.iterator();
+        List<BreakpointRequest> toDelete = new LinkedList<BreakpointRequest>();
+
+        while (it.hasNext()) {
+            BreakpointRequest bp = it.next();
+
+            ReferenceType bpType = bp.location().declaringType();
+            if (bpType.name().equals(className) && bp.getProperty(Debugger.PERSIST_BREAKPOINT_PROPERTY) == null) {
+                toDelete.add(bp);
+            }
+        }
+        
+        erm.deleteEventRequests(toDelete);
+    }
+
+    /**
+     * Restore the previosuly saved breakpoints with the new classloader.
+     * 
+     * @param loader
+     *            The new class loader to restore the breakpoints into
+     */
+    public void restoreBreakpoints(List<Location> saved)
+    {
+        // Debug.message("[VMRef] restoreBreakpoints()");
+
+        EventRequestManager erm = machine.eventRequestManager();
+
+        // create the list of locations - converted to the new classloader
+        // this has to be done before we suspend the machine because
+        // loadClassesAndFindLine needs the machine running to work
+        // see bug #526
+        List<Location> newSaved = new ArrayList<Location>();
+
+        Iterator<Location> savedIterator = saved.iterator();
+
+        while (savedIterator.hasNext()) {
+            Location oldLocation = savedIterator.next();
+
+            Location newLocation = loadClassesAndFindLine(oldLocation.declaringType().name(), oldLocation.lineNumber());
+
+            if (newLocation != null) {
+                newSaved.add(newLocation);
+            }
+        }
+
+        // to stop our server thread getting away from us, lets halt the
+        // VM temporarily
+        synchronized(workerThread) {
+            workerThreadReadyWait();
+            
+            // we need to throw away all the breakpoints referring to the old
+            // class loader but then we need to restore our internal breakpoints
+            
+            // Note, we have to be careful when deleting breakpoints. There is
+            // a JDI bug which causes threads to halt indefinitely when hitting
+            // a breakpoint that is being deleted. That's why we wait for the
+            // worker thread to be in a stopped state before we proceed, and we
+            // suspend the machine to prevent problems with the server thread.
+            // Also we make sure any pending breakpoint events are processed before
+            // removing the breakpoints.
+            machine.suspend();
+            eventHandler.waitQueueEmpty();
+            erm.deleteAllBreakpoints();
+            serverClassAddBreakpoints();
+            
+            // add all the new breakpoints we have created
+            Iterator<Location> it = newSaved.iterator();
+            
+            while (it.hasNext()) {
+                Location l = (Location) it.next();
+                
+                BreakpointRequest bpreq = erm.createBreakpointRequest(l);
+                bpreq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+                bpreq.putProperty(VMEventHandler.DONT_RESUME, "yes");
+                bpreq.enable();
+            }
+            machine.resume();
+        }
+    }
+
+    // -- support methods --
+
+    /**
+     * Wait for the "server" thread to start. This must be synchronized on
+     * serverThreadLock (in JdiDebugger).
+     */
+    private void serverThreadStartWait()
+    {
+        synchronized(this) {
+            try {
+                while (!serverThreadStarted) {
+                    if (exitStatus == Debugger.TERMINATED)
+                        throw new VMDisconnectedException();
+                    wait(); // wait for new thread to start
+                }
+            }
+            catch (InterruptedException ie) {}
+        }
+    }
+    
+    /**
+     * Resume the server thread to begin executing some function.
+     * 
+     * Calls to this method should be synchronized on the serverThreadLock
+     * (in JdiDebugger).
+     */
+    private void resumeServerThread()
+    {
+        synchronized (eventHandler) {
+            serverThread.resume();
+            owner.serverThreadResumed(serverThread);
+            owner.raiseStateChangeEvent(Debugger.RUNNING);
+        }
+        // Note, we do the state change after the resume because the state
+        // change may throw VMDisconnectedException (in which case we don't
+        // want to go into the RUNNING state).
+    }
+    
+    /**
+     * Wait until the "worker" thread is ready for use. This method should
+     * be called with the workerThread monitor held.
+     * 
+     * @throws VMDisconnectedException  if the VM terminates.
+     */
+    private void workerThreadReadyWait()
+    {
+        try {
+            while (!workerThreadReady || workerThreadReserved) {
+                if (exitStatus == Debugger.TERMINATED) {
+                    throw new VMDisconnectedException();
+                }
+                workerThread.wait();
+            }
+        }
+        catch(InterruptedException ie) {}
+    }
+    
+    /**
+     * Wait until the "worker" thread has finished executing. This
+     * should be called only if workerThreadReserved has been set to
+     * true by the current thread.
+     * 
+     * @throws VMDisconnectedException  if the VM terminates.
+     */
+    private void workerThreadFinishWait()
+    {
+        try {
+            while (!workerThreadReady) {
+                if (exitStatus == Debugger.TERMINATED) {
+                    throw new VMDisconnectedException();
+                }
+                workerThread.wait();
+            }
+        }
+        catch(InterruptedException ie) {}
+    }
+    
+    /**
+     * Invoke the default constructor for the given class and return a reference
+     * to the generated instance.
+     */
+    private ObjectReference invokeConstructor(String className)
+    {
+        // Calls to this method are serialized via serverThreadLock in JdiDebugger
+        
+        serverThreadStartWait();
+        
+        // Store the class and method to call
+        setStaticFieldObject(serverClass, ExecServer.CLASS_TO_RUN_NAME, className);
+        setStaticFieldValue(serverClass, ExecServer.EXEC_ACTION_NAME, machine.mirrorOf(ExecServer.INSTANTIATE_CLASS));
+        
+        // Resume the thread, wait for it to finish and the new thread to start
+        serverThreadStarted = false;
+        resumeServerThread();
+        serverThreadStartWait();
+        
+        // Get return value and check for exceptions
+        Value rval = getStaticFieldObject(serverClass, ExecServer.METHOD_RETURN_NAME);
+        if (rval == null) {
+            ObjectReference exception = getStaticFieldObject(serverClass, ExecServer.EXCEPTION_NAME);
+            if (exception != null) {
+                exceptionEvent(new InvocationException(exception));
+            }
+        }
+        return (ObjectReference) rval;
+    }
+    
+    /**
+     * Invoke a particular constructor with arguments. The parameter types
+     * of the constructor must be supplied (String[]) as well as the
+     * argument values (ObjectReference []).
+     * 
+     * @param className  The name of the class to construct an instance of
+     * @param paramTypes The parameter types of the constructor (class names)
+     * @param args      The argument values to use in the constructor call
+     * 
+     * @return  The newly constructed object
+     */
+    private ObjectReference invokeConstructor(String className, String [] paramTypes, ObjectReference [] args)
+    {
+        // Calls to this method are serialized via serverThreadLock in JdiDebugger
+        
+        serverThreadStartWait();
+        boolean needsMachineResume = false;
+        
+        try {
+            int length = paramTypes.length;
+            if (args.length != length) {
+                throw new IllegalArgumentException();
+            }
+
+            // Store the class, parameter types and arguments
+
+            ArrayType objectArray = (ArrayType) loadClass("[Ljava.lang.Object;");
+            ArrayType stringArray = (ArrayType) loadClass("[Ljava.lang.String;");
+
+            // avoid problems with ObjectCollectedExceptions, see:
+            // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4257193
+            // We suspend the machine which seems to help prevent GC from occurring.
+            machine.suspend();
+            needsMachineResume = true;
+            ArrayReference argsArray = objectArray.newInstance(length);
+            ArrayReference typesArray = stringArray.newInstance(length);
+            
+            // Even with a suspended virtual machine, these arrays have been known to be garbage collected.
+            // Force them to remain uncollected:
+            while (true) {
+                try {
+                    argsArray.disableCollection();
+                    break;
+                }
+                catch (ObjectCollectedException oce) {
+                    argsArray = objectArray.newInstance(length);
+                }
+            }
+            
+            while (true) {
+                try {
+                    typesArray.disableCollection();
+                    break;
+                }
+                catch (ObjectCollectedException oce) {
+                    typesArray = stringArray.newInstance(length);
+                }
+            }
+            
+            // Fill the arrays with the correct values
+            for (int i = 0; i < length; i++) {
+                StringReference s = machine.mirrorOf(paramTypes[i]);
+                typesArray.setValue(i, s);
+                argsArray.setValue(i, args[i]);
+            }
+            
+            setStaticFieldValue(serverClass, ExecServer.PARAMETER_TYPES_NAME, typesArray);
+            setStaticFieldValue(serverClass, ExecServer.ARGUMENTS_NAME, argsArray);
+            typesArray.enableCollection();
+            argsArray.enableCollection();
+
+            setStaticFieldObject(serverClass, ExecServer.CLASS_TO_RUN_NAME, className);
+            setStaticFieldValue(serverClass, ExecServer.EXEC_ACTION_NAME, machine.mirrorOf(ExecServer.INSTANTIATE_CLASS_ARGS));
+            machine.resume();
+            needsMachineResume = false;
+            
+            // Resume the thread, wait for it to finish and the new thread to start
+            serverThreadStarted = false;
+            resumeServerThread();
+            serverThreadStartWait();
+            
+            // Get return value and check for exceptions
+            Value rval = getStaticFieldObject(serverClass, ExecServer.METHOD_RETURN_NAME);
+            if (rval == null) {
+                ObjectReference exception = getStaticFieldObject(serverClass, ExecServer.EXCEPTION_NAME);
+                if (exception != null) {
+                    exceptionEvent(new InvocationException(exception));
+                }
+            }
+            return (ObjectReference) rval;
+
+        }
+        catch (ClassNotFoundException cnfe) { }
+        catch (ClassNotLoadedException cnle) { }
+        catch (InvalidTypeException ite) { }
+        finally {
+            if (needsMachineResume) {
+                machine.resume();
+            }
+        }
+        
+        return null;
+    }
+    
+    // Calls to this method are serialized via serverThreadLock in JdiDebugger
+    public Value invokeTestSetup(String cl)
+            throws InvocationException
+    {
+        // Make sure the server thread has started
+        serverThreadStartWait();
+        
+        // Store the class and method to call
+        setStaticFieldObject(serverClass, ExecServer.CLASS_TO_RUN_NAME, cl);
+        setStaticFieldValue(serverClass, ExecServer.EXEC_ACTION_NAME, machine.mirrorOf(ExecServer.TEST_SETUP));
+        
+        // Resume the thread, wait for it to finish and the new thread to start
+        serverThreadStarted = false;
+        resumeServerThread();
+        serverThreadStartWait();
+        
+        // Get return value and check for exceptions
+        Value rval = getStaticFieldObject(serverClass, ExecServer.METHOD_RETURN_NAME);
+        if (rval == null) {
+            ObjectReference e = getStaticFieldObject(serverClass, ExecServer.EXCEPTION_NAME);
+            if (e != null) {
+                exceptionEvent(new InvocationException(e));
+                throw new InvocationException(e);
+            }
+        }
+        return rval;
+    }
+    
+    /**
+     * Run a unit test method (including setup/teardown).
+     * @param cl     The class containing the method
+     * @param method The test method to run
+     * @return  null if the test passed, or an ArrayReference if it fails, with:
+     *          [0] = failure type ("failure"/"error")
+     *          [1] = the exception message
+     *          [2] = the stack trace
+     *          [3] = the class of the failure point
+     *          [4] = the source file name containing the failure point
+     *          [5] = the line number of the failure point
+     * @throws InvocationException
+     */
+    public Value invokeRunTest(String cl, String method)
+        throws InvocationException
+    {
+        // Calls to this method are serialized via serverThreadLock in JdiDebugger
+
+        serverThreadStartWait();
+        
+        // Store the class and method to call
+        setStaticFieldObject(serverClass, ExecServer.CLASS_TO_RUN_NAME, cl);
+        setStaticFieldObject(serverClass, ExecServer.METHOD_TO_RUN_NAME, method);
+        setStaticFieldValue(serverClass, ExecServer.EXEC_ACTION_NAME, machine.mirrorOf(ExecServer.TEST_RUN));
+        
+        // Resume the thread, wait for it to finish and the new thread to start
+        serverThreadStarted = false;
+        resumeServerThread();
+        serverThreadStartWait();
+        
+        Value rval = getStaticFieldObject(serverClass, ExecServer.METHOD_RETURN_NAME);
+        if (rval == null) {
+            ObjectReference e = getStaticFieldObject(serverClass, ExecServer.EXCEPTION_NAME);
+            if (e != null) {
+                exceptionEvent(new InvocationException(e));
+                throw new InvocationException(e);
+            }
+        }
+        return rval;
+    }
+
+    /**
+     * Dispose of all gui windows opened from the debug vm.
+     */
+    void disposeWindows()
+    {
+        // Calls to this method are serialized via serverThreadLock in JdiDebugger
+
+        serverThreadStartWait();
+            
+        // set the action to "dispose windows"
+        setStaticFieldValue(serverClass, ExecServer.EXEC_ACTION_NAME, machine.mirrorOf(ExecServer.DISPOSE_WINDOWS));
+        
+        // Resume the thread, it then proceeds to remove open windows
+        serverThreadStarted = false;
+        resumeServerThread();
+        // We don't bother waiting for it to finish
+    }
+    
+    /**
+     * Add an object to the object map on the debug vm.
+     * @param instanceName  the name of the object to add
+     * @param object        a reference to the object to add
+     */
+    void addObject(String scopeId, String instanceName, ObjectReference object)
+    {
+        try {
+            synchronized(workerThread) {
+                workerThreadReadyWait();
+                setStaticFieldValue(serverClass, ExecServer.WORKER_ACTION_NAME, machine.mirrorOf(ExecServer.ADD_OBJECT));
+                
+                // parameters
+                setStaticFieldObject(serverClass, ExecServer.OBJECTNAME_NAME, instanceName);
+                setStaticFieldValue(serverClass, ExecServer.OBJECT_NAME, object);
+                setStaticFieldObject(serverClass, ExecServer.SCOPE_ID_NAME, scopeId);
+                
+                workerThreadReady = false;
+                workerThread.resume();
+            }
+        }
+        catch (VMDisconnectedException vmde) {}
+        catch (VMMismatchException vmmme) {}
+    }
+    
+    /**
+     * Remove an object from the object map on the debug vm.
+     * @param instanceName   the name of the object to remove
+     */
+    void removeObject(String scopeId, String instanceName)
+    {
+        synchronized(workerThread) {
+            try {
+                workerThreadReadyWait();
+                setStaticFieldValue(serverClass, ExecServer.WORKER_ACTION_NAME, machine.mirrorOf(ExecServer.REMOVE_OBJECT));
+        
+                // parameters
+                setStaticFieldObject(serverClass, ExecServer.OBJECTNAME_NAME, instanceName);
+                setStaticFieldObject(serverClass, ExecServer.SCOPE_ID_NAME, scopeId);
+        
+                workerThreadReady = false;
+                workerThread.resume();
+            }
+            catch(VMDisconnectedException vmde) { }
+        }
+    }
+
+    /**
+     * Check whether a thread is sitting on the server thread breakpoint. 
+     */
+    static boolean isAtMainBreakpoint(ThreadReference tr)
+    {
+        try {
+            return (tr.isAtBreakpoint() && SERVER_CLASSNAME.equals(tr.frame(0).location().declaringType().name()));
+        }
+        catch (IncompatibleThreadStateException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Get a reference to an object from a static field in some class in the
+     * debug VM.
+     * 
+     * VMDisconnected exception may be thrown.
+     * 
+     * @param cl         The class containing the field
+     * @param fieldName  The name of the field
+     * @return    An ObjectReference referring to the object
+     */
+    ObjectReference getStaticFieldObject(ClassType cl, String fieldName)
+    {
+        Field resultField = cl.fieldByName(fieldName);
+
+        if (resultField == null)
+            throw new IllegalArgumentException("getting field " + fieldName + " resulted in no fields");
+
+        return (ObjectReference) cl.getValue(resultField);
+    }
+    
+    /**
+     * Set the value of a static field in the debug VM.
+     * @param cl         The class containing the field
+     * @param fieldName  The name of the field
+     * @param value      The value to which the field must be set
+     */
+    void setStaticFieldValue(ClassType cl, String fieldName, Value value)
+    {
+        Field field = cl.fieldByName(fieldName);
+        
+        try {
+            cl.setValue(field,value);
+        }
+        catch(InvalidTypeException ite) { }
+        catch(ClassNotLoadedException cnle) { }
+    }
+
+    /**
+     * Set the value of some static field as a string. A mirror of the given
+     * string value is created on the debug VM.
+     */
+    void setStaticFieldObject(ClassType cl, String fieldName, String value)
+    {
+        // Any mirror object which is created is prone to being garbage
+        // collected before we can assign it to a field. This causes an
+        // ObjectCollectedException. using the "disableCollection" method seems
+        // to help but there is still a window between object creation and that
+        // method being called, so we catch the exception and use a more
+        // forceful approach in that case.
+        
+        try {
+            StringReference s = machine.mirrorOf(value);
+            s.disableCollection();
+            setStaticFieldValue(cl, fieldName, s);
+            s.enableCollection();
+        }
+        catch(ObjectCollectedException oce) {
+            machine.suspend();
+            StringReference s = machine.mirrorOf(value);
+            setStaticFieldValue(cl, fieldName, s);
+            machine.resume();
+        }
+    }
+
+    /**
+     * Find the mirror of a class/interface/array in the remote VM.
+     * 
+     * The class is expected to exist. We expect only one single class to exist
+     * with this name. Throws a ClassNotFoundException if the class could not be
+     * found.
+     * 
+     * This should only be used for classes that we know exist and are loaded ie
+     * ExecServer etc.
+     */
+    private ReferenceType findClassByName(String className, ClassLoaderReference clr)
+        throws ClassNotFoundException
+    {
+        // find the class
+        List<ReferenceType> list = machine.classesByName(className);
+        if (list.size() == 1) {
+            return (ReferenceType) list.get(0);
+        }
+        else if (list.size() > 1) {
+            Iterator<ReferenceType> iter = list.iterator();
+            while (iter.hasNext()) {
+                ReferenceType cl = iter.next();
+                if (cl.classLoader() == clr)
+                    return cl;
+            }
+        }
+        throw new ClassNotFoundException(className);
+    }
+
+    /**
+     * Find the mirror of a class/interface/array in the remote VM.
+     * 
+     * @param className
+     *            the name of the class to find
+     * @return a reference to the class
+     * 
+     * @throws ClassNotFoundException
+     */
+    public ReferenceType findClassByName(String className)
+        throws ClassNotFoundException
+    {
+        return findClassByName(className, currentLoader);
+    }
+
+    /**
+     * Find the mirror of a method in the remote VM.
+     * 
+     * The method is expected to exist. We expect only one single method to
+     * exist with this name and report an error if more than one is found.
+     */
+    Method findMethodByName(ReferenceType type, String methodName)
+    {
+        List<Method> list = type.methodsByName(methodName);
+        if (list.size() != 1) {
+            throw new IllegalArgumentException("getting method " + methodName + " resulted in " + list.size()
+                    + " methods");
+        }
+        return (Method) list.get(0);
+    }
+
+    /**
+     * Create a thread that will retrieve any output from the remote machine and
+     * direct it to our terminal (or vice versa).
+     */
+    private IOHandlerThread redirectIOStream(final Reader reader, final Writer writer)
+    {
+        IOHandlerThread thr;
+
+        thr = new IOHandlerThread(reader, writer);
+        thr.setPriority(Thread.MAX_PRIORITY - 1);
+        thr.start();
+
+        return thr;
+    }
+
+    /**
+     * The thread for retrieving output from the remote machine and redirecting
+     * it to the terminal.
+     */
+    private class IOHandlerThread extends Thread
+    {
+        private Reader reader;
+        private Writer writer;
+        private volatile boolean keepRunning = true;
+
+        IOHandlerThread(Reader reader, Writer writer)
+        {
+            super("BlueJ I/O Handler");
+            this.reader = reader;
+            this.writer = writer;
+            setPriority(Thread.MIN_PRIORITY);
+        }
+
+        public void close()
+        {
+            keepRunning = false;
+        }
+
+        public void run()
+        {
+            try {
+                // An arbitrary buffer size.
+                char [] chbuf = new char[4096];
+                
+                while (keepRunning) {
+                    int numchars = reader.read(chbuf);
+                    if (numchars == -1) {
+                        keepRunning = false;
+                    }
+                    else if (keepRunning) {
+                        writer.write(chbuf, 0, numchars);
+                        if (! reader.ready()) {
+                            writer.flush();
+                        }
+                    }
+                }
+            }
+            catch (IOException ex) {
+                // Debug.reportError("Cannot read output user VM.");
+            }
+        }
+    }
+
+    /**
+     * Find the VMReference which corresponds to the supplied VirtualMachine instance.
+     */
+    public static VMReference getVmForMachine(VirtualMachine mc)
+    {
+        synchronized (vmToReferenceMap) {
+            return (VMReference) vmToReferenceMap.get(mc);
+        }
+    }
+    
+    /*
+    public void dumpConnectorArgs(Map arguments)
+    {
+        // debug code to print out all existing arguments and their
+        // description
+        Collection c = arguments.values();
+        Iterator i = c.iterator();
+        while (i.hasNext()) {
+            Connector.Argument a = (Connector.Argument) i.next();
+            Debug.message("arg name: " + a.name());
+            Debug.message("  descr: " + a.description());
+            Debug.message("  value: " + a.value());
+        }
+    }
+    */
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/CallDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/CallDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e15f4c7c84969c617bf4ed758da55e61b4d2bb5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/CallDialog.java
@@ -0,0 +1,984 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSeparator;
+import javax.swing.JTextField;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.TextType;
+import bluej.debugmgr.objectbench.ObjectBenchEvent;
+import bluej.debugmgr.objectbench.ObjectBenchInterface;
+import bluej.debugmgr.objectbench.ObjectBenchListener;
+import bluej.utility.ComponentFactory;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+import bluej.utility.GrowableBox;
+import bluej.utility.MultiLineLabel;
+import bluej.views.CallableView;
+import bluej.views.TypeParamView;
+import bluej.views.View;
+
+/**
+ * Superclass for interactive call dialogs (method calls or free
+ * form calls.
+ *
+ * @author  Michael Kolling
+ */
+public abstract class CallDialog extends EscapeDialog
+    implements ObjectBenchListener, FocusListener
+{
+    protected static final Insets INSETS = new Insets(2, 2, 2, 2);
+
+    protected static final String emptyFieldMsg = Config.getString("error.methodCall.emptyField");
+    protected static final String emptyTypeFieldMsg = Config.getString("error.methodCall.emptyTypeField");
+
+    public static final int OK = 0;
+    public static final int CANCEL = 1;
+
+    private MultiLineLabel errorLabel;
+    protected ParameterList parameterList;
+    protected ParameterList typeParameterList;
+
+    private ObjectBenchInterface bench;
+    private CallDialogWatcher watcher;
+    private boolean listeningObjects; // listening on the object bench
+
+    protected JButton okButton;
+    protected String defaultParamValue = "";
+    
+    // Text Area
+    private JPanel descPanel;
+    private JTextField focusedTextField;
+    
+    protected CallHistory history;
+
+    public static class VarArgFactory implements ComponentFactory
+    {
+        private List<String> history;
+        private CallDialog dialog;
+
+        public VarArgFactory(CallDialog dialog, List<String> history)
+        {
+            this.history = history;
+            this.dialog = dialog;
+        }
+
+        public void setHistory(List<String> history)
+        {
+            this.history = history;
+        }
+        
+        public JComponent createComponent(JButton addButton, JButton removeButton)
+        {
+            Box container = new Box(BoxLayout.X_AXIS);
+            JComboBox comboBox = dialog.createComboBox(history);
+            comboBox.setSelectedIndex(0);
+            container.add(comboBox);
+            container.add(Box.createHorizontalStrut(5));
+            container.add(new JLabel(" , "));
+            container.add(Box.createHorizontalStrut(5));
+            container.add(addButton);
+            container.add(Box.createHorizontalStrut(5));
+            container.add(removeButton);
+            return container;
+        }
+    }
+    
+    /**
+     * Class that holds the components for  a list of parameters. 
+     * That is: the actual parameter component and the formal type of the parameter.
+     * @author Poul Henriksen <polle@mip.sdu.dk>
+     */
+    public static class ParameterList
+    {
+        private List<JComponent> parameters;
+        private List<String> types;
+        private boolean isVarArgs;
+        private String defaultParamValue;
+
+        public ParameterList(int initialSize, String defaultParamValue, boolean isVarArgs) 
+        {            
+            parameters = new ArrayList<JComponent>(initialSize);
+            types = new ArrayList<String>(initialSize);
+            this.defaultParamValue = defaultParamValue;
+            this.isVarArgs = isVarArgs;
+        }
+
+        public JComboBox getParameter(int index)
+        {
+            if (isVarArgs && index >= (parameters.size() - 1)) {
+                GrowableBox box = getGrowableBox();
+                int boxIndex = index - parameters.size() + 1;
+                return (JComboBox) ((Container) box.getComponent(boxIndex)).getComponent(0);
+            } else {
+                return (JComboBox) parameters.get(index);
+            }
+        }
+
+        public JComponent getParameterComponent(int index)
+        {
+            return (JComponent) parameters.get(index);
+        }
+
+        public String getType(int index)
+        {
+            if (isVarArgs && index >= (parameters.size() - 1)) {
+                return (String) types.get(types.size() - 1);
+            } else {
+                return (String) types.get(index);
+            }
+        }
+
+        private GrowableBox getGrowableBox()
+        {
+            if (parameters.size() < 1) {
+                return null;
+            }
+            Object c = parameters.get(parameters.size() - 1);
+            if (c instanceof GrowableBox) {
+                return (GrowableBox) parameters.get(parameters.size() - 1);
+            } else {
+                return null;
+            }
+        }
+
+        public void addParameter(int index, JComboBox component, String type)
+        {
+            parameters.add(index, component);
+            types.add(index, type);
+        }
+
+        public void setVarArg(GrowableBox component, String type)
+        {
+            GrowableBox box = getGrowableBox();
+            if (box != null) {
+                parameters.remove(box);
+            }
+            parameters.add(component);
+            types.add(type);
+        }
+
+        public int size()
+        {
+            if (isVarArgs) {
+                return parameters.size() + getGrowableBox().getComponentCountWithoutEmpty() - 1;
+            } else {
+                return parameters.size();
+            }
+        }
+
+        public void clear()
+        {
+            for (Iterator<JComponent> iter = parameters.iterator(); iter.hasNext();) {
+                JComponent element = iter.next();
+                if (isVarArgs && !iter.hasNext()) {
+                    ((GrowableBox) element).clear();
+                } else {
+                    ((JComboBox) element).setSelectedIndex(0);
+                }
+            }
+        }
+
+        /**
+         * Set the history for the given element.
+         * 
+         * @param i
+         * @param historyList
+         */
+        public void setHistory(int i, List<String> historyList)
+        {
+            if(historyList == null) {
+                return;
+            }
+            else if (isVarArgs && i >= (parameters.size() - 1)) {
+                GrowableBox varArgs = getGrowableBox();
+                VarArgFactory factory = (VarArgFactory) varArgs.getComponentFactory();
+                factory.setHistory(historyList);
+            } else {
+                getParameter(i).setModel(new DefaultComboBoxModel(historyList.toArray()));
+                getParameter(i).insertItemAt(defaultParamValue, 0);
+            }
+        }
+    }
+    
+    public CallDialog(JFrame parentFrame, ObjectBenchInterface objectBench, String title)
+    {
+        super(parentFrame, title, false);
+        bench = objectBench;
+    }
+
+    /**
+     * The Ok button was pressed.
+     */
+    public abstract void doOk();
+
+    /**
+     * The Cancel button was pressed.
+     * Process a "Cancel" event to cancel a Constructor or Method call.
+     * Makes dialog invisible.
+     */
+    public void doCancel()
+    {
+        callWatcher(CANCEL);
+    }
+
+    /**
+     * Set a watcher for events of this dialog.
+     */
+    public void setWatcher(CallDialogWatcher w)
+    {
+        watcher = w;
+    }
+
+    /**
+     * callWatcher - notify watcher of dialog events.
+     */
+    public void callWatcher(int event)
+    {
+        if (watcher != null) {
+            watcher.callDialogEvent(this, event);
+        }
+    }
+
+    /**
+     * setWaitCursor - Sets the cursor to "wait" style cursor, using swing
+     *  bug workaround at present
+     */
+    public void setWaitCursor(boolean wait)
+    {
+        if(wait)
+            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+        else
+            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+    }
+
+    /**
+     * Return the label to be used for showing error messages.
+     */
+    protected MultiLineLabel getErrorLabel()
+    {
+        if(errorLabel == null) {
+            errorLabel = new MultiLineLabel("\n\n", LEFT_ALIGNMENT);
+            errorLabel.setForeground(new Color(136,56,56));  // dark red
+        }
+        return errorLabel;
+    }
+
+    /**
+     * Return the frame's object bench.
+     */
+    protected ObjectBenchInterface getObjectBench()
+    {
+        return bench;
+    }
+
+    /**
+     * Start listening to object bench events.
+     */
+    protected void startObjectBenchListening()
+    {
+        if (!listeningObjects && bench != null) {
+            bench.addObjectBenchListener(this);
+            listeningObjects = true;
+        }
+    }
+
+    /**
+     * Stop listening to object bench events.
+     */
+    protected void stopObjectBenchListening()
+    {
+        if (listeningObjects && bench != null) {
+            bench.removeObjectBenchListener(this);
+            listeningObjects = false;
+        }
+    }
+
+    /**
+     * setMessage - Sets a status bar style message for the dialog mainly
+     *  for reporting back compiler errors upon method calls.
+     */
+    public void setErrorMessage(String message)
+    {
+        // cut the "location: __SHELL3" bit from some error messages
+        int index = message.indexOf("location:");
+        if(index != -1)
+            message = message.substring(0,index-1);
+
+        errorLabel.setText(message);
+        pack();
+        invalidate();
+        validate();
+    }
+
+    // ---- ObjectBenchListener interface ----
+
+    /**
+     * The object was selected interactively (by clicking
+     * on it with the mouse pointer).
+     */
+    public void objectEvent(ObjectBenchEvent obe)
+    {
+        NamedValue value = obe.getValue();
+        insertText(value.getName());
+    }
+
+    /**
+     * Build the Swing dialog. The top and center components
+     * are supplied by the specific subclasses. This method
+     * add the Ok and Cancel buttons.
+     */
+    protected void makeDialog(JComponent topComponent, JComponent centerComponent)
+    {
+        JPanel contentPane = (JPanel)getContentPane();
+
+        // create the ok/cancel button panel
+        JPanel buttonPanel = new JPanel();
+        buttonPanel.setOpaque(false);
+        {
+            buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+
+            //JButton okButton = BlueJTheme.getOkButton();
+            okButton = BlueJTheme.getOkButton();
+            okButton.addActionListener(new ActionListener() {
+                        public void actionPerformed(ActionEvent evt) { doOk(); }
+                    });
+
+            JButton cancelButton = BlueJTheme.getCancelButton();
+            cancelButton.addActionListener(new ActionListener() {
+                        public void actionPerformed(ActionEvent evt) { doCancel(); }
+                    });
+                    
+            DialogManager.addOKCancelButtons(buttonPanel, okButton, cancelButton);
+
+            getRootPane().setDefaultButton(okButton);
+        }
+
+        //contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
+        contentPane.setLayout(new BorderLayout(6,6));
+        contentPane.setBorder(BlueJTheme.generalBorder);
+
+        if(topComponent != null)
+            contentPane.add(topComponent, BorderLayout.NORTH);
+        if(centerComponent != null)
+            contentPane.add(centerComponent, BorderLayout.CENTER);
+        contentPane.add(buttonPanel, BorderLayout.SOUTH);
+
+        pack();
+        DialogManager.centreDialog(this);
+
+        // Close Action when close button is pressed
+        addWindowListener(new WindowAdapter() {
+                public void windowClosing(WindowEvent event) {
+                    setVisible(false);
+                }
+            });
+    }
+    
+    /**
+     * Returns the formal type parameters for the class that declares this method.
+     * @return Array of typeParamViews
+     */
+    public static TypeParamView[] getFormalTypeParams(CallableView callable)
+    {
+        View clazz = callable.getDeclaringView();
+        return clazz.getTypeParams();        
+    }
+    
+    /**
+     * Calculates and returns the preferred height of a combobox.
+     * 
+     * @return Preferred height of a normal JComboBox
+     */
+    protected double getComboBoxHeight()
+    {
+        JComboBox comboBox = createComboBox(new ArrayList<String>());
+        double comboHeight = comboBox.getPreferredSize().getHeight();
+        return comboHeight;
+    }
+
+    protected JComboBox createComboBox(List<String> history)
+    {        
+        if(history == null) {
+            history = new ArrayList<String>();
+        }
+        JComboBox component = new JComboBox(history.toArray());
+        component.insertItemAt(defaultParamValue, 0);
+        component.setEditable(true);
+        
+        Dimension prefSize = component.getPreferredSize();
+        if (prefSize.width < 100) {
+            // On MacOS (Leopard) the ComboBox is tiny. So we
+            // explicitly set the width here.
+            prefSize.width = 100;
+            component.setPreferredSize(prefSize);            
+        }
+        // treat 'return' in text field as OK
+        component.getEditor().addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent evt)
+            {
+               doOk();
+            }
+        });
+        // add FocusListener for text insertion
+        ((JTextField) component.getEditor().getEditorComponent()).addFocusListener(this);
+        return component;
+    }
+
+    /**
+     * Sets the preferred height of the component.
+     * @param c The component for which to change the preferred height
+     * @param height the new height
+     */
+    protected void setPreferredHeight(JComponent c, double height)
+    {
+        int lastTypeWidth = (int) c.getPreferredSize().getWidth();
+        c.setPreferredSize(new Dimension(lastTypeWidth, (int) height));
+    }
+
+    /**
+     * Creates a panel of parameters for a method
+     */
+    protected JPanel createParameterPanel()
+    {
+        CallableView method = getCallableView();
+        Class<?>[] paramClasses = getArgTypes(false);
+        String[] paramNames = method.getParamNames();
+        String[] paramTypes = method.getParamTypeStrings();
+
+        parameterList = new ParameterList(paramClasses.length, defaultParamValue, method.isVarArgs());
+        for (int i = 0; i < paramTypes.length; i++) {
+            String paramString = paramTypes[i];
+            if(paramNames!=null) {
+                paramString += " " + paramNames[i];
+            }
+            if (method.isVarArgs() && i == (paramClasses.length - 1)) {
+                List<String> historyList = history.getHistory(paramClasses[i].getComponentType());
+                GrowableBox component = new GrowableBox(new VarArgFactory(this, historyList),
+                        BoxLayout.Y_AXIS, INSETS.top + INSETS.bottom);
+                //We want the dialog to resize when new args are added
+                component.addComponentListener(new ComponentListener() {
+                    public void componentResized(ComponentEvent e)
+                    {
+                        CallDialog.this.pack();
+                    }
+
+                    public void componentMoved(ComponentEvent e)
+                    {
+                    }
+
+                    public void componentShown(ComponentEvent e)
+                    {
+                    }
+
+                    public void componentHidden(ComponentEvent e)
+                    {
+                    }
+                });
+                parameterList.setVarArg(component, paramString);
+            } else {
+                List<String> historyList = history.getHistory(paramClasses[i]);
+                JComboBox component = createComboBox(historyList);
+                parameterList.addParameter(i, component, paramString);
+            }
+        }
+
+        return createParameterPanel("(", ")", parameterList);
+    }
+
+    /**
+     * Creates a panel of parameters.
+     * 
+     * @param startString The string prepended before the first parameter. Typically something like ( or <
+     * @param endString The string appended after the last parameter. Typically something like ) or >
+     * @param parameterList A list containing the components for the parameter panel
+     * @return
+     */
+    protected JPanel createParameterPanel(String startString, String endString,
+            ParameterList parameterList)
+    {
+        JPanel tmpPanel = new JPanel();
+        GridBagLayout gridBag = new GridBagLayout();
+        tmpPanel.setLayout(gridBag);
+
+
+        JLabel startParenthesis = new JLabel(startString);
+        double comboHeight = getComboBoxHeight();
+        //we want a large parenthesis
+        double parenthesisHeight = startParenthesis.getPreferredSize().getHeight();
+        double parenthesisScale = comboHeight / parenthesisHeight;
+        Font f = startParenthesis.getFont();
+        Font parenthesisFont = f.deriveFont((float) (f.getSize() * parenthesisScale));
+        startParenthesis.setFont(parenthesisFont);
+
+        GridBagConstraints constraints = new GridBagConstraints();
+        constraints.insets = INSETS;
+        constraints.gridx = 0;
+        constraints.anchor = GridBagConstraints.NORTHEAST;
+        tmpPanel.add(startParenthesis, constraints);
+
+        for (int i = 0; i < parameterList.size(); i++) {
+            constraints.gridx = 1;
+            constraints.gridy = i;
+            constraints.anchor = GridBagConstraints.WEST;
+
+            JComponent component = parameterList.getParameterComponent(i);
+            gridBag.setConstraints(component, constraints);
+            tmpPanel.add(component);
+
+            JLabel eol = new JLabel(",", JLabel.LEFT);
+            JLabel type = new JLabel(" " + parameterList.getType(i), JLabel.LEFT);
+            if (i == (parameterList.size() - 1)) {
+                eol.setText(endString);
+                eol.setFont(parenthesisFont);
+                if (parameterList.size() == 1) {                    
+                    type = null;
+                } else {
+                    setPreferredHeight(type, comboHeight);
+                    constraints.anchor = GridBagConstraints.NORTH;
+                }                
+            }                      
+
+            if(type!=null) {
+                    constraints.gridx = 3;
+                    tmpPanel.add(type, constraints);
+            }            
+
+            constraints.gridx = 2;
+            setPreferredHeight(eol, comboHeight);
+            constraints.anchor = GridBagConstraints.SOUTHWEST;
+            gridBag.setConstraints(eol, constraints);
+            tmpPanel.add(eol); 
+        }
+        return tmpPanel;
+    }
+    
+    /**
+     * getArgTypes - Get an array with the classes of the parameters for this
+     * method. "null" if there are no parameters. <br>
+     * If varArgsExpanded is set to true, the varargs will be expanded to the
+     * number of variable arguments that have been typed into the dialog. For
+     * instance, if the only argument is a vararg of type String and two strings
+     * has been typed in, this method will return an array of two String
+     * classes.
+     * 
+     * @param varArgsExpanded
+     *            if set to true, varargs will be expanded.
+     */
+    public Class<?>[] getArgTypes(boolean varArgsExpanded)
+    {
+        CallableView method = getCallableView();
+        Class<?>[] params = method.getParameters();
+        boolean hasVarArgs = method.isVarArgs() && parameterList != null
+                && parameterList.size() >= params.length;
+        if (hasVarArgs && varArgsExpanded) {
+            int totalParams = parameterList.size();
+            Class<?>[] allParams = new Class[totalParams];
+            System.arraycopy(params, 0, allParams, 0, params.length);
+            Class<?> varArgType = params[params.length - 1].getComponentType();
+            for (int i = params.length - 1; i < totalParams; i++) {
+                allParams[i] = varArgType;
+            }
+            return allParams;
+        } else {
+            return params;
+        }
+    }
+
+    /**
+     * Get arguments from param entry fields as array of strings.
+     * May be null (if there are no arguments).
+     */
+    public String[] getArgs()
+    {
+        String[] args = null;
+
+        if (parameterList != null) {
+            args = new String[parameterList.size()];
+            for (int i = 0; i < parameterList.size(); i++) {
+                args[i] = (String) parameterList.getParameter(i).getEditor().getItem();    
+            }
+        }
+        return args;
+    }
+    
+    /**
+     * Returns false if any of the parameter fields are empty
+     */
+    public boolean parameterFieldsOk()
+    {        
+        if (parameterList != null) {            
+            for (int i = 0; i < parameterList.size(); i++) {
+                String arg = (String) parameterList.getParameter(i).getEditor().getItem();
+                if (arg == null || arg.trim().equals(""))
+                    return false;                
+            }
+        }
+        return true;
+    }
+    
+    /**
+     * Returns false if some of the typeParameter fields are empty.
+     * That is: if one or more type parameters, but not all, are typed in
+     */
+    public boolean typeParameterFieldsOk()
+    {        
+        boolean oneIsTypedIn = false;
+        boolean oneIsEmpty = false;
+        if (typeParameterList != null) {            
+            for (int i = 0; i < typeParameterList.size(); i++) {
+                String arg = (String) typeParameterList.getParameter(i).getEditor().getItem();
+                if (arg == null || arg.trim().equals("")) {
+                    oneIsEmpty = true;                     
+                } else {
+                    oneIsTypedIn = true;
+                }
+                if(oneIsEmpty && oneIsTypedIn) {
+                    return false;
+                }                
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Clear parameters of any param entry fields
+     */
+    protected void clearParameters()
+    {
+        if (parameterList != null) {
+            parameterList.clear();
+        }
+        if (typeParameterList != null) {
+            typeParameterList.clear();
+        }
+    }
+    
+    /**
+     * Set the visibility of the dialog, clearing parameter edit fields
+     * and setting focus.
+     */
+    public void setVisible(boolean show)
+    {
+        if (! show) {
+            stopObjectBenchListening();
+        }
+        super.setVisible(show);
+    }
+
+    /**
+     * Build the Swing dialog.
+     */
+    protected void makeDialog(String className, String instanceName)
+    {
+        super.setContentPane(new JPanel() {
+            protected void paintComponent(Graphics g)
+            {
+                super.paintComponent(g);
+                
+                Graphics2D g2d = (Graphics2D)g;
+                int width = getWidth();
+                int height = getHeight();
+                
+                g2d.setPaint(new GradientPaint(width/4, 0, new Color(230,229,228),
+                                               width*3/4, height, new Color(191,186,178)));
+                g2d.fillRect(0, 0, width, height);
+            }
+        });
+        
+        JPanel dialogPanel = new JPanel();
+        dialogPanel.setOpaque(false);
+        {
+            descPanel = new JPanel();
+            descPanel.setOpaque(false);
+            {
+                descPanel.setLayout(new BoxLayout(descPanel, BoxLayout.Y_AXIS));
+                descPanel.setAlignmentX(LEFT_ALIGNMENT);
+            }
+
+            JPanel centerPanel = new JPanel();
+            centerPanel.setOpaque(false);
+            {
+                centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS));
+                centerPanel.setAlignmentX(LEFT_ALIGNMENT);
+                //
+                // Set dialog items depends on the Dialog type
+                //
+                makeDialogInternal(className, instanceName, centerPanel);
+            }
+
+            dialogPanel.setLayout(new BoxLayout(dialogPanel, BoxLayout.Y_AXIS));
+            dialogPanel.setBorder(BlueJTheme.generalBorder);
+            dialogPanel.add(descPanel);
+            dialogPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+            JSeparator sep = new JSeparator();
+            sep.setForeground(new Color(191,190,187));
+            sep.setBackground(new Color(0,0,0,0));
+            dialogPanel.add(sep);
+            dialogPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+            dialogPanel.add(centerPanel);
+            dialogPanel.add(getErrorLabel());
+        }
+        makeDialog(null, dialogPanel);
+    }
+
+    /**
+     * setDescription - display a new description in the dialog
+     */
+    protected void setDescription(MultiLineLabel label)
+    {
+        label.setAlignmentX(LEFT_ALIGNMENT);
+        descPanel.removeAll();
+        descPanel.add(label);
+        label.setOpaque(false);
+        invalidate();
+        validate();
+    }
+    
+    /**
+     * Insert text into edit field (JComboBox) that has focus.
+     */
+    public void insertText(String text)
+    {
+        if (parameterList != null) {
+            if (focusedTextField != null) {
+                focusedTextField.setText(text);
+                // bring to front after insertion, doesn't seem to work.
+                this.setVisible(true);
+            }
+        }
+    }
+    
+    /**
+     * Workaround for udating model problems with JComboBox.
+     * Updates CallHistory and resets model to updated Vectors.  Ugly and
+     * brutal but corrects problems with JComboBox update problems.
+     */
+    public void updateParameters()
+    {
+        if (parameterList != null) {
+            Class<?>[] paramClasses = getArgTypes(true);
+            //First we add all the current items into the historylist
+            for (int i = 0; i < parameterList.size(); i++) {
+                history.addCall(paramClasses[i], (String) parameterList.getParameter(i).getEditor()
+                        .getItem());                
+            }
+            //Then we update all the comboboxes
+            for (int i = 0; i < parameterList.size(); i++) {                
+                List<String> historyList = history.getHistory(paramClasses[i]);                
+                parameterList.setHistory(i, historyList);                
+            }
+        }
+        
+        if (typeParameterList != null) {
+            CallableView callable = getCallableView();
+            TypeParamView[] formalTypeParams = getFormalTypeParams(callable);
+            String[] typeParams = getTypeParams();
+            //First we add all the current items into the historylist
+            for (int i = 0; i < typeParams.length; i++) {
+                history.addCall(formalTypeParams[i], typeParams[i]);
+            }
+            //Then we update all the comboboxes
+            for (int i = 0; i < typeParams.length; i++) {
+                List<String> historyList = history.getHistory(formalTypeParams[i]);
+                typeParameterList.setHistory(i, historyList);                                
+            }
+        }
+    }
+    
+    /**
+     * For a generic class this will return the type parameters if any has been
+     * typed in. Otherwise it will just return an empty array.
+     * 
+     * @return A String array containing the type parameters as typed by the
+     *         user
+     */
+    public String[] getTypeParams()
+    {
+        if (typeParameterList == null) {
+            return new String[0];
+        }
+        String[] typeParams = new String[typeParameterList.size()];
+        for (int i = 0; i < typeParameterList.size(); i++) {
+            typeParams[i] = (String) typeParameterList.getParameter(i).getEditor().getItem();
+            if (typeParams[i].equals("")) {
+                // more complete checking of parameters is done elsewhere
+                return new String[0];
+            }
+        }
+        return typeParams;
+    }
+
+    /**
+     * getArgTypes - Get an array with the types of the parameters for this
+     * method. This takes into account mapping from type parameter names to
+     * their types as supplied in the constructor or setInstanceInfo call.<p>
+     * 
+     * If varArgsExpanded is set to true, the varargs will be expanded to the
+     * number of variable arguments that have been typed into the dialog. For
+     * instance, if the only argument is a vararg of type String and two
+     * strings have been typed in, this method will return an array of two
+     * String classes.
+     * 
+     * @param varArgsExpanded
+     *            if set to true, varargs will be expanded.
+     * @param raw
+     *            if true, raw types will be returned
+     */
+    public JavaType[] getArgGenTypes(boolean varArgsExpanded)
+    {
+        CallableView method = getCallableView();
+        boolean raw = targetIsRaw();
+        
+        // first construct a type parameter map which includes not only
+        // type parameters from the declaring class, but also those from this
+        // particular call
+        Map<String,GenTypeParameter> typeParameterMap = getTargetTypeArgs();
+        Map<String,GenTypeParameter> typeMap = new HashMap<String,GenTypeParameter>();
+        if (typeParameterMap != null) {
+            typeMap.putAll(typeParameterMap);
+        }
+        
+        String [] typeParams = getTypeParams();
+        TypeParamView[] formalTypeParamViews = getFormalTypeParams(method);                  
+        int len = typeParams.length;
+        for (int i = 0; i < len; i++) {
+            TypeParamView view = formalTypeParamViews[i];
+            GenTypeDeclTpar formalType = view.getParamType();
+            JavaType actualType = new TextType(typeParams[i]);
+            typeMap.put(formalType.getTparName(), actualType);
+        }
+        
+        // Map type parameter names in arguments to the corresponding types
+        JavaType[] params = method.getParamTypes(raw);
+        for (int i = 0; i < params.length; i++) {
+            params[i] = params[i].mapTparsToTypes(typeMap).getUpperBound();
+        }
+        
+        // handle varargs expansion
+        boolean hasVarArgs = method.isVarArgs() && parameterList != null
+                && parameterList.size() >= params.length;
+        if (hasVarArgs && varArgsExpanded) {
+            int totalParams = parameterList.size();
+            JavaType[] allParams = new JavaType[totalParams];
+            System.arraycopy(params, 0, allParams, 0, params.length);
+            JavaType varArgType = params[params.length - 1].getArrayComponent();
+            for (int i = params.length - 1; i < totalParams; i++) {
+                allParams[i] = varArgType;
+            }
+            return allParams;
+        } else {
+            return params;
+        }
+    }
+
+    /**
+     * Get the user-supplied instance name (constructor dialogs). Returns null for method dialogs.
+     */
+    protected String getNewInstanceName()
+    {
+        return null;
+    }
+    
+    protected abstract CallableView getCallableView();
+    
+    protected abstract void makeDialogInternal(String className, String instanceName, JPanel centerPanel);
+    
+    protected boolean targetIsRaw()
+    {
+        return false;
+    }
+    
+    protected Map<String,GenTypeParameter> getTargetTypeArgs()
+    {
+        return Collections.emptyMap();
+    }
+    
+    // --- FocusListener interface ---
+
+    /**
+     * FocusEventListener method fired when watched component gains focus
+     * Assigns focusedTextField to work around difficulties in JComboBox
+     * firing focus gained events.
+     */
+    public void focusGained(FocusEvent fe)
+    {
+        if (fe.getComponent() instanceof JTextField) {
+            focusedTextField = (JTextField) fe.getComponent();
+            focusedTextField.selectAll();
+        }
+    }
+
+    /**
+     * FocusEventListener method fired when watched component loses focus
+     * Does nothing at present except for debug message.
+     *
+     */
+    public void focusLost(FocusEvent fe)
+    {
+        //Debug.message(" Focus Lost: " + fe.paramString());
+    }
+
+    // --- end of FocusListener interface ---
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/CallDialogWatcher.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/CallDialogWatcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..e75a0557c734a57a7864e1387a233aba05eb4b2e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/CallDialogWatcher.java
@@ -0,0 +1,33 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+/**
+ * Interface implemented by classes interested in the MethodDialog
+ *
+ * @author  Michael Kolling
+ * @version $Id: CallDialogWatcher.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface CallDialogWatcher
+{
+	void callDialogEvent(CallDialog dlg, int event);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/CallHistory.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/CallHistory.java
new file mode 100644
index 0000000000000000000000000000000000000000..910836505ce6e3cfeea0785640af06016759c633
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/CallHistory.java
@@ -0,0 +1,175 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+
+import bluej.views.TypeParamView;
+
+/** 
+ * Manages an invocation history of arguments used in a package when objects 
+ * created on the ObjectBench
+ *
+ * @author Bruce Quig
+ */
+public class CallHistory
+{
+    private Map<String,List<String>> objectTypes = null;
+    private List<Class<?>> objectClasses = null;
+    private List<String> objectParams = null;
+    private Map<String,List<String>> typeParams = null;
+
+    private int historyLength;
+
+    static final int DEFAULT_LENGTH = 6;
+
+    static final String INT_NAME = "int";
+    static final String BOOLEAN_NAME = "boolean";
+    static final String LONG_NAME = "long";
+    static final String FLOAT_NAME = "float";
+    static final String DOUBLE_NAME = "double";
+    static final String SHORT_NAME = "short";
+    static final String STRING_NAME = "java.lang.String"; 
+
+    public CallHistory()
+    {
+        this(DEFAULT_LENGTH);
+    }
+
+    public CallHistory(int length)
+    {
+        historyLength = length;
+        objectTypes = new HashMap<String,List<String>>(8);
+        objectTypes.put(INT_NAME, new ArrayList<String>(length));
+        objectTypes.put(LONG_NAME, new ArrayList<String>(length));
+        objectTypes.put(BOOLEAN_NAME, new ArrayList<String>(length)); 
+        objectTypes.put(FLOAT_NAME, new ArrayList<String>(length));
+        objectTypes.put(DOUBLE_NAME, new ArrayList<String>(length));
+        objectTypes.put(SHORT_NAME, new ArrayList<String>(length));
+        objectTypes.put(STRING_NAME, new ArrayList<String>(length));
+        objectClasses = new ArrayList<Class<?>>();
+        objectParams = new ArrayList<String>();
+        typeParams = new HashMap<String,List<String>>();
+    }
+
+    /**
+     * Gets the appropriate history for the specified data type.
+     * 
+     * @param objectClass
+     *            the name of the object's class
+     * @return the List containing the appropriate history of invocations
+     */
+    public List<String> getHistory(Class<?> objectClass)
+    {
+        List<String> history = null;
+        // if listed in hashtable ie primitive or String
+        if( objectTypes.containsKey(objectClass.getName())) {
+            history = objectTypes.get(objectClass.getName());
+        }
+        // otherwise get general object history
+        else {
+            history = new ArrayList<String>();
+            for(int i = 0; i < objectClasses.size(); i++) {
+                // if object parameter can be assigned from element in Class 
+                // vector add to history
+                if (objectClass.isAssignableFrom(objectClasses.get(i))) {
+                    history.add(objectParams.get(i));
+                }
+            }
+        }
+        return history;
+    }
+
+    /**
+     * Gets the appropriate history for the type param
+     * 
+     * @param typeParam
+     *            the type parameter
+     * @return the List containing the appropriate history of invocations
+     */
+    public List<String> getHistory(TypeParamView typeParam)
+    {
+        return typeParams.get(typeParam.toString());
+    }
+
+    public void addCall(TypeParamView typeParam, String parameter)
+    {
+        List<String> history = typeParams.get(typeParam.toString());
+        if(history == null) {
+            history = new ArrayList<String>();
+            typeParams.put(typeParam.toString(), history);
+        }
+        history.add(parameter);        
+    }
+
+    /**
+     * Adds a call to the history of a particular datatype
+     * 
+     * @param objectType
+     *            the object's class
+     * @param argument
+     *            the parameter
+     */
+    public void addCall(Class<?> objectType, String argument)
+    {
+        if(argument != null) {
+            // if a primitive or String
+            if(objectTypes.containsKey(objectType.getName())) {
+
+                List<String> history = getHistory(objectType);
+                int index = history.indexOf(argument);
+    
+                // if first no change
+                if (index != 0) {
+                    // if already there remove
+                    if(index > 0) {
+                        history.remove(index);
+                    }
+                    history.add(0, argument);
+                }
+                // trim to size if necessary
+                if(history.size() > historyLength) {
+                    history.remove(historyLength);
+                }
+            }
+            //else add to other object's class and param vectors
+            else {
+                int index = objectParams.indexOf(argument);
+        
+                // if first no change
+                if( index != 0) {
+                    // if already there remove
+                    if(index > 0) {
+                        objectParams.remove(index);
+                        objectClasses.remove(index);
+                    }
+                    objectClasses.add(0, objectType);
+                    objectParams.add(0, argument);
+                }
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ClassHistory.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ClassHistory.java
new file mode 100644
index 0000000000000000000000000000000000000000..40ccd7ceacd9d4a21f96bc0fb02eb99b702590c7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ClassHistory.java
@@ -0,0 +1,67 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+
+/** 
+ * This class implements a singleton history object for library class
+ * invocations.
+ *
+ * @author Michael Kolling
+ * @version $Id: ClassHistory.java 6215 2009-03-30 13:28:25Z polle $
+ *
+ */
+public class ClassHistory extends History
+{
+    // ======= static (factory) section =======
+
+    private static ClassHistory classHistory = null;
+
+    /**
+     * Get the class history singleton. The first time this method
+     * is called, the 'maxLength' parameter determines the history
+     * size. The parameter has no effect on subsequent calls.
+     */
+    public static ClassHistory getClassHistory(int maxLength)
+    {
+        if(classHistory == null)
+            classHistory = new ClassHistory(maxLength);
+        return classHistory;
+    }
+
+    // ======= instance section =======
+
+    /**
+     * Initialise this history with some often-used classes for convinience.
+     */
+    private ClassHistory(int maxLength)
+    {
+        super(maxLength, false);
+        put("java.lang.String");
+        put("java.lang.Math");
+        put("java.util.ArrayList");
+        put("java.util.Random");
+        put("java.util.");
+        put("java.awt.");
+        put("javax.swing.");
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ConstructAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ConstructAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa5393334fc3f6fee4a5f837ad4bfc95935ee950
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ConstructAction.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import bluej.debugmgr.objectbench.InvokeListener;
+import bluej.views.ConstructorView;
+
+/**
+ * Simple action to construct an object.
+ * 
+ * @author Davin McCall
+ * @version $Id$
+ */
+public class ConstructAction extends AbstractAction
+{
+    private ConstructorView constructor;
+    private InvokeListener invokeListener;
+    
+    public ConstructAction(ConstructorView cv, InvokeListener il, String desc)
+    {
+        super(desc);
+        constructor = cv;
+        invokeListener = il;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        invokeListener.callConstructor(constructor);
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ConstructorDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ConstructorDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..fbad3d3b2973a51a31419c5890208ca6dfeda453
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ConstructorDialog.java
@@ -0,0 +1,334 @@
+package bluej.debugmgr;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugmgr.objectbench.ObjectBenchInterface;
+import bluej.utility.JavaNames;
+import bluej.views.CallableView;
+import bluej.views.ConstructorView;
+import bluej.views.LabelPrintWriter;
+import bluej.views.TypeParamView;
+import bluej.views.View;
+
+public class ConstructorDialog extends CallDialog
+{
+    // Window Titles
+    private static final String appName = Config.getApplicationName(); 
+    private static final String wCreateTitle = appName + ":  " + Config.getString("pkgmgr.methodCall.titleCreate");
+    // MD_CREATE Specific
+    static final String sNameOfInstance = Config.getString("pkgmgr.methodCall.namePrompt");
+    static final String sTypeParameters = Config.getString("pkgmgr.methodCall.typeParametersPrompt");
+    static final String sTypeParameter = Config.getString("pkgmgr.methodCall.typeParameterPrompt");
+    static final String illegalNameMsg = Config.getString("error.methodCall.illegalName");
+    static final String duplicateNameMsg = Config.getString("error.methodCall.duplicateName");
+
+    private JTextField instanceNameText;
+    private ConstructorView constructor;
+
+    private boolean okCalled;
+
+    /**
+     * MethodDialog constructor.
+     * 
+     * @param parentFrame  The parent window for the dialog
+     * @param ob           The object bench to listen for object selection on
+     * @param callHistory  The call history tracker
+     * @param initialName  The initial (suggested) instance name
+     * @param method       The constructor or method being used
+     * @param typeMap      The mapping of type parameter names to runtime types
+     *                     (a Map of String -> GenType).
+     */
+    public ConstructorDialog(JFrame parentFrame, ObjectBenchInterface ob, CallHistory callHistory,
+            String initialName, ConstructorView constructor)
+    {
+        super(parentFrame, ob, "");
+
+        history = callHistory;
+
+        this.constructor = constructor;
+        makeDialog(constructor.getClassName(), initialName);
+        setInstanceInfo(initialName);
+    }
+    
+    /*
+     * @see bluej.debugmgr.CallDialog#makeDialogInternal(java.lang.String, java.lang.String, javax.swing.JPanel)
+     */
+    @Override
+    protected void makeDialogInternal(String className, String instanceName, JPanel centerPanel)
+    {
+        makeCreateDialog(className, instanceName, constructor, centerPanel);
+    }
+    
+    /**
+     * makeCreateDialog - create a dialog to create an object (including
+     *  constructor call)
+     */
+    private void makeCreateDialog(String className, String instanceName, CallableView method,
+            JPanel panel)
+    {
+        setTitle(wCreateTitle);
+
+        JLabel instName = new JLabel(sNameOfInstance);
+        instanceNameText = new JTextField(instanceName, 16);
+        // treat 'return' in text field as OK
+        instanceNameText.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent evt)
+            {
+                doOk();
+            }
+        });
+        instanceNameText.addFocusListener(new FocusListener() {
+            public void focusGained(FocusEvent fe)
+            {
+                ((JTextField) (fe.getComponent())).selectAll();
+            }
+
+            public void focusLost(FocusEvent fe)
+            {
+            }
+        });
+
+        JPanel tmpPanel = new JPanel();
+        tmpPanel.setOpaque(false);
+
+        GridBagLayout gridBag = new GridBagLayout();
+        tmpPanel.setLayout(gridBag);
+        GridBagConstraints constraints = new GridBagConstraints();
+        constraints.insets = INSETS;
+        constraints.gridy = 0;
+        constraints.gridx = 0;
+        gridBag.setConstraints(instName, constraints);
+        if(!Config.isGreenfoot()) {
+            tmpPanel.add(instName);
+        }
+        constraints.gridx = 1;
+        constraints.gridwidth = 1;
+        constraints.anchor = GridBagConstraints.WEST;
+        constraints.fill = GridBagConstraints.HORIZONTAL;
+        gridBag.setConstraints(instanceNameText, constraints);
+        if(!Config.isGreenfoot()) {
+            tmpPanel.add(instanceNameText);
+        }
+
+        View clazz = method.getDeclaringView();
+        if (clazz.isGeneric()) {
+            JLabel name = null;
+            if(getFormalTypeParams(constructor).length > 1) {
+                name = new JLabel(sTypeParameters);
+            } else {
+                name = new JLabel(sTypeParameter);
+            }
+            constraints.gridwidth = 1;
+            constraints.gridx = 0;
+            constraints.gridy++;
+            constraints.anchor = GridBagConstraints.NORTHWEST;
+            constraints.fill = GridBagConstraints.NONE;
+            setPreferredHeight(name, getComboBoxHeight());
+            gridBag.setConstraints(name, constraints);
+            tmpPanel.add(name);
+
+            JPanel typeParameterPanel = createTypeParameterPanel();
+            typeParameterPanel.setOpaque(false);
+            constraints.gridwidth = 1;
+            constraints.gridx = 1;
+            constraints.anchor = GridBagConstraints.WEST;
+            constraints.fill = GridBagConstraints.NONE;
+            tmpPanel.add(typeParameterPanel, constraints);
+        }
+
+        if (method.hasParameters()) {
+            JLabel name = new JLabel("new " + className, JLabel.RIGHT);
+            constraints.gridwidth = 1;
+            constraints.gridx = 0;
+            constraints.gridy++;
+            constraints.anchor = GridBagConstraints.NORTHEAST;
+            constraints.fill = GridBagConstraints.NONE;
+            setPreferredHeight(name, getComboBoxHeight());
+            gridBag.setConstraints(name, constraints);
+            tmpPanel.add(name);
+
+            constraints.anchor = GridBagConstraints.WEST;
+            constraints.gridx = 1;
+            constraints.fill = GridBagConstraints.HORIZONTAL;
+            JPanel parameterPanel = createParameterPanel();
+            parameterPanel.setOpaque(false);
+            tmpPanel.add(parameterPanel, constraints);
+
+            constraints.gridx = 3;
+            constraints.gridy = 0;
+            constraints.weightx = 1.0;
+            JPanel filler = new JPanel();
+            filler.setOpaque(false);
+            gridBag.setConstraints(filler, constraints);
+            tmpPanel.add(filler);
+        }
+
+        tmpPanel.setBorder(BorderFactory.createEmptyBorder(BlueJTheme.generalSpacingWidth, 0,
+                BlueJTheme.generalSpacingWidth, 0));
+        panel.add(tmpPanel, BorderLayout.NORTH);
+    } // makeCreateDialog
+
+    /**
+     * setInstanceName - set the name of the instance shown in the label
+     * for method call dialogs, or in the text field for construction dialogs,
+     * and the assosciated type parameters.
+     */
+    public void setInstanceInfo(String instanceName)
+    {
+        instanceNameText.setText(instanceName);
+        createDescription();
+        
+        // reset error label message
+        setErrorMessage("");
+
+        clearParameters();
+        startObjectBenchListening();
+
+        // focus requests have been wrapped in invokeLater method to resolve issues 
+        // with focus confusion on Mac OSX (BlueJ 2.0, JDK 1.4.2)
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run()
+            {
+                if (!Config.isGreenfoot()) {
+                    instanceNameText.requestFocusInWindow();
+                }
+                else if (typeParameterList != null) {
+                    typeParameterList.getParameter(0).getEditor().getEditorComponent().requestFocusInWindow();
+                }
+                else if (parameterList != null) {
+                    parameterList.getParameter(0).getEditor().getEditorComponent().requestFocusInWindow();
+                }
+            }
+        });
+    }
+
+    /**
+     * Create the description. This includes the comments for the method
+     * or constructor, together with its signature, and appears at the top
+     * of the dialog.
+     */
+    private void createDescription()
+    {
+        LabelPrintWriter writer = new LabelPrintWriter();
+        constructor.print(writer);
+        setDescription(writer.getLabel());
+        setVisible(true);
+    }
+
+    /**
+     * Creates a panel of type parameters for a new object
+     */
+    private JPanel createTypeParameterPanel()
+    {
+        TypeParamView formalTypeParams[] = getFormalTypeParams(constructor);
+
+        typeParameterList = new ParameterList(formalTypeParams.length, defaultParamValue, false);
+        for (int i = 0; i < formalTypeParams.length; i++) {
+            List<String> historyList = history.getHistory(formalTypeParams[i]);            
+            JComboBox component = createComboBox(historyList);
+            typeParameterList.addParameter(i, component, formalTypeParams[i].toString());
+        }
+        String startString = "<";
+        String endString = ">";
+        ParameterList superParamList = typeParameterList;
+        return createParameterPanel(startString, endString, superParamList);
+    }
+
+    /**
+     * doOk - Process an "Ok" event to invoke a Constructor or Method.
+     * Collects arguments and calls watcher objects (Invoker).
+     */
+    public void doOk()
+    {
+        if(!okCalled) {
+            if (!JavaNames.isIdentifier(getNewInstanceName())) {
+                setErrorMessage(illegalNameMsg);
+                return;
+            }
+            ObjectBenchInterface ob = getObjectBench();
+            if (ob != null && ob.hasObject(getNewInstanceName())) {
+                setErrorMessage(duplicateNameMsg);
+                return;
+            }
+            
+            if (!parameterFieldsOk()) {
+                setErrorMessage(emptyFieldMsg);            
+            } else if (!typeParameterFieldsOk()) {     
+                setErrorMessage(emptyTypeFieldMsg);
+            } else {
+                setWaitCursor(true);
+                okButton.requestFocus();
+                SwingUtilities.invokeLater(new Runnable()
+                {
+                    public void run()
+                    {
+                        callWatcher(OK);
+                    }
+                });
+                okCalled = true;
+            }
+        }
+    }
+
+    /**
+     * Redefined setEnabled method to ensure that OK button gets disabled.
+     * As ActionListeners are also attached to combo boxes it can trigger 
+     * more than one OK action as the default button also catches an 
+     * action whther it has focus or not.
+     * 
+     * <p>Calling setEnabled on the Dialog alone does not prevent the default button 
+     * from getting action events. We therefore explicitly call setEnabled on the 
+     * default button (OK)
+     * 
+     * <p>The okCalled flag is used to prevent multiple rapid button presses before
+     * the button and dialog are disabled.
+     */
+    public void setEnabled(boolean state)
+    {
+        okButton.setEnabled(state);
+        super.setEnabled(state);
+        if(state) {
+            //reset ok called status when re-enabling dialog
+            okCalled = false;    
+        }
+    }
+    
+    /**
+     * getNewInstanceName - get the contents of the instance name field.
+     */
+    public String getNewInstanceName()
+    {
+        if (instanceNameText == null) {
+            return "";
+        }
+        else {
+            return instanceNameText.getText().trim();
+        }
+    }
+    
+    /*
+     * @see bluej.debugmgr.CallDialog#getCallableView()
+     */
+    @Override
+    protected CallableView getCallableView()
+    {
+        return constructor;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExecControlButtonModel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExecControlButtonModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..609f86fb6b6d421a23fe6303c819c1bae07ae106
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExecControlButtonModel.java
@@ -0,0 +1,69 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import javax.swing.JToggleButton;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * ButtonModel for the "Show Debugger" checkBoxItem in the menu.
+ * This model takes care that the right things happen when the checkbox
+ * is shown or changed.
+ *
+ * @author Michael Kolling
+ */
+public class ExecControlButtonModel extends JToggleButton.ToggleButtonModel
+{
+	private PkgMgrFrame pmf;
+	
+    public ExecControlButtonModel(PkgMgrFrame pmf)
+    {
+        super();
+        this.pmf = pmf;
+    }
+
+    public boolean isSelected()
+    {
+    	if (pmf.isEmptyFrame()) {
+			// if no project is open, we default to off
+			return false;
+    	}
+    	else if (!pmf.getProject().hasExecControls()) {
+			// we don't want to create the ExecControls frame unless we
+			// have to, so if its not made yet, default to off
+			return false;
+    	}
+    	else {
+			// otherwise, ask the ExecControls if they're visible
+			return pmf.getProject().getExecControls().isVisible();
+    	}
+    }
+
+    public void setSelected(boolean b)
+    {
+		if (!pmf.isEmptyFrame()) {
+			super.setSelected(b);
+			pmf.getProject().getExecControls().showHide(b);
+		}
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExecControls.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExecControls.java
new file mode 100644
index 0000000000000000000000000000000000000000..02e3be841ac1e30995193a147442db62ef988117
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExecControls.java
@@ -0,0 +1,968 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.EventQueue;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JSplitPane;
+import javax.swing.JTree;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.DebuggerThread;
+import bluej.debugger.DebuggerThreadTreeModel;
+import bluej.debugger.DebuggerThreadTreeModel.SyncMechanism;
+import bluej.debugger.SourceLocation;
+import bluej.debugmgr.inspector.Inspector;
+import bluej.pkgmgr.Project;
+import bluej.utility.GradientFillPanel;
+import bluej.utility.JavaNames;
+
+/**
+ * Window for controlling the debugger
+ *
+ * @author  Michael Kolling
+ */
+public class ExecControls extends JFrame
+    implements ListSelectionListener, TreeSelectionListener, TreeModelListener
+{
+    private static final String stackTitle =
+        Config.getString("debugger.execControls.stackTitle");
+    private static final String staticTitle =
+        Config.getString("debugger.execControls.staticTitle");
+    private static final String instanceTitle =
+        Config.getString("debugger.execControls.instanceTitle");
+    private static final String localTitle =
+        Config.getString("debugger.execControls.localTitle");
+    private static final String threadTitle =
+        Config.getString("debugger.execControls.threadTitle");
+
+    private static final String haltButtonText =
+        Config.getString("debugger.execControls.haltButtonText");
+    private static final String stepButtonText =
+        Config.getString("debugger.execControls.stepButtonText");
+    private static final String stepIntoButtonText =
+        Config.getString("debugger.execControls.stepIntoButtonText");
+    private static final String continueButtonText =
+        Config.getString("debugger.execControls.continueButtonText");
+    private static final String terminateButtonText =
+        Config.getString("debugger.execControls.terminateButtonText");
+
+    private static final int SHORTCUT_MASK =
+        Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+
+    private static String[] empty = new String[0];
+
+    // === instance ===
+
+    // the display for the list of active threads
+    private JTree threadTree; 
+    private DebuggerThreadTreeModel threadModel;
+    
+    private JComponent mainPanel;
+    private JList stackList, staticList, instanceList, localList;
+    private JButton stopButton, stepButton, stepIntoButton, continueButton, terminateButton;
+    private CardLayout cardLayout;
+    private JPanel flipPanel;
+    private JCheckBoxMenuItem systemThreadItem;
+
+    // the Project that owns this debugger
+    private Project project;
+
+    // the debug machine this control is looking at
+    private Debugger debugger = null;
+    
+    // the thread currently selected
+    private DebuggerThread selectedThread;
+
+    private DebuggerClass currentClass;     // the current class for the
+                                            //  selected stack frame
+    private DebuggerObject currentObject;   // the "this" object for the
+                                            //  selected stack frame
+    private int currentFrame = 0;           // currently selected frame
+    
+    // A flag to keep track of whether a stack frame selection was performed
+    // explicitly via the gui or as a result of a debugger event
+    private boolean autoSelectionEvent = false; 
+    
+    /**
+     * Fields from these classes (key from map) are only shown if they are in the corresponding whitelist
+     * of fields (corresponding value from map)
+     */
+    private Map<String, Set<String>> restrictedClasses = Collections.emptyMap(); 
+    
+
+    /**
+     * Create a window to view and interact with a debug VM.
+     * 
+     * @param project  the project this window is associated with
+     * @param debugger the debugger this window is debugging
+     */
+    public ExecControls(Project project, Debugger debugger)
+    {
+        super(Config.getApplicationName() + ":  " + Config.getString("debugger.execControls.windowTitle"));
+
+        if (project == null || debugger == null) {
+            throw new NullPointerException("project or debugger null in ExecControls");
+        }
+
+        this.project = project;
+        this.debugger = debugger;
+
+        createWindow();
+    }
+
+    /**
+     * Show or hide the ExecControl window.
+     */
+    public void showHide(boolean show)
+    {
+        setVisible(show);
+    }
+    
+    /**
+     * Sets the restricted classes - classes for which only some fields should be displayed.
+     * 
+     * @param restrictedClasses a map of class name to a set of white-listed fields.
+     */
+    public void setRestrictedClasses(Map<String, Set<String>> restrictedClasses)
+    {
+        this.restrictedClasses = restrictedClasses;
+    }
+
+
+    // ----- ListSelectionListener interface -----
+
+    /**
+     * A list item was selected. This can be either in the
+     * stack list, or one of the variable lists.
+     */
+    public void valueChanged(ListSelectionEvent event)
+    {
+        // ignore mouse down, dragging, etc.
+        if(event.getValueIsAdjusting()) {
+            return;
+        }
+
+        if(event.getSource() == stackList) {
+            selectStackFrame(stackList.getSelectedIndex());
+        }
+    }
+
+    // ----- end of ListSelectionListener interface -----
+
+    // ----- TreeSelectionListener interface -----
+
+    /**
+     * A tree item was selected. This is in the thread list.
+     */
+    public void valueChanged(TreeSelectionEvent event)
+    {
+        Object src = event.getSource();
+
+        if(src == threadTree) {
+            clearThreadDetails();
+
+            // check for "unselecting" a node
+            // (happens when the VM is restarted)
+            if (!event.isAddedPath()) {
+                setSelectedThread(null);
+                return;
+            }
+
+            DefaultMutableTreeNode node =
+                (DefaultMutableTreeNode) threadTree.getLastSelectedPathComponent();
+
+            if (node == null) {
+                return;
+            }
+
+            DebuggerThread dt = threadModel.getNodeAsDebuggerThread(node);        
+
+            // the thread can not be found, dt will end up as null and
+            // the selected thread will be cleared
+            setSelectedThread(dt);
+        }
+    }
+
+    // ----- end of TreeSelectionListener interface -----
+
+    // ----- TreeModelListener interface -----
+
+    /**
+     * When a thread changes state in the tree, we may need to update
+     * the controls for the selected thread.
+     */
+    public void treeNodesChanged(TreeModelEvent e)
+    {
+        if (selectedThread == null) {
+            return;
+        }
+
+        Object nodes[] = e.getChildren();
+
+        for(int i=0; i<nodes.length; i++) {
+            if (nodes[i] == null) {
+                continue;
+            }
+
+            if (selectedThread.equals(threadModel.getNodeAsDebuggerThread(nodes[i]))) {
+                setSelectedThread(selectedThread);
+            }
+        }
+    }
+
+    public void treeNodesInserted(TreeModelEvent e) { }
+    public void treeNodesRemoved(TreeModelEvent e) { }
+    public void treeStructureChanged(TreeModelEvent e) { }
+
+    // ----- end of TreeModelListener interface -----
+
+    /**
+     * A list item was double clicked.
+     * 
+     * This will be in one of the variable lists. We try to
+     * view the relevant object that was double clicked on.
+     */
+    private void listDoubleClick(MouseEvent event)
+    {
+        Component src = event.getComponent();
+
+        if(src == staticList && staticList.getSelectedIndex() >= 0) {
+            viewStaticField(staticList.getSelectedIndex());
+        }
+        else if(src == instanceList && instanceList.getSelectedIndex() >= 0) {
+            viewInstanceField((DebuggerField) instanceList.getSelectedValue());
+        }
+        else if(src == localList && localList.getSelectedIndex() >= 0) {
+            viewLocalVar(localList.getSelectedIndex());
+        }
+    }
+
+    /**
+     * Checks to make sure that a particular thread is
+     * selected in the thread tree. Often when we get to this,
+     * the thread in question should already be selected so
+     * in that case we should not cause any more events, or
+     * we'll end in a cycle.
+     * 
+     * If the thread is already selected, this method
+     * will ensure that the status details are up to date.
+     * 
+     * @param  dt  the thread to hilight in the thread
+     *             tree and whose status we want to display.
+     */
+    public void makeSureThreadIsSelected(final DebuggerThread dt)
+    {
+        TreePath tp = threadModel.findNodeForThread(dt);
+
+        if (tp != null) {
+            if (!tp.equals(threadTree.getSelectionPath())) {
+                threadTree.clearSelection();
+                threadTree.addSelectionPath(tp);
+            }
+            
+            // There seems to be a swing glitch causing the thread-tree scrollpane
+            // to be reduced to a very small size by the divider. Doing a paint
+            // here seems to fix it.
+            mainPanel.paintImmediately(0,0,mainPanel.getSize().width,mainPanel.getSize().height);
+        }
+    }
+
+    /**
+     * Set our internally selected thread and update the
+     * UI to reflect its status.
+     *
+     * <p>This does not actually highlight the selected thread - use makeSureThreadIsSelected()
+     * for that.
+     * 
+     * @see #makeSureThreadIsSelected(DebuggerThread)
+     * 
+     * @param dt  the thread to select or null if the thread
+     *            selection has been cleared
+     */
+    public void setSelectedThread(DebuggerThread dt)
+    {
+        selectedThread = dt;
+
+        if (dt == null) {
+            stopButton.setEnabled(false);
+            stepButton.setEnabled(false);
+            stepIntoButton.setEnabled(false);
+            continueButton.setEnabled(false);
+
+            cardLayout.show(flipPanel, "blank");
+        }
+        else {
+            boolean isSuspended = selectedThread.isSuspended();
+
+            stopButton.setEnabled(!isSuspended);
+            stepButton.setEnabled(isSuspended);
+            stepIntoButton.setEnabled(isSuspended);
+            continueButton .setEnabled(isSuspended);
+
+            cardLayout.show(flipPanel, isSuspended ? "split" : "blank");
+
+            setThreadDetails();
+        }
+    }
+
+    /**
+     * Display the details for the currently selected thread.
+     * These details include showing the threads stack, and displaying 
+     * the details for the top stack frame.
+     */
+    private void setThreadDetails()
+    {
+        stackList.setFixedCellWidth(-1);
+        //Copy the list because we may alter it:
+        LinkedList<SourceLocation> stack = new LinkedList<SourceLocation>(selectedThread.getStack());
+        SourceLocation[] filtered = getFilteredStack(stack);
+        if(filtered.length > 0) {
+            stackList.setListData(filtered);
+            // show details of top frame
+            autoSelectionEvent = true;
+            selectStackFrame(0);
+            autoSelectionEvent = false;
+        }
+    }
+    
+    public static SourceLocation [] getFilteredStack(List<SourceLocation> stack)
+    {
+        int first = -1;
+        int i;
+        for (i = 0; i < stack.size(); i++) {
+            SourceLocation loc = stack.get(i);
+            String className = loc.getClassName();
+
+            // ensure that the bluej.runtime.ExecServer frames are not shown
+            if (className.startsWith("bluej.runtime.") && !className.equals(bluej.runtime.BJInputStream.class.getCanonicalName())) {
+                break;
+            }
+
+            // must getBase on classname so that we find __SHELL
+            // classes in other packages ie a.b.__SHELL
+            // if it is a __SHELL class, stop processing the stack
+            if (JavaNames.getBase(className).startsWith("__SHELL")) {
+                break;
+            }
+            
+            if (Config.isGreenfoot() && className.startsWith("greenfoot.core.")) {
+                break;
+            }
+            
+            // Topmost stack location shown will have source available!
+            if (first == -1 && loc.getFileName() != null) {
+                first = i;
+            }
+        }
+        
+        if (first == -1 || i == 0) {
+            return new SourceLocation[0];
+        }
+        
+        SourceLocation[] filtered = new SourceLocation[i - first];
+        for (int j = first; j < i; j++) {
+            filtered[j - first] = stack.get(j);
+        }
+        
+        return filtered;
+    }
+    
+    /**
+     * Clear the display of thread details (stack and variables).
+     */
+    private void clearThreadDetails()
+    {
+        stackList.setListData(empty);
+        staticList.setListData(empty);
+        instanceList.setListData(empty);
+        localList.setListData(empty);
+    }
+
+    /**
+     * Make a stack frame in the stack display the selected stack frame.
+     * This will cause this frame's details (local variables, etc.) to be
+     * displayed, as well as the current source position being marked.
+     */
+    private void selectStackFrame(int index)
+    {
+        // if the UI isn't up to date, make sure the correct frame is
+        // selected in the list
+        if (stackList.getSelectedIndex() != index) {
+            stackList.setSelectedIndex(index);
+        }
+        else if (index >= 0) {
+            setStackFrameDetails(index);
+            selectedThread.setSelectedFrame(index);
+                
+            if (! autoSelectionEvent) {
+                project.showSource(selectedThread);
+            }
+            
+            currentFrame = index;
+        }
+    }
+
+    /**
+     * Display the detail information (current object fields and local var's)
+     * for a specific stack frame.
+     */
+    private void setStackFrameDetails(int frameNo)
+    {
+        currentClass = selectedThread.getCurrentClass(frameNo);
+        currentObject = selectedThread.getCurrentObject(frameNo);
+        if(currentClass != null) {
+            staticList.setFixedCellWidth(-1);
+            List<DebuggerField> fields = currentClass.getStaticFields();
+            List<String> listData = new ArrayList<String>(fields.size());
+            for (DebuggerField field : fields) {
+                String declaringClass = field.getDeclaringClassName();
+                Set<String> whiteList = restrictedClasses.get(declaringClass);
+                if (whiteList == null || whiteList.contains(field.getName())) {
+                    listData.add(Inspector.fieldToString(field) + " = " + field.getValueString());
+                }
+            }
+            staticList.setListData(listData.toArray(new String[listData.size()]));
+        }
+        
+        instanceList.setFixedCellWidth(-1);
+        if(currentObject != null && !currentObject.isNullObject()) {
+            List<DebuggerField> fields = currentObject.getFields();
+            List<DebuggerField> listData = new ArrayList<DebuggerField>(fields.size());
+            for (DebuggerField field : fields) {
+                if (! Modifier.isStatic(field.getModifiers())) {
+                    String declaringClass = field.getDeclaringClassName();
+                    Set<String> whiteList = restrictedClasses.get(declaringClass);
+                    if (whiteList == null || whiteList.contains(field.getName())) {
+                        listData.add(field);
+                    }
+                }
+            }
+            instanceList.setListData(listData.toArray(new DebuggerField[listData.size()]));
+        }
+        else {
+            instanceList.setListData(new String[0]);
+        }
+        
+        if(selectedThread != null) {
+            localList.setFixedCellWidth(-1);
+            localList.setListData(selectedThread.getLocalVariables(frameNo).toArray());
+        }
+    }
+
+    /**
+     * Display an object inspector for an object in a static field.
+     */
+    private void viewStaticField(int index)
+    {
+        DebuggerField field = currentClass.getStaticField(index);
+        if(field.isReferenceType() && ! field.isNull()) {
+            project.getInspectorInstance(field.getValueObject(null), null, null, null, this);
+        }
+    }
+
+    /**
+     * Display an object inspector for an object in an instance field.
+     */
+    private void viewInstanceField(DebuggerField field)
+    {
+        if(field.isReferenceType() && ! field.isNull()) {
+            project.getInspectorInstance(field.getValueObject(null), null, null, null, this);
+        }
+    }
+
+    /**
+     * Display an object inspector for an object in a local variable.
+     */
+    private void viewLocalVar(int index)
+    {
+        if(selectedThread.varIsObject(currentFrame, index)) {
+            project.getInspectorInstance(selectedThread.getStackObject(currentFrame, index),
+                           null, null, null, this);
+        }
+    }
+
+    /**
+     * Create and arrange the GUI components.
+     */
+    private void createWindow()
+    {
+        Image icon = BlueJTheme.getIconImage();
+        if (icon != null) {
+            setIconImage(icon);
+        }
+    
+        setJMenuBar(makeMenuBar());
+
+        JPanel contentPane = new GradientFillPanel(new BorderLayout(6,6));
+        setContentPane(contentPane);
+        contentPane.setBorder(BorderFactory.createEmptyBorder(8,8,8,8));
+
+        // Create the control button panel
+
+        JPanel buttonBox = new JPanel();
+        buttonBox.setOpaque(false);
+        {
+            buttonBox.setLayout(new GridLayout(1,0));
+
+            stopButton = addButton(new StopAction(), buttonBox);
+            stepButton = addButton(new StepAction(), buttonBox);
+            stepIntoButton = addButton(new StepIntoAction(), buttonBox);
+            continueButton = addButton(new ContinueAction(), buttonBox);
+
+            // terminate is always on
+            terminateButton = addButton(new TerminateAction(), buttonBox);
+            terminateButton.setEnabled(true);
+        }
+
+        contentPane.add(buttonBox, BorderLayout.SOUTH);
+
+        // create a mouse listener to monitor for double clicks
+        MouseListener mouseListener = new MouseAdapter() {
+            public void mouseClicked(MouseEvent e) {
+                if (e.getClickCount() == 2) {
+                    listDoubleClick(e);
+                }
+            }
+        };
+
+        // create static variable panel
+        JScrollPane staticScrollPane = new JScrollPane();
+        {
+            staticList = new JList(new DefaultListModel());
+            {
+                staticList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+                staticList.addListSelectionListener(this);
+                staticList.setVisibleRowCount(3);
+                staticList.setFixedCellWidth(150);
+                staticList.addMouseListener(mouseListener);
+            }
+            staticScrollPane.setViewportView(staticList);
+            JLabel lbl = new JLabel(staticTitle);
+            lbl.setOpaque(true);
+            staticScrollPane.setColumnHeaderView(lbl);
+        }
+
+        // create instance variable panel
+        JScrollPane instanceScrollPane = new JScrollPane();
+        {
+            instanceList = new JList(new DefaultListModel());
+            {
+                instanceList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+                instanceList.addListSelectionListener(this);
+                instanceList.setVisibleRowCount(4);
+                instanceList.setFixedCellWidth(150);
+                instanceList.addMouseListener(mouseListener);
+                instanceList.setCellRenderer(new FieldCellRenderer());
+            }
+            instanceScrollPane.setViewportView(instanceList);
+            JLabel lbl = new JLabel(instanceTitle);
+            lbl.setOpaque(true);
+            instanceScrollPane.setColumnHeaderView(lbl);
+        }
+
+        // create local variable panel
+        JScrollPane localScrollPane = new JScrollPane();
+        {
+            localList = new JList(new DefaultListModel());
+            {
+                localList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+                localList.addListSelectionListener(this);
+                localList.setVisibleRowCount(4);
+                localList.setFixedCellWidth(150);
+                localList.addMouseListener(mouseListener);
+            }
+            localScrollPane.setViewportView(localList);
+            JLabel lbl = new JLabel(localTitle);
+            lbl.setOpaque(true);
+            localScrollPane.setColumnHeaderView(lbl);
+        }
+
+        // Create variable display area
+
+        JSplitPane innerVarPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+                                                 staticScrollPane, instanceScrollPane);
+        innerVarPane.setDividerSize(6);
+        innerVarPane.setBorder(null);
+        innerVarPane.setOpaque(false);
+
+        JSplitPane varPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+                                            innerVarPane, localScrollPane);
+        varPane.setDividerSize(6);
+        varPane.setBorder(null);
+        varPane.setOpaque(false);
+
+        // Create stack listing panel
+
+        stackList = new JList(new DefaultListModel());
+        stackList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        stackList.addListSelectionListener(this);
+        stackList.setFixedCellWidth(150);
+        JScrollPane stackScrollPane = new JScrollPane(stackList);
+        JLabel lbl = new JLabel(stackTitle);
+        lbl.setOpaque(true);
+        stackScrollPane.setColumnHeaderView(lbl);
+
+        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+                                              stackScrollPane, varPane);
+        splitPane.setDividerSize(6);
+        splitPane.setBorder(null);
+        splitPane.setOpaque(false);
+
+        // Create thread panel
+        JPanel threadPanel = new JPanel(new BorderLayout());
+        threadPanel.setOpaque(false);
+
+
+        MouseListener treeMouseListener = new MouseAdapter() {
+            public void mousePressed(MouseEvent e) {
+                TreePath selPath = threadTree.getPathForLocation(e.getX(), e.getY());
+                if(selPath != null) {
+                    DefaultMutableTreeNode node =
+                        (DefaultMutableTreeNode) selPath.getLastPathComponent();
+
+                    if (node != null) {
+                        DebuggerThread dt = threadModel.getNodeAsDebuggerThread(node);        
+
+                        if (dt != null) {
+                            setSelectedThread(dt);
+                        }
+                    }
+                }
+            }
+        };
+
+        threadModel = debugger.getThreadTreeModel();
+        threadModel.setSyncMechanism(new SyncMechanism() {
+            public void invokeLater(Runnable r)
+            {
+                if(EventQueue.isDispatchThread())
+                    r.run();
+                else
+                    EventQueue.invokeLater(r);
+            }
+        });
+        threadModel.addTreeModelListener(this);
+
+        threadTree = new JTree(threadModel);
+        {
+            threadTree.getSelectionModel().
+            setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+            threadTree.setVisibleRowCount(5);
+            threadTree.setShowsRootHandles(false);
+            threadTree.setRootVisible(false);
+            threadTree.addTreeSelectionListener(this);             
+            threadTree.addMouseListener(treeMouseListener);
+        }
+
+        JScrollPane threadScrollPane = new JScrollPane(threadTree);
+        lbl = new JLabel(threadTitle);
+        lbl.setOpaque(true);
+        threadScrollPane.setColumnHeaderView(lbl);
+        threadPanel.add(threadScrollPane, BorderLayout.CENTER);
+        //threadPanel.setMinimumSize(new Dimension(100,100));
+
+        flipPanel = new JPanel();
+        flipPanel.setOpaque(false);
+        {
+            flipPanel.setLayout(cardLayout = new CardLayout());
+
+            flipPanel.add(splitPane, "split");
+            JPanel tempPanel = new JPanel();
+            JLabel infoLabel = new JLabel(Config.getString("debugger.threadRunning"));
+            infoLabel.setForeground(Color.gray);
+            tempPanel.add(infoLabel);
+            flipPanel.add(tempPanel, "blank");
+        }
+
+        if (Config.isGreenfoot()) {
+            mainPanel = flipPanel;
+        } else {
+        /* JSplitPane */ mainPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+                                              threadPanel, flipPanel);
+            ((JSplitPane)mainPanel).setDividerSize(6);
+            mainPanel.setOpaque(false);
+        }
+        
+        contentPane.add(mainPanel, BorderLayout.CENTER);
+
+        // Close Action when close button is pressed
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent event) {
+                Window win = (Window)event.getSource();
+                win.setVisible(false);
+            }
+            
+        });
+
+        // save position when window is moved
+        addComponentListener(new ComponentAdapter() {
+            public void componentMoved(ComponentEvent event){
+                Config.putLocation("bluej.debugger", getLocation());
+            }
+        });
+
+        setLocation(Config.getLocation("bluej.debugger"));
+
+        pack();
+    }
+
+    /**
+     * Create the debugger's menubar, all menus and items.
+     */
+    private JMenuBar makeMenuBar()
+    {
+        JMenuBar menubar = new JMenuBar();
+        JMenu menu = new JMenu(Config.getString("terminal.options"));
+
+        
+        if (!Config.isGreenfoot()) {
+            systemThreadItem = new JCheckBoxMenuItem(new HideSystemThreadAction());
+            systemThreadItem.setSelected(true);
+            menu.add(systemThreadItem);
+            menu.add(new JSeparator());
+        }
+        debugger.hideSystemThreads(true);
+
+        menu.add(new CloseAction());
+
+        menubar.add(menu);
+        return menubar;
+    }
+    
+    /**
+     * Create a text & image button and add it to a panel.
+     * 
+     * @param action
+     *            The assosciated Action (with text, icon, action, etc).
+     * @param panel
+     *            The panel to add the button to.
+     */
+    private JButton addButton(Action action, JPanel panel)
+    {
+        JButton button = new JButton(action);
+        button.setVerticalTextPosition(AbstractButton.BOTTOM);
+        button.setHorizontalTextPosition(AbstractButton.CENTER);
+        button.setEnabled(false);
+        panel.add(button);
+        return button;
+    }
+    
+    /**
+     * Action to halt the selected thread.
+     */
+    private class StopAction extends AbstractAction
+    {
+        public StopAction()
+        {
+            super(haltButtonText, Config.getFixedImageAsIcon("stop.gif"));
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            if (selectedThread == null)
+                return;
+            clearThreadDetails();
+            if (!selectedThread.isSuspended()) {
+                selectedThread.halt();
+            }
+        }
+    }
+        
+    /**
+     * Action to step through the code.
+     */
+    private class StepAction extends AbstractAction
+    {
+        public StepAction()
+        {
+            super(stepButtonText, Config.getFixedImageAsIcon("step.gif"));
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            if (selectedThread == null)
+                return;
+            clearThreadDetails();
+            project.removeStepMarks();
+            if (selectedThread.isSuspended()) {
+                selectedThread.step();
+            }
+            project.updateInspectors();
+        }
+    }
+    
+    /**
+     * Action to "step into" the code.
+     */
+    private class StepIntoAction extends AbstractAction
+    {
+        public StepIntoAction()
+        {
+            super(stepIntoButtonText, Config.getFixedImageAsIcon("step_into.gif"));
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            if (selectedThread == null)
+                return;
+            clearThreadDetails();
+            project.removeStepMarks();
+            if (selectedThread.isSuspended()) {
+                selectedThread.stepInto();
+            }
+        }
+    }
+    
+    /**
+     * Action to continue a halted thread. 
+     */
+    private class ContinueAction extends AbstractAction
+    {
+        public ContinueAction()
+        {
+            super(continueButtonText, Config.getFixedImageAsIcon("continue.gif"));
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            if (selectedThread == null)
+                return;
+            clearThreadDetails();
+            project.removeStepMarks();
+            if (selectedThread.isSuspended()) {
+                selectedThread.cont();
+            }
+        }
+    }
+    
+    /**
+     * Action to terminate the program, restart the VM.
+     */
+    private class TerminateAction extends AbstractAction
+    {
+        public TerminateAction()
+        {
+            super(terminateButtonText, Config.getFixedImageAsIcon("terminate.gif"));
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            try {
+                // throws an illegal state exception
+                // if we press this whilst we are already
+                // restarting the remote VM
+                project.restartVM();
+            }
+            catch (IllegalStateException ise) { }
+        }
+    }
+    
+    /**
+     * Action to close the debugger window.
+     */
+    private class CloseAction extends AbstractAction
+    {
+        public CloseAction()
+        {
+            super(Config.getString("close"));
+            putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_W, SHORTCUT_MASK));
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            setVisible(false);
+        }
+    }
+    
+    /**
+     * Action to enable/disable hiding of system threads. All this action
+     * actually does is toggle an internal flag.
+     */
+    private class HideSystemThreadAction extends AbstractAction
+    {
+        public HideSystemThreadAction()
+        {
+            super(Config.getString("debugger.hideSystemThreads"));
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            debugger.hideSystemThreads(systemThreadItem.isSelected());
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExecutionEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExecutionEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c1db0146e7ef58b86aa480765703cddaff07efc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExecutionEvent.java
@@ -0,0 +1,232 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugger.gentype.JavaType;
+import bluej.pkgmgr.Package;
+
+/**
+ * Event class that holds all the relevant information about
+ * an execution.
+ *
+ * @author  Clive Miller
+ */
+public class ExecutionEvent
+{
+    /**
+     * The execution has finished normally;
+     */
+    public static final String NORMAL_EXIT = "Normal exit";
+
+    /**
+     * The execution has finished due to an exception
+     */
+    public static final String EXCEPTION_EXIT = "An exception occurred";
+
+    /**
+     * The execution has finished because the user has forcefully terminated it
+     */
+    public static final String TERMINATED_EXIT = "User terminated";
+    
+    private String className, objectName;
+    private String methodName;
+    private JavaType[] signature;
+    private String[] parameters;
+    private String result;
+    private String command;
+    private Package pkg;
+    private DebuggerObject resultObject;   // If there is a result object it goes here.
+    private ExceptionDescription exception;  // If an exception occurred, this is it.
+
+    /**
+     * Constructs an ExecutionEvent where className and objName are null and only the package is set.
+     * @param pkg The package this event is bound to.
+     */
+    public ExecutionEvent(Package pkg)
+    {
+        this.pkg = pkg;
+    }
+    
+    /**
+     * Constructs an ExecutionEvent given a className and objName.
+     * @param pkg        The package this event is bound to.
+     * @param className  The className of the event.
+     * @param objectName The object name, as in the object bench, of the event, can be null.
+     */
+    public ExecutionEvent(Package pkg, String className, String objectName)
+    {
+    	this.pkg = pkg;
+        this.className = className;
+        this.objectName = objectName;
+    }
+
+    public void setObjectName (String objectName)
+    {
+        this.objectName = objectName;
+    }
+    
+    /**
+     * Set the name of the called method. For a constructor call, this should be left null.
+     */
+    public void setMethodName (String methodName)
+    {
+        this.methodName = methodName;
+    }
+    
+    /**
+     * Set the types and values (Java expressions) of the method/constructor arguments.
+     */
+    public void setParameters (JavaType[] signature, String[] parameters)
+    {
+        this.signature = signature;
+        this.parameters = parameters;
+    }
+
+    /**
+     * Set the result of the execution. This should be one of:
+     * NORMAL_EXIT - the execution terminated successfully
+     * FORCED_EXIT - System.exit() was called
+     * EXCEPTION_EXIT - the execution failed due to an exception
+     * TERMINATED_EXIT - the user terminated the VM before execution completed
+     */
+    public void setResult (String result)
+    {
+        this.result = result;
+    }
+
+    /**
+     * When an invocation has some valid result it can pass it on using this method.
+     * 
+     * <p>For a constructor call (class name is set but method name is not), the created
+     * instance itself should be set as the result object. For any other invocation, the
+     * result should be a wrapper with a single "result" field containing the actual result.
+     */
+    public void setResultObject (DebuggerObject resultObject)
+    {
+        this.resultObject = resultObject;
+    }
+    
+    /**
+     * Set the exception which occurred (if one did).
+     */
+    public void setException(ExceptionDescription exception)
+    {
+        this.exception = exception;
+    }
+    
+    public void setCommand (String cmd)
+    {
+        this.command = cmd;
+    }
+    
+    /**
+     * Get the name of the class on which the invocation occurred.
+     * For an instance method invocation, this returns the class of the object on
+     *   which the method was invoked.
+     * For a static method or constructor call, this returns the class name.
+     * For a free-form invocation, this returns null.
+     */
+    public String getClassName()
+    {
+        return className;
+    }
+    
+    /**
+     * Get the name of the object on which the invocation occurred.
+     * For constructor calls, returns the name of the constructed object.
+     * For static method calls or free-form invocations returns null.
+     */
+    public String getObjectName()
+    {
+        return objectName;
+    }
+    
+    /**
+     * Get the name of the method which was invoked.
+     * For a constructor or free-form invocation, this returns null.
+     */
+    public String getMethodName()
+    {
+        return methodName;
+    }
+    
+    /**
+     * Get the method/constructor parameter types.
+     * For a free-form invocation this returns null. 
+     */
+    public JavaType[] getSignature()
+    {
+        return signature;
+    }
+    
+    /**
+     * Gets the arguments to the method/constructor (as java expressions).
+     * For a free-form invocation this returns null.
+     */
+    public String[] getParameters()
+    {
+        return parameters;
+    }
+    
+    /**
+     * Get the result of the execution. This will be one of:
+     * NORMAL_EXIT - the execution terminated successfully
+     * EXCEPTION_EXIT - the execution failed due to an exception
+     * TERMINATED_EXIT - the user terminated the VM before execution completed
+     */
+    public String getResult()
+    {
+        return result;
+    }
+
+    /**
+     * This is the Object resulting from the invocation.
+     * 
+     * <p>For a constructor call (class name is set but method name is not), the created
+     * instance itself is the result object. For any other invocation, the result object is 
+     * a wrapper with a single "result" field containing the actual invocation result.
+     */
+    public DebuggerObject getResultObject()
+    {
+        return resultObject;
+    }
+
+    /**
+     * Get the exception which occurred (valid if the result is EXCEPTION_EXIT).
+     */
+    public ExceptionDescription getException()
+    {
+        return exception;
+    }
+    
+    public Package getPackage()
+    {
+        return pkg;
+    }
+    
+    public String getCommand()
+    {
+        return command;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExpressionInformation.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExpressionInformation.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ee6d9d070a8ae0c0c7ac597b9d694c5f0c6d777
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ExpressionInformation.java
@@ -0,0 +1,191 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.views.CallableView;
+import bluej.views.Comment;
+import bluej.views.MethodView;
+
+/**
+ * This class stores information about an expression. This could be from an
+ * arbitrary invocation where we only have the actual invocation string. It
+ * could also be from the invocation of a method, in which case we have more
+ * information such as the method signature, javadoc, etc...
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class ExpressionInformation
+{
+    private Comment comment;
+    private String signature;
+    private String expression;
+    private MethodView methodView;
+
+    private String invokedOn;
+    private String[] args;
+    
+    // if expression is a call of an instance method, this is the type of the instance.
+    private GenTypeClass instanceType;
+    
+    private static final Comment emptyComment = new Comment();;
+
+    /**
+     * Generates the expression information from a method view. The actual
+     * values for arguments to the method is not yet available and should be set
+     * later.
+     * 
+     * @see #setArgumentValues(String[])
+     * @param methodView
+     *            The MethodView of the invoked method
+     */
+    public ExpressionInformation(MethodView methodView, String instanceName)
+    {
+        this.methodView = methodView;
+        comment = methodView.getComment();
+        signature = methodView.getLongDesc();
+
+        if (methodView.isStatic()) {
+            invokedOn = methodView.getClassName();
+        } else {
+            invokedOn = instanceName;
+        }
+    }
+    
+    public ExpressionInformation(MethodView methodView, String instanceName, GenTypeClass instanceType)
+    {
+        this.methodView = methodView;
+        comment = methodView.getComment();
+        signature = methodView.getLongDesc(instanceType.getMap());
+
+        if (methodView.isStatic()) {
+            invokedOn = methodView.getClassName();
+        } else {
+            invokedOn = instanceName;
+            this.instanceType = instanceType;
+        }
+    }
+
+    /**
+     * Generates the expression information from an expression. This just copies
+     * the actual string.
+     * 
+     * @param expression
+     *            The expression we are watching
+     */
+    public ExpressionInformation(String expression)
+    {
+        this.expression = expression;
+    }
+
+    /**
+     * Sets the values for the arguments to the method call.
+     * 
+     * @param args the argument values
+     */
+    public void setArgumentValues(String[] args)
+    {	
+        this.args = args;	    
+    }
+
+    /**
+     * Returns the javadoc for this method
+     *  
+     * @return Returns the comment. Never null.
+     */
+    public Comment getComment()
+    {
+        if(comment!=null) {
+            return comment;
+        } else {
+            return emptyComment;
+        }
+    }
+
+    /**
+     * Returns the expression.
+     * 
+     * @return Returns the expression.
+     */
+    public String getExpression()
+    {
+        expression = invokedOn + "." + methodView.getName();
+        expression += "(";
+        if (args != null) {
+            for (int i = 0; i < args.length; i++) {
+                String string = args[i];
+                expression += string;
+                if (i + 1 < args.length) {
+                    expression += ", ";
+                }
+            }
+        }
+        expression += ")";
+
+        return expression;
+    }
+
+    /**
+     * Get the signature for the method.
+     * 
+     * @return Returns the method signature or null if it is not available
+     */
+    public String getSignature()
+    {
+        return signature;
+    }
+
+    /**
+     * Get the type of the object on which the method was called.
+     * 
+     * @return The type of the object, or null.
+     */
+    public GenTypeClass getInstanceType()
+    {
+        return instanceType;
+    }
+
+    /**
+     * Get the method view assosciated with this expression.
+     * 
+     * @return the method view.
+     */
+    public CallableView getMethodView()
+    {
+        return methodView;
+    }
+
+    public String toString()
+    {
+        String newline = System.getProperty("line.separator");
+        StringBuffer s = new StringBuffer();
+
+        s.append(newline);
+        s.append(getComment());		
+        s.append(newline);
+        s.append(getSignature());
+        s.append(newline);
+        s.append(getExpression());	
+
+        return s.toString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/FieldCellRenderer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/FieldCellRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..5617bda8495c5fe2623ec0e6f43ce3f4e4d6ac7e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/FieldCellRenderer.java
@@ -0,0 +1,47 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import java.awt.Component;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JList;
+
+import bluej.debugger.DebuggerField;
+import bluej.debugmgr.inspector.Inspector;
+
+/**
+ * A list cell renderer to display fields.
+ * 
+ * @author Davin Mccall
+ */
+public class FieldCellRenderer extends DefaultListCellRenderer
+{
+    @Override
+    public Component getListCellRendererComponent(JList list, Object value,
+            int index, boolean isSelected, boolean cellHasFocus)
+    {
+        DebuggerField field = (DebuggerField) value;
+        String s = Inspector.fieldToString(field) + " = " + field.getValueString();
+        return super.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/History.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/History.java
new file mode 100644
index 0000000000000000000000000000000000000000..596ee67c9b9dfced454fe560c3c7157fc7430120
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/History.java
@@ -0,0 +1,102 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/** 
+ * History objects maintain a history of text strings. This serves as a
+ * superclass for various histories (see, for example, ClassHistory,
+ * FreeCallHistory).
+ *
+ * @author Michael Kolling
+ */
+public class History
+{
+    protected List<String> history = null;
+    protected int maxLength;
+    private boolean blankAtStart;
+    
+    /**
+     * Create a empty history limited to a given maximum
+     * number of entries.
+     *
+     * @param maxLength The maximum length of the hostory list. The
+     *                  list truncates its tail when growing longer.
+     * @param blankDefault If true, maintains an empty string as the
+     *                  first (most recent) entry.
+     */
+    protected History(int maxLength, boolean blankDefault)
+    {
+        this.maxLength = maxLength;
+        history = new ArrayList<String>(maxLength+1);
+        history.add("");
+        blankAtStart = blankDefault;
+    }
+
+    /**
+     * Put an entry into the history list. This method is only for 
+     * initialisation through subclasses. It does not check for 
+     * duplicates or maxlength.
+     */
+    protected void put(String value)
+    {
+        history.add(value);
+    }
+
+    /**
+     * Return the history of used classes.
+     */	
+    public List<String> getHistory()
+    {
+        return history;
+    }
+
+    /**
+     * Add a string to the history of used strings.
+     * 
+     * @param newString  the new string to add
+     */
+    public void add(String newString)
+    {
+        if(newString != null && (newString.length() != 0)) {
+
+            // remove at old position (if present) and add at front
+            history.remove(newString);
+
+            if(blankAtStart) {
+                history.add(1, newString);
+            }
+            else {
+                // remove empty entry at front
+                if(((String)history.get(0)).length() == 0)
+                    history.remove(0);
+                history.add(0, newString);
+            }
+
+            // don't let it grow too big
+            if(history.size() > maxLength)
+                history.remove(maxLength);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/IndexHistory.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/IndexHistory.java
new file mode 100644
index 0000000000000000000000000000000000000000..0cebfd659a000734a4e03a9157658111bf293e30
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/IndexHistory.java
@@ -0,0 +1,90 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+/**
+ * A history of Strings that maintains an internal cursor to provide
+ * 'getNext'/'getPrevious'-style methods to traverse the history list. 
+ * 
+ * @author mik
+ */
+
+public class IndexHistory extends History {
+
+    private int currentIndex;
+    
+    /**
+     * 
+     * @param maxLength Number of entries in history list
+     */
+    public IndexHistory(int maxLength)
+    {
+        super(maxLength, true);
+        currentIndex = 0;
+    }
+    
+    /**
+     * Add a string to the history of used strings.
+     * 
+     * @param newString  the new string to add
+     */
+    public void add(String newString)
+    {
+        super.add(newString);
+        currentIndex = 0;
+    }
+    
+    /**
+     * Get the previous history entry. Calling this repeatedly walks
+     * back through the history
+     * 
+     * @return The previous history entry.
+     */
+    public String getPrevious()
+    {
+        if(currentIndex+1 < history.size()) {
+            currentIndex++;
+            return (String) history.get(currentIndex);
+        }
+        else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the next history entry. Calling this repeatedly walks
+     * forward through the history
+     * 
+     * @return The next history entry.
+     */
+    public String getNext()
+    {
+        if(currentIndex > 0) {
+            currentIndex--;
+            return (String) history.get(currentIndex);
+        }
+        else {
+            return null;
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/Invoker.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/Invoker.java
new file mode 100644
index 0000000000000000000000000000000000000000..fca5d4b33f0b887f690b111b19694b67235ef1f2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/Invoker.java
@@ -0,0 +1,1317 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import java.awt.EventQueue;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.swing.JFrame;
+
+import bluej.Config;
+import bluej.compiler.CompileObserver;
+import bluej.compiler.Diagnostic;
+import bluej.compiler.EventqueueCompileObserver;
+import bluej.compiler.JobQueue;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.DebuggerResult;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.NameTransform;
+import bluej.debugmgr.objectbench.ObjectBenchInterface;
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.runtime.Shell;
+import bluej.testmgr.record.ConstructionInvokerRecord;
+import bluej.testmgr.record.ExpressionInvokerRecord;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.testmgr.record.MethodInvokerRecord;
+import bluej.testmgr.record.VoidMethodInvokerRecord;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.JavaNames;
+import bluej.utility.Utility;
+import bluej.views.CallableView;
+import bluej.views.ConstructorView;
+import bluej.views.MethodView;
+
+/**
+ * Debugger class that arranges invocation of constructors or methods. This
+ * class constructs a "shell" java source file, compiles it, then loads the
+ * resulting class file and executes a method in a new thread.
+ * 
+ * @author Michael Kolling
+ */
+public class Invoker
+    implements CompileObserver, CallDialogWatcher
+{
+    public static final int OBJ_NAME_LENGTH = 8;
+    public static final String SHELLNAME = "__SHELL";
+    private static int shellNumber = 0;
+
+    private static final synchronized String getShellName()
+    {
+        return SHELLNAME + (shellNumber++);
+    }
+
+    /**
+     * To allow each method/constructor dialog to have a call history we need to
+     * cache the dialogs we create. We store the mapping from method to dialog
+     * in this hashtable.
+     */
+    private static Map<MethodView, MethodDialog> methods = new HashMap<MethodView, MethodDialog>();
+    private static Map<ConstructorView, ConstructorDialog> constructors =
+        new HashMap<ConstructorView, ConstructorDialog>();
+
+    private JFrame pmf;
+    private boolean codepad; //Used to decide whether to do data collection (don't record if for codepad)
+    private File pkgPath;
+    private String pkgName;
+    private String pkgScopeId;
+    private CallHistory callHistory;
+    private ResultWatcher watcher;
+    private CallableView member;
+    private String shellName;
+    /** Name of the result object */
+    private String objName;
+    private Map<String,GenTypeParameter> typeMap; // map type parameter names to types
+    private ValueCollection localVars;
+    private ValueCollection objectBenchVars;
+    private ObjectBenchInterface objectBench;
+    private Debugger debugger;
+    private String imports; // import statements to include in shell file
+    private NameTransform nameTransform;
+    private InvokerCompiler compiler;
+    private Charset sourceCharset;
+    
+    /** Name of the target object to which the call is applied */
+    private String instanceName;
+
+    private CallDialog dialog;
+    private boolean constructing;
+
+    private String commandString;
+    private InvokerRecord ir;
+    
+    /** Whether we've already seen an error from the compiler */
+    private boolean gotError;
+
+    /**
+     * Construct an invoker, specifying most attributes manually.
+     */
+    public Invoker(JFrame frame, CallableView member, ResultWatcher watcher, File pkgPath, String pkgName,
+            String pkgScopeId, CallHistory callHistory, ValueCollection objectBenchVars,
+            ObjectBenchInterface objectBench, Debugger debugger, InvokerCompiler compiler,
+            String instanceName, Charset sourceCharset)
+    {
+        this.pmf = frame;
+        this.member = member;
+        this.watcher = watcher;
+        if (member instanceof ConstructorView) {
+            this.objName = member.getClassName().toLowerCase();
+            constructing = true;
+        }
+        else if (member instanceof MethodView) {
+            constructing = false;
+        }
+        
+        this.instanceName = instanceName;
+        this.pkgPath = pkgPath;
+        this.pkgName = pkgName;
+        this.pkgScopeId = pkgScopeId;
+        this.callHistory = callHistory;
+        this.objectBenchVars = objectBenchVars;
+        this.objectBench = objectBench;
+        this.debugger = debugger;
+        this.nameTransform = new NameTransform() {
+            public String transform(String typeName)
+            {
+                return typeName;
+            }
+        };
+        this.compiler = compiler;
+        this.shellName = getShellName();
+        this.sourceCharset = sourceCharset;
+    }
+
+    /**
+     * Create an invoker for a free form statement or expression. After using this
+     * constructor, optionally call setImports(), then call doFreeFormInvocation()
+     * to perform compilation and execution.
+     */
+    public Invoker(PkgMgrFrame pmf, ValueCollection localVars, String command, ResultWatcher watcher)
+    {
+        initialize(pmf);
+        
+        this.watcher = watcher;
+        this.member = null;
+        this.shellName = getShellName();
+        this.objName = null;
+        this.instanceName = null;
+        this.localVars = localVars;
+
+        constructing = false;
+        codepad = true;
+        commandString = command;
+    }
+    
+    /**
+     * Call a class's constructor OR call a static method and create an
+     * ObjectWrapper for the resulting object
+     * 
+     * @param pmf
+     *            the frame of the package we are working on
+     * @param member
+     *            the member to invoke
+     * @param watcher
+     *            an object interested in the result of the invocation
+     */
+    public Invoker(PkgMgrFrame pmf, CallableView member, ResultWatcher watcher)
+    {
+        initialize(pmf);
+
+        this.member = member;
+        this.watcher = watcher;
+        this.shellName = getShellName();
+        codepad = false;
+
+        // in the case of a constructor, we need to construct an object name
+        if (member instanceof ConstructorView) {
+            this.objName = pmf.getProject().getDebugger().guessNewName(member.getClassName());
+            constructing = true;
+        }
+        else if (member instanceof MethodView) {
+            constructing = false;
+        }
+        else {
+            Debug.reportError("illegal member type in invocation");
+            throw new IllegalArgumentException("Unknown callable type");
+        }
+    }
+
+    /**
+     * Call an instance method on an object
+     * 
+     * @param pmf
+     *            the frame of the package we are working on
+     * @param member
+     *            the member to invoke
+     * @param objWrapper
+     *            the object to invoke the method on
+     * @param watcher
+     *            an object interested in the result of the invocation
+     */
+    public Invoker(PkgMgrFrame pmf, MethodView member, ObjectWrapper objWrapper, ResultWatcher watcher)
+    {
+        initialize(pmf);
+
+        this.member = member;
+        this.watcher = watcher;
+        this.shellName = getShellName();
+        codepad = false;
+
+        // We want a map of all the type parameters that may appear in the
+        // method signature to the corresponding instantiation types from the
+        // object to which the method is being applied.
+        //
+        // Tpar names in the method signature however correspond to names from
+        // the class in which the method was declared. So we need to map tpars
+        // from the object's class to that class.
+        this.instanceName = objWrapper.getName();
+        this.typeMap = objWrapper.getObject().getGenType().mapToSuper(member.getClassName()).getMap();
+
+        constructing = false;
+    }
+
+    /**
+     * Initialize most of the invoker's necessary fields via a PkgMgrFrame reference.
+     */
+    private void initialize(final PkgMgrFrame pmf)
+    {
+        this.pmf = pmf;
+        final Package pkg = pmf.getPackage();
+        this.pkgPath = pkg.getPath();
+        this.pkgName = pkg.getQualifiedName();
+        this.pkgScopeId = pkg.getId();
+        this.callHistory = pkg.getCallHistory();
+        this.objectBenchVars = pmf.getObjectBench();
+        this.objectBench = pmf.getObjectBench();
+        this.debugger = pkg.getProject().getDebugger();
+        this.nameTransform = new CleverQualifyTypeNameTransform(pkg);
+        compiler = new InvokerCompiler() {
+            public void compile(File[] files, CompileObserver observer)
+            {
+                Project project = pkg.getProject();
+                JobQueue.getJobQueue().addJob(files, observer, project.getClassLoader(),
+                        project.getProjectDir(), true, project.getProjectCharset());
+            }
+        };
+        this.sourceCharset = pmf.getProject().getProjectCharset();
+    }
+    
+    /**
+     * Set the import statements that should be in effect when this invocation
+     * is performed.
+     * 
+     * @param importStatements   The import statements in complete and valid java syntax
+     */
+    public void setImports(String importStatements)
+    {
+        imports = importStatements;
+    }
+    
+    /**
+     * Open a dialog to get further information about the requested invocation, or
+     * if no information is needed (ie. no parameters) then just proceed with the
+     * invocation.
+     * 
+     * When the dialog is complete, it will call proceed with the invocation
+     * (see callDialogEvent).
+     */
+    public void invokeInteractive()
+    {
+        gotError = false;
+        // check for a method call with no parameter
+        // if so, just do it
+        if ((!constructing || Config.isGreenfoot()) && !member.hasParameters()) {
+            dialog = null;
+            doInvocation(null, (JavaType []) null, null);
+        }
+        else {
+            CallDialog cDialog;
+            if (member instanceof MethodView) {
+                // Method requires a method dialog
+                MethodView mmember = (MethodView) member;
+                MethodDialog mDialog = methods.get(member);
+
+                if (mDialog == null) {
+                    mDialog = new MethodDialog(pmf, objectBench, callHistory, instanceName, mmember, typeMap);
+                    methods.put(mmember, mDialog);
+                }
+                else {
+                    mDialog.setInstanceInfo(instanceName, typeMap);
+                    mDialog.setCallLabel(mmember.isStatic() ? mmember.getClassName() : instanceName);
+                }
+                cDialog = mDialog;
+            }
+            else {
+                // Constructor
+                ConstructorView cmember = (ConstructorView) member;
+                ConstructorDialog conDialog = constructors.get(cmember);
+                
+                if (conDialog == null) {
+                    conDialog = new ConstructorDialog(pmf, objectBench, callHistory, objName, cmember);
+                    constructors.put(cmember, conDialog);
+                }
+                else {
+                    conDialog.setInstanceInfo(objName);
+                }
+                cDialog = conDialog;
+            }
+
+            cDialog.setVisible(true);
+            cDialog.setEnabled(true);
+            cDialog.setWatcher(this);
+            dialog = cDialog;
+        }
+    }
+
+    // -- CallDialogWatcher interface --
+
+    /**
+     * The call dialog notified of an event. If it is an OK, start doing the
+     * call.
+     */
+    public void callDialogEvent(CallDialog dlg, int event)
+    {
+        if (event == CallDialog.CANCEL) {
+            dlg.setVisible(false);
+        }
+        else if (event == CallDialog.OK) {
+            gotError = false;
+            dialog.setEnabled(false);
+            objName = dialog.getNewInstanceName();
+            String[] actualTypeParams = dialog.getTypeParams();
+            doInvocation(dialog.getArgs(), dialog.getArgGenTypes(true), actualTypeParams);
+        }
+        else {
+            Debug.reportError("Invoker: Unknown CallDialog event");
+        }
+    }
+
+    // -- end of CallDialogWatcher interface --
+
+    /**
+     * Invokes a constructor or method with the given parameters.
+     * 
+     * @param params The arguments to the method/constructor (Java expressions)
+     */
+    public void invokeDirect(String[] params)
+    {
+        gotError = false;
+        final JavaType[] argTypes = member.getParamTypes(false);
+        for (int i = 0; i < argTypes.length; i++) {
+            argTypes[i] = argTypes[i].mapTparsToTypes(typeMap).getUpperBound();
+        }
+        
+        doInvocation(params, argTypes, null);
+    }
+
+    /**
+     * After all the interactive stuff is finished, finally do the invocation of
+     * the method. (This can be a constructor call or a normal method call.)
+     * 
+     * Invocation here means: construct shell class and start compiling it.
+     * 
+     * The "endCompile" method is called when the compilation has completed. If
+     * successful, the shell class will then be executed.
+     *  
+     * @param args  The arguments to the method/constructor as they will appear
+     *              in the generated source
+     * @param argTypes  The argument types (ignored for generic callables);
+     *              type parameters have been mapped to actual types
+     * @param typeParams  Specifies the type parameters as supplied by the
+     *                    user
+     */
+    protected void doInvocation(String[] args, JavaType[] argTypes, String[] typeParams)
+    {
+        gotError = false;
+        int numArgs = (args == null ? 0 : args.length);
+
+        // prepare variables (assigned with actual values) for each parameter
+        String [] argTypeStrings;
+        if (argTypes != null)
+            argTypeStrings = new String[argTypes.length];
+        else
+            argTypeStrings = null;
+        
+        if (! member.isGeneric() || member.isConstructor()) {
+            for (int i = 0; i < numArgs; i++) {
+                JavaType argType = argTypes[i];
+                argTypeStrings[i] = argType.toString(nameTransform);
+            }
+        }
+
+        doInvocation(args, argTypeStrings, typeParams);
+    }
+
+    /**
+     * Workhorse doInvocation method which takes a string array for the
+     * argument types instead of a GenType array. This constructs the code strings,
+     * writes the invocation file, compiles it and eventually executes it.
+     */
+    private void doInvocation(String[] args, String[] argTypes, String[] typeParams)
+    {
+        int numArgs = (args == null ? 0 : args.length);
+        final String className = member.getClassName();
+
+        // Generic methods currently require special handling
+        boolean isGenericMethod = member.isGeneric() && ! member.isConstructor();
+        
+        // prepare variables (assigned with actual values) for each parameter
+        StringBuffer buffer = new StringBuffer();
+        if (! isGenericMethod) {
+            for (int i = 0; i < numArgs; i++) {
+                buffer.append(argTypes[i]);
+                buffer.append(" __bluej_param" + i);
+                buffer.append(" = " + args[i]);
+                buffer.append(";" + Config.nl);
+            }
+        }
+        String paramInit = buffer.toString();
+
+        // Build two strings with parameter lists: one using the variable names
+        // "(__bluej_param0,__bluej_param1,...)" for internal use, one using the
+        // actual values for interface display.
+
+        buffer.setLength(0);
+        StringBuffer argBuffer = new StringBuffer();
+        buildArgStrings(buffer, argBuffer, args);
+        String argString = buffer.toString();
+        String actualArgString = argBuffer.toString();
+        if (isGenericMethod)
+            argString = actualArgString; 
+        
+        // build the invocation string
+
+        buffer.setLength(0);
+        String command; // the interactive command in text form
+        boolean isVoid = false;
+
+        String constype = null;
+        if (constructing) {
+            constype = nameTransform.transform(className);
+            if (typeParams != null && typeParams.length > 0) {
+                constype += "<";
+                for (int i = 0; i < typeParams.length; i++) {
+                    String typeParam = typeParams[i];
+                    constype += typeParam;
+                    if (i < (typeParams.length - 1)) {
+                        constype += ",";
+                    }
+                }
+                constype += ">";
+            }
+            command = "new " + constype;
+            ir = new ConstructionInvokerRecord(constype, objName, command + actualArgString, args);
+        }
+        else { // it's a method call
+            MethodView method = (MethodView) member;
+            isVoid = method.isVoid();
+
+            if (method.isStatic())
+                command = nameTransform.transform(className) + "." + method.getName();
+            else {
+                command = instanceName + "." + method.getName();
+            }
+
+            if (isVoid) {
+                ir = new VoidMethodInvokerRecord(command + actualArgString, args);
+                objName = null;
+            }
+            else {
+                ir = new MethodInvokerRecord(method.getGenericReturnType(), command + actualArgString, args);
+                objName = "result";
+            }
+        }
+
+        if (constructing && member.getParameterCount() == 0 && (typeParams == null || typeParams.length == 0)) {
+            // Special case for construction of a class using the default constructor.
+            // We can do this without writing and compiling a shell file.
+            
+            commandString = command + actualArgString;
+            watcher.beginCompile(); // there is no compile step, really
+            watcher.beginExecution(ir);
+            
+            // We must however do so in a seperate thread. Otherwise a constructor which
+            // goes into an infinite loop can hang BlueJ.
+            new Thread() {
+                public void run() {
+                    EventQueue.invokeLater(new Runnable() {
+                        public void run() {
+                            closeCallDialog();
+                        }
+                    });
+                    
+                    final DebuggerResult result = debugger.instantiateClass(className);
+
+                    EventQueue.invokeLater(new Runnable() {
+                        public void run() {
+                            // the execution is completed, get the result if there was one
+                            // (this could be either a construction or a function result)
+                            
+                            handleResult(result, false); // handles error situations
+                        }
+                    });
+                }
+            }.start();
+        }
+        else {
+            if (isVoid)
+                argString += ';';
+            
+            watcher.beginCompile();
+            File shell = writeInvocationFile(paramInit, command + argString, isVoid, constype);
+            if (shell != null) {
+                commandString = command + actualArgString;
+                compileInvocationFile(shell);
+            }
+            else {
+                endCompile(new File[0], false);
+            }
+        }
+    }
+
+    /**
+     * Build up two strings representing the arguments to a method/constructor
+     * call as a comma-seperated list enclosed in braces ie. (x, y, z)<p>
+     * 
+     * The first buffer gets the form (__bluej_param0, __bluej_param1 ...)
+     * while the second gets the arguments as supplied by the user.<p>
+     * 
+     * @param buffer    The first buffer
+     * @param argBuffer The second buffer
+     * @param args      The arguments supplied by the user
+     */
+    protected void buildArgStrings(StringBuffer buffer, StringBuffer argBuffer, String[] args)
+    {
+        int numArgs = args == null ? 0 : args.length;
+        
+        buffer.append("(");
+        argBuffer.append("(");
+        if (numArgs > 0) {
+            buffer.append("__bluej_param0");
+            argBuffer.append(args[0]);
+        }
+        for (int i = 1; i < numArgs; i++) {
+            buffer.append(",__bluej_param" + i);
+            argBuffer.append(", ");
+            argBuffer.append(args[i]);
+        }
+        buffer.append(")");
+        argBuffer.append(")");
+    }
+    
+    /**
+     * Arrange to execute a free form (text) invocation.
+     * 
+     * <p>Invocation here means: construct shell class and compile. The execution
+     * is done once we return from compilation (in method "endCompile").
+     * Compilation is done asynchronously by the CompilerThread.
+     * 
+     * <p>This method is still executed in the interface thread, while "endCompile"
+     * will be executed by the CompilerThread.
+     * 
+     * <p>Returns true if successful, or false if there was a problem (the shell
+     * file couldn't be written). In case of failure, a dialog is displayed to
+     * alert the user.
+     */
+    public boolean doFreeFormInvocation(String resultType)
+    {
+        gotError = false;
+        boolean hasResult = resultType != null;
+        if (hasResult) {
+            if (resultType.equals(""))
+                resultType = null;
+            objName = "result";
+            ir = new ExpressionInvokerRecord(commandString);
+        }
+        else {
+            objName = null;
+            // this is a statement, treat as a void method result
+            ir = new VoidMethodInvokerRecord(commandString, null);
+        }
+
+        File shell = writeInvocationFile("", commandString, !hasResult, resultType);
+        if (shell != null) {
+            compileInvocationFile(shell);
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+
+    /**
+     * Write a source file for a class (the 'shell file') to do the interactive
+     * invocation. Returns the written file, or null if the file cannot be written
+     * (an error dialog will be shown in this case).
+     * 
+     * <p>A shell file has, very roughly, the following form:
+     * 
+     * <p><pre>
+     * $PKGLINE
+     * $IMPORTS
+     * public class $CLASSNAME extends bluej.runtime.Shell
+     * {
+     *   public static void run() throws Throwable
+     *   {
+     *     $SCOPEINIT
+     *     $PARAMINIT
+     *     $INVOCATION
+     *   }
+     * }
+     * </pre><p>
+     * 
+     * PARAMINIT and INVOCATION correspond directly to the parameters
+     * 'paramInit' and 'callString' as passed to this method.<p>
+     * 
+     * SCOPEINIT declares a Map, __bluej_runtime_scope, which maps object
+     * names to their values (allowing objects from the object bench to be
+     * accessed).
+     * 
+     *  
+     * @param paramInit  java code which initializes parameter variables
+     * @param callString java code which executes requested method/code
+     * @param isVoid   true if no result is returned
+     * @param constype  the exact type of the object being constructed. Only
+     *                  needed if 'constructing' is true, but can be supplied in other
+     *                  cases to yield a more accurate result type (when generic types
+     *                  are involved).
+     */
+    private File writeInvocationFile(String paramInit, String callString,
+            boolean isVoid, String constype)
+    {
+        // Create package specification line ("package xyz")
+        String packageLine;
+        if (pkgName.length() == 0) {
+            packageLine = "";
+        }
+        else {
+            packageLine = "package " + pkgName + ";";
+        }
+
+        StringBuffer buffer = new StringBuffer();
+        
+        // Build scope, i.e. add one line for every object on the object
+        // bench that gets the object and makes it available for use as
+        // a parameter.
+        
+        // A sample of the code generated
+        //  java.util.Map __bluej_runtime_scope = getScope("BJIDC:\\aproject");
+        //  JavaType instnameA = (JavaType) __bluej_runtime_scope.get("instnameA");
+        //  OtherJavaType instnameB = (OtherJavaType) __bluej_runtime_scope.get("instnameB");
+
+        String scopeId = Utility.quoteString(pkgScopeId);
+        Iterator<? extends NamedValue> wrappers = objectBenchVars.getValueIterator();
+
+        Map<String, String> objBenchVarsMap = new HashMap<String, String>();
+        
+        if (wrappers.hasNext() || localVars != null) {
+            buffer.append("final bluej.runtime.BJMap __bluej_runtime_scope = getScope(\"" + scopeId + "\");" + Config.nl);
+            while (wrappers.hasNext()) {
+                NamedValue objBenchVar = wrappers.next();
+                objBenchVarsMap.put(objBenchVar.getName(), getVarDeclString("", false, objBenchVar, nameTransform));
+            }
+        }
+        
+        // put the local variables here if we don't know the result type. If we do know
+        // the result type, we put the local variables inside the result wrapper object
+        // later on.
+        if (localVars != null && constype == null) {
+            Iterator<? extends NamedValue> i = localVars.getValueIterator();
+            while (i.hasNext()) {
+                NamedValue localVar = i.next();
+                objBenchVarsMap.put(localVar.getName(), getVarDeclString("lv:", false, localVar, nameTransform));
+            }
+        }
+        
+        Iterator<String> obVarsIterator = objBenchVarsMap.values().iterator();
+        while (obVarsIterator.hasNext()) {
+            buffer.append(obVarsIterator.next().toString());
+        }
+        
+        String vardecl = buffer.toString();
+        buffer.setLength(0);
+
+        // build the invocation string
+        
+        // A sample of the code generated:
+        //
+        // Result type not known:
+        //    try {
+        //      return makeObj(2+new String("ap").length());
+        //    }
+        //    finally {
+        //    }
+        //
+        // Result type known:
+        //    return new java.lang.Object() {
+        //       int result;
+        //       try {
+        //           result = 2+new String("ap").length();
+        //       }
+        //       finally {
+        //       }
+        //    }
+        //
+        // Note that codepad local variable values, if any, are saved in the finally block.
+
+        if (!isVoid) {
+            if (constype == null) {
+                buffer.append(paramInit);
+                buffer.append("try {" + Config.nl);
+                buffer.append("return makeObj(");
+            }
+            else {
+                buffer.append("return new java.lang.Object() { ");
+                buffer.append(constype + " result;" + Config.nl);
+                buffer.append("{ ");
+                buffer.append(paramInit);
+                if (localVars != null) {
+                    writeVariables("lv:", buffer, false, localVars.getValueIterator(), nameTransform);
+                }
+                buffer.append("try {" + Config.nl);
+                buffer.append("result=(");
+            }
+            buffer.append(callString);
+            // Append a new line, as the call string may end with a //-style comment
+            buffer.append(Config.nl);
+            buffer.append(");}");
+            buffer.append(Config.nl);
+            buffer.append("finally {" + Config.nl);
+        }
+        else {
+            buffer.append(paramInit);
+            buffer.append(callString);
+            // Append a new line, as the call string may end with a //-style comment
+            buffer.append(Config.nl);
+        }
+
+        String invocation = buffer.toString();
+        
+        // save altered local variable values
+        buffer = new StringBuffer();
+        if (localVars != null) {
+            for (Iterator<?> i = localVars.getValueIterator(); i.hasNext();) {
+                NamedValue wrapper = (NamedValue) i.next();
+                if (! wrapper.isFinal() || ! wrapper.isInitialized()) {
+                    String instname = wrapper.getName();
+                    
+                    buffer.append("__bluej_runtime_scope.put(\"lv:" + instname + "\", "); 
+                    wrapValue(buffer, instname, wrapper.getGenType());
+                    buffer.append(");" + Config.nl);
+                }
+            }
+        }
+        String scopeSave = buffer.toString();
+
+        File shellFile = new File(pkgPath, shellName + ".java");
+        BufferedWriter shell = null;
+        try {
+            FileOutputStream fos = new FileOutputStream(shellFile);
+            shell = new BufferedWriter(new OutputStreamWriter(fos, sourceCharset));
+
+            shell.write(packageLine);
+            shell.newLine();
+            if (imports != null) {
+                shell.write(imports);
+                shell.newLine();
+            }
+            shell.write("public class ");
+            shell.write(shellName);
+            shell.write(" extends bluej.runtime.Shell {");
+            shell.newLine();
+            shell.write("public static ");
+            if (isVoid) {
+                shell.write("void");
+            }
+            else {
+                shell.write("java.lang.Object");
+            }
+            shell.write(" run() throws Throwable {");
+            shell.newLine();
+            shell.write(vardecl);
+            shell.newLine();
+            shell.write(invocation);
+            shell.write(scopeSave);
+            if (! isVoid) {
+                shell.write("}"); // end finally block
+                if (constype != null) {
+                    shell.write("} };"); // end block, anonymous inner object
+                }
+            }
+            shell.newLine();
+            shell.write("}}"); // end method, class
+            shell.newLine();
+            shell.close();
+        }
+        catch (IOException e) {
+            DialogManager.showError(pmf, "could-not-write-shell-file");
+            if (shell != null) {
+                try {
+                    shell.close();
+                }
+                catch (IOException ioe) {}
+            }
+            shellFile.delete();
+            return null;
+        }
+        return shellFile;
+    }
+    
+    /**
+     * Write out shell code to retrieve the values of variables or bench objects.
+     * 
+     * @param scopePx  The scope prefix ("lv:" for local variables)
+     * @param buffer   The string buffer to write the code to
+     * @param isStatic  True if the variables should be declared static
+     * @param i        An iterator through the variables to write
+     * @param nt       The name transform to use
+     */
+    private void writeVariables(String scopePx, StringBuffer buffer, boolean isStatic, Iterator<?> i, NameTransform nt)
+    {
+        for (; i.hasNext();) {
+            NamedValue wrapper = (NamedValue) i.next();
+            if (wrapper.isInitialized()) {
+                String type = wrapper.getGenType().toString(nt);
+                String instname = wrapper.getName();
+                
+                if (wrapper.isFinal()) {
+                    buffer.append("final ");
+                }
+                if (isStatic) {
+                    buffer.append("static ");
+                }
+                
+                buffer.append(type);
+                
+                buffer.append(" " + instname + " = ");
+                extractValue(buffer, scopePx, instname, wrapper.getGenType(), type);
+                buffer.append(Config.nl);
+            }
+        }
+    }
+    
+    /**
+     * Get the string to declare a variable.
+     * @param scopePx   The scope prefix for the value map
+     * @param isStatic  True if the variable should be declared static
+     * @param wrapper   The NamedValue representing the variable (and its name)
+     * @param nt        The name transform to use for class names
+     * 
+     * @return the string to declared the variable
+     */
+    private String getVarDeclString(String scopePx, boolean isStatic, NamedValue wrapper, NameTransform nt)
+    {
+        if (wrapper.isInitialized()) {
+            String type = wrapper.getGenType().toString(nt);
+            String instname = wrapper.getName();
+            StringBuffer buffer = new StringBuffer();
+            
+            if (wrapper.isFinal()) {
+                buffer.append("final ");
+            }
+            if (isStatic) {
+                buffer.append("static ");
+            }
+            
+            buffer.append(type);
+            
+            buffer.append(" " + instname + " = ");
+            extractValue(buffer, scopePx, instname, wrapper.getGenType(), type);
+            buffer.append(Config.nl);
+            
+            return buffer.toString();
+        }
+        else {
+            return "";
+        }
+    }
+
+    /**
+     * Write code to extract a value of a given type.
+     * @param buffer    The buffer in which the expression is stored
+     * @param scopePx   The scope prefix ("" for object bench, "lv:" for codepad)
+     * @param instname  The name of the value (used as map key)
+     * @param type      The type of the value
+     */
+    private void extractValue(StringBuffer buffer, String scopePx, String instname, JavaType type, String typeStr)
+    {
+        if (type.isPrimitive()) {
+            // primitive type. Must pull a wrapped object out, and then
+            // unwrap it.
+            
+            String castType;
+            String extractMethod;
+            
+            if (type.typeIs(JavaType.JT_BOOLEAN)) {
+                castType = "java.lang.Boolean";
+                extractMethod = "booleanValue";
+            }
+            else if (type.typeIs(JavaType.JT_CHAR)) {
+                castType = "java.lang.Character";
+                extractMethod = "charValue";
+            }
+            else if (type.typeIs(JavaType.JT_BYTE)) {
+                castType = "java.lang.Byte";
+                extractMethod = "byteValue";
+            }
+            else if (type.typeIs(JavaType.JT_SHORT)) {
+                castType = "java.lang.Short";
+                extractMethod = "shortValue";
+            }
+            else if (type.typeIs(JavaType.JT_INT)) {
+                castType = "java.lang.Integer";
+                extractMethod = "intValue";
+            }
+            else if (type.typeIs(JavaType.JT_LONG)) {
+                castType = "java.lang.Long";
+                extractMethod = "longValue";
+            }
+            else if (type.typeIs(JavaType.JT_FLOAT)) {
+                castType = "java.lang.Float";
+                extractMethod = "floatValue";
+            }
+            else if (type.typeIs(JavaType.JT_DOUBLE)) {
+                castType = "java.lang.Double";
+                extractMethod = "doubleValue";
+            }
+            else {
+                throw new UnsupportedOperationException("unhandled primitive type");
+            }
+            
+            buffer.append("((" + castType + ")__bluej_runtime_scope.get(\"");
+            buffer.append(scopePx + instname + "\"))." + extractMethod + "();");
+        }
+        else {
+            // reference (object) type. Much easier.
+            buffer.append("(" + typeStr);
+            buffer.append(")__bluej_runtime_scope.get(\"");
+            buffer.append(scopePx + instname + "\");" + Config.nl);
+        }
+    }
+    
+    /**
+     * Wrap a value, if necessary, as an appropriate object type.
+     * @param buffer  The resulting expression is written to this buffer
+     * @param name    The name of the variable holding the value
+     * @param type    The type of the value
+     */
+    private void wrapValue(StringBuffer buffer, String name, JavaType type)
+    {
+        if (type.isPrimitive()) {
+            if (type.typeIs(JavaType.JT_BOOLEAN))
+                buffer.append("java.lang.Boolean.valueOf(" + name + ")");
+            else if (type.typeIs(JavaType.JT_BYTE))
+                buffer.append("new java.lang.Byte(" + name + ")");
+            else if (type.typeIs(JavaType.JT_CHAR))
+                buffer.append("new java.lang.Character(" + name + ")");
+            else if (type.typeIs(JavaType.JT_DOUBLE))
+                buffer.append("new java.lang.Double(" + name + ")");
+            else if (type.typeIs(JavaType.JT_FLOAT))
+                buffer.append("new java.lang.Float(" + name + ")");
+            else if (type.typeIs(JavaType.JT_LONG))
+                buffer.append("new java.lang.Long(" + name + ")");
+            else if (type.typeIs(JavaType.JT_INT))
+                buffer.append("new java.lang.Integer(" + name + ")");
+            else if (type.typeIs(JavaType.JT_SHORT))
+                buffer.append("new java.lang.Short(" + name + ")");
+            else {
+                throw new UnsupportedOperationException("unhandled primitive type.");
+            }
+        }
+        else {
+            buffer.append(name);
+        }
+    }
+
+    /**
+     * Start the compilation of a shell fine and register us as a watcher. After
+     * this, we just wait for the callback from the compiler.
+     */
+    private void compileInvocationFile(File shellFile)
+    {
+        File[] files = {shellFile};
+        compiler.compile(files, new EventqueueCompileObserver(this));
+    }
+
+    // -- CompileObserver interface --
+
+    // not interested in these events:
+    @Override
+    public void startCompile(File[] sources) { }
+
+    /*
+     * @see bluej.compiler.CompileObserver#compilerMessage(bluej.compiler.Diagnostic)
+     */
+    @Override
+    public boolean compilerMessage(Diagnostic diagnostic)
+    {
+        if (diagnostic.getType() == Diagnostic.ERROR) {
+            if (! gotError) {
+                gotError = true;
+                errorMessage(diagnostic.getFileName(), diagnostic.getStartLine(), diagnostic.getMessage());
+                return true;
+            }
+        }
+        // We ignore warnings for shell classes
+        return false;
+    }
+    
+    /**
+     * An error was detected during compilation of the shell class.
+     */
+    private void errorMessage(String filename, long lineNo, String message)
+    {
+        if (dialog != null) {
+            dialog.setErrorMessage("Error: " + message);
+        }
+        watcher.putError(message, ir);
+    }
+    
+    /**
+     * The compilation of the shell class has ended. If all went well, execute
+     * now. Then clean up.
+     */
+    @Override
+    public synchronized void endCompile(File[] sources, boolean successful)
+    {
+        if (dialog != null) {
+            dialog.setWaitCursor(false);
+            if (successful) {
+                closeCallDialog();
+            }
+        }
+
+        if (successful) {
+            watcher.beginExecution(ir);
+            startClass();
+        }
+        else {
+            finishCall(false);
+        }
+    }
+
+    /**
+     * Clean up after an invocation or attempted invocation.
+     * @param successful  Whether the invocation compilation was successful
+     */
+    private void finishCall(boolean successful)
+    {
+        deleteShellFiles();
+        
+        if (! successful && dialog != null) {
+            // Re-enable call dialog: use can try again with
+            // different parameters.
+            dialog.setEnabled(true);
+        }
+    }
+    
+    private void closeCallDialog()
+    {
+        if (dialog != null) {
+            dialog.setWaitCursor(false);
+            dialog.setVisible(false);
+            // JDK on Windows has a bug. If the PkgMgrFrame is
+            // minimised while the call dialog is still showing, the
+            // call dialog re-appears when the PkgMgrFrame is restored.
+            // Calling dispose() as a workaround.
+            // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5005454
+            if (Config.isWinOS()) {
+                dialog.dispose();
+            }
+            dialog.updateParameters();
+        }
+    }
+
+    /**
+     * Remove the shell files that we created for this invocation.
+     */
+    private void deleteShellFiles()
+    {
+        File srcFile = new File(pkgPath, shellName + ".java");
+        srcFile.delete();
+
+        File classFile = new File(pkgPath, shellName + ".class");
+        classFile.delete();
+        
+        // Remove any inner class files
+        String [] innerClassFiles = pkgPath.list(new FilenameFilter() {
+            @Override
+            public boolean accept(File dir, String name)
+            {
+                return (name.startsWith(shellName + "$"));
+            }
+        });
+        
+        for (String innerClassFile : innerClassFiles) {
+            new File(pkgPath, innerClassFile).delete();
+        }
+    }
+
+    // -- end of CompileObserver interface --
+
+    /**
+     * Execute an interactive method call. At this point, the shell class has
+     * been compiled and we are ready to go.
+     */
+    private void startClass()
+    {
+        final String shellClassName = JavaNames.combineNames(pkgName, shellName);
+        
+        new Thread() {
+            public void run() {
+                try {
+                    final DebuggerResult result = debugger.runClassMain(shellClassName);
+                    
+                    EventQueue.invokeLater(new Runnable() {
+                        public void run() {
+                            // the execution is completed, get the result if there was one
+                            // (this could be either a construction or a function result)
+                            
+                            handleResult(result, constructing);
+                            finishCall(true);
+                        }
+                    });
+                    
+                }
+                catch (Throwable e) {
+                    e.printStackTrace(System.err);
+                }
+            }
+        }.start();
+    }
+    
+    /**
+     * After an execution has finished, check whether there is a result (such as
+     * a freshly created object, a function result or an exception) and make
+     * sure that it gets processed appropriately.
+     * 
+     * <p>"exitStatus" and "result" fields should be set with appropriate values before
+     * calling this.
+     * 
+     * <p>This method is called on the Swing event thread.
+     */
+    public void handleResult(DebuggerResult result, boolean unwrap)
+    {
+        try {
+            // first, check whether we had an unexpected exit
+            int status = result.getExitStatus();
+            switch(status) {
+                case Debugger.NORMAL_EXIT :
+                    // resultObj will be the null object representation (isNullObject() == true) for a void call
+                    DebuggerObject resultObj = result.getResultObject();
+                    if (unwrap) {
+                        // For constructor calls, the result is expected to be the created object.
+                        resultObj = resultObj.getInstanceField(0).getValueObject(null);
+                    }
+                    if (!codepad)
+                    {
+                        String resultType;
+                        //Only record this if it wasn't on behalf of the codepad (codepad records separately):
+                        if (resultObj.getClassName().startsWith(Shell.class.getCanonicalName()))
+                        {
+                            //Wrapped by Shell class, grab from first field.
+                            if (resultObj.getInstanceField(0).getType().isPrimitive())
+                            {
+                                // If it's a field with primitive type, use type of field:
+                                resultType = resultObj.getInstanceField(0).getType().toString();  
+                            }
+                            else
+                            {
+                                // Take type from resulting object:
+                                resultType = resultObj.getInstanceField(0).getValueObject(null).getClassName();
+                            }
+                        }
+                        else
+                        {
+                            resultType = resultObj.getClassName();
+                            if (resultType.equals(""))
+                            {
+                                resultType = "void";
+                            }
+                        }
+                    }
+                    
+                    ir.setResultObject(resultObj);
+                    watcher.putResult(resultObj, objName, ir);
+                    break;
+
+                case Debugger.EXCEPTION :
+                    ExceptionDescription exc = result.getException();
+                    watcher.putException(exc, ir);
+                    break;
+
+                case Debugger.TERMINATED : // terminated by user
+                    if (!codepad)
+                    watcher.putVMTerminated(ir);
+                    break;
+
+            } // switch
+        }
+        catch (Throwable e) {
+            e.printStackTrace(System.err);
+        }
+    }
+
+    static class CleverQualifyTypeNameTransform
+        implements NameTransform
+    {
+        Package mypackage;
+
+        public CleverQualifyTypeNameTransform(Package p)
+        {
+            mypackage = p;
+        }
+
+        public String transform(String n)
+        {
+            return cleverQualifyTypeName(mypackage, n);
+        }
+    }
+
+    static private String cleverQualifyTypeName(Package p, String typeName)
+    {
+        // if we happen to have a class in this package with the
+        // same name as the start of the package, then fully qualifying names
+        // does not work ie if the package is Test.Sub and we have
+        // a class called Test, then all fully qualified names
+        // fail ie new Test.Sub.Test() and new Test.Sub.Foo()
+        // in the package where the class Test exists.
+        // so in this case we need to use the unqualified name
+        // ie new Test() and new Foo()
+
+        // note we need to retain the fully qualified case for when
+        // we add library classes etc which may involve constructing
+        // objects of types which are not in the current package
+
+        if (!p.isUnnamedPackage()) {
+            String pkgName = p.getQualifiedName();
+            int firstDot = pkgName.indexOf(".");
+
+            if (firstDot >= 0)
+                pkgName = pkgName.substring(0, firstDot);
+
+            // if the first part of the package name exists as a target
+            // lets unqualify the typeName
+            if (p.getTarget(pkgName) != null)
+                typeName = JavaNames.getBase(typeName);
+        }
+
+        // now we need to deal with nested types
+        // these types will have a $ in them but depending on whether
+        // they are anonymous classes or member classes will change how
+        // we want to refer to them
+        // an anonymous class we can refer to as MyClass$1 and the
+        // compiler is ok with that
+        // a member class, despite being given a type name of
+        // MyClass$MemberClass, must be referred to as MyClass.MemberClass
+        // in the source code. Here we make this change to the typeName
+        // based entirely on whether the character following the $ is
+        // a numeral or not (which just happens to be the way it is at
+        // the moment but I don't think its written down in the JLS or
+        // anything so this may break)
+
+        int firstDollar = typeName.indexOf('$');
+
+        if (firstDollar != -1) {
+            StringBuffer sb = new StringBuffer(typeName);
+
+            // go to length - 1 only so we always have an i+1 character
+            // to check. What this means is that if the last character
+            // in the typeName is a $, it won't be converted but I don't
+            // think a type name with a $ as the last character is valid
+            // anyway
+            for (int i = firstDollar; i < sb.length() - 1; i++) {
+                if (sb.charAt(i) == '$' && !Character.isDigit(sb.charAt(i + 1)))
+                    sb.setCharAt(i, '.');
+            }
+
+            typeName = sb.toString();
+        }
+
+        return JavaNames.typeName(typeName);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/InvokerCompiler.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/InvokerCompiler.java
new file mode 100644
index 0000000000000000000000000000000000000000..3fee98f17efe70d8870b5561b59f7f136b3b46f7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/InvokerCompiler.java
@@ -0,0 +1,36 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import java.io.File;
+
+import bluej.compiler.CompileObserver;
+
+/**
+ * An interface for compiling jobs from the Invoker.
+ * 
+ * @author Davin McCall
+ */
+public interface InvokerCompiler
+{
+    void compile(File [] files, CompileObserver observer);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/LibraryCallDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/LibraryCallDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..1836f1f839414d3c4a30bc6a0af1d13dcb260931
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/LibraryCallDialog.java
@@ -0,0 +1,355 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+import bluej.*;
+import bluej.pkgmgr.*;
+import bluej.pkgmgr.Package;
+import bluej.utility.*;
+import bluej.views.*;
+
+/**
+ * This dialog allows selection of classes and their static methods from
+ * available libraries. When a constructor or static method is selected
+ * it can be invoked.
+ *
+ * @author  Michael Kolling
+ */
+public class LibraryCallDialog extends EscapeDialog
+	implements ActionListener, ListSelectionListener
+{
+    private static final String[] clickHere = {
+        "    ",
+        "    " + Config.getString("callLibraryDialog.clickHere1"),
+        "    " + Config.getString("callLibraryDialog.clickHere2"),
+    };
+
+    private static final String[] classNotFound = {
+        "    ",
+        "    " + Config.getString("callLibraryDialog.classNotFound1"),
+        "    " + Config.getString("callLibraryDialog.classNotFound2"),
+    };
+
+    private JComboBox classField;
+    private JList methodList;
+    private JButton docButton;
+    private JButton okButton;
+    private JButton cancelButton;
+
+    private ClassHistory history;
+    private Package pkg;
+    private CallableView viewToCall;
+    private List<CallableView> currentViews;      // views currently displayed in list
+
+    public LibraryCallDialog(PkgMgrFrame pmf)
+    {
+        super(pmf, Config.getString("callLibraryDialog.title"), false);
+        pkg = pmf.getPackage();
+        currentViews = new ArrayList<CallableView>();
+        viewToCall = null;
+        history = ClassHistory.getClassHistory(10);
+        makeDialog();
+    }
+
+
+    /**
+     * Set the visibility of the dialog
+     */
+    public void setVisible(boolean show)
+    {
+    	super.setVisible(show);
+    	if (show) {
+            okButton.setEnabled(false);
+            classField.setModel(new DefaultComboBoxModel(history.getHistory().toArray()));
+            classSelected();
+            classField.requestFocus();
+    	}
+    }
+
+    /**
+     * Process action events
+     */
+    public void actionPerformed(ActionEvent event)
+    {
+        Object eventSource = event.getSource();
+        if(eventSource == classField)
+            classSelected();
+        else if (eventSource == docButton)
+            showDocumentation();
+        else if (eventSource == okButton)
+            doOk();
+        else if (eventSource == cancelButton)
+            doCancel();
+    }
+
+    /**
+     * Show the javadoc documentation for the selected class in a browser.
+     */
+    private void showDocumentation()
+    {
+        String className = (String)classField.getEditor().getItem();
+        
+        // Assume unqualified classes are in java.lang
+        if(className.indexOf('.') == -1)
+            className = "java.lang." + className;
+        
+        Utility.showClassDocumentation(className, "#constructor_summary");
+    }
+
+    /**
+     * doOk - Process an "Ok" event to invoke a Constructor or Method.
+     *  Collects arguments and calls watcher objects (Invoker).
+     */
+    private void doOk()
+    {
+        if(viewToCall == null)   // not a method - help text selected
+            return;
+
+        history.add((String)classField.getEditor().getItem());
+        setVisible(false);
+        pkg.getEditor().raiseMethodCallEvent(pkg, viewToCall);
+    }
+
+    /**
+     * Process a "Cancel" event to cancel a call.
+     * Makes dialog invisible.
+     */
+    private void doCancel()
+    {
+        setVisible(false);
+    }
+
+    /**
+     * A class was selected in the class selection box. Try to load that
+     * class. If successful, display its constructors and methods. Otherwise
+     * clear the method list and return.
+     */
+    private void classSelected()
+    {
+        Class<?> cl = null;
+        currentViews.clear();
+        viewToCall = null;
+        okButton.setEnabled(false);
+
+        String className = (String)classField.getEditor().getItem();
+
+        if(className.length() == 0) {
+            displayTextInClassList(clickHere);
+            return;
+        }
+
+        boolean loaded;
+        try {
+            ClassLoader loader = pkg.getProject().getClassLoader();
+            cl = loader.loadClass(className);
+            loaded = true;
+        }
+        catch(Exception exc) {
+            loaded = false;
+        }
+        if (!loaded) {   // try for unqualified names in java.lang
+            try {
+                ClassLoader loader = pkg.getProject().getClassLoader();
+                cl = loader.loadClass("java.lang."+className);
+            }
+            catch(Exception exc) {
+                displayTextInClassList(classNotFound);
+                return;
+            }
+        }
+        displayMethodsForClass(cl);
+    }
+
+    /**
+     * Given a class, display its constructors and methods in the method list.
+     */
+    private void displayMethodsForClass(Class<?> cl)
+    {
+        View classView = View.getView(cl);
+        ViewFilter filter;
+        List<String> list = new ArrayList<String>();
+
+        ConstructorView[] constructors = classView.getConstructors();
+        
+        // Determine visibility of package private / protected members
+        int visibilityMod = ViewFilter.PUBLIC;
+        if (classView.getPackageName().equals(pkg.getQualifiedName()))
+            visibilityMod = ViewFilter.PACKAGE;
+
+        filter = new ViewFilter(ViewFilter.INSTANCE | visibilityMod);
+        addMethods(list, constructors, filter);
+
+        MethodView[] methods = classView.getAllMethods();
+        filter = new ViewFilter(ViewFilter.STATIC | visibilityMod);
+        addMethods(list, methods, filter);
+
+        methodList.setListData(list.toArray());
+        methodList.clearSelection();
+        methodList.setEnabled(true);
+        docButton.setEnabled(true);
+    }
+
+    /**
+     * Display a message that the current class was not found.
+     */
+    private void displayTextInClassList(String[] text)
+    {
+        methodList.setListData(text);
+        methodList.setEnabled(false);
+        docButton.setEnabled(false);
+    }
+
+    /**
+     * Add some methods, filtered by a given view filter, to a list.
+     */
+    public void addMethods(List<String> list, CallableView[] methods,
+                            ViewFilter filter)
+    {
+        for(int i = 0; i < methods.length; i++) {
+            if(filter.accept(methods[i])) {
+                currentViews.add(methods[i]);
+                list.add(methods[i].getShortDesc());
+                //list.add(methods[i].toString());  // includes public static
+            }
+        }
+    }
+
+    // ----- ListSelectionListener interface -----
+
+    /**
+     *  A list item was selected. This can be either in the thread list,
+     *  the stack list, or one of the variable lists.
+     */
+    public void valueChanged(ListSelectionEvent event)
+    {
+        if(event.getValueIsAdjusting())  // ignore mouse down, dragging, etc.
+            return;
+
+        int index = methodList.getSelectedIndex();
+        if(index == -1)
+            return;
+
+        String text = (String)methodList.getSelectedValue();
+        if(text.charAt(0) == ' ')
+            return;
+
+        viewToCall = currentViews.get(index);
+        okButton.setEnabled(true);
+    }
+
+    // ----- end of ListSelectionListener interface -----
+
+    /**
+     * Build the Swing dialog.
+     */
+    private void makeDialog()
+    {
+        JPanel contentPane = (JPanel)getContentPane();
+
+        JPanel classPanel = new JPanel(new BorderLayout(4,6));
+        {
+            classPanel.add(new JLabel(
+                  Config.getString("callLibraryDialog.classLabel")),
+                  BorderLayout.WEST);
+
+            classField = new JComboBox(history.getHistory().toArray());
+            classField.setEditable(true);
+            classField.setMaximumRowCount(10);
+            JTextField textField = (JTextField)classField.getEditor().getEditorComponent();
+            textField.setColumns(16);
+            classField.addActionListener(this);
+            classPanel.add(classField, BorderLayout.CENTER);
+
+            docButton = new JButton(Config.getString("callLibraryDialog.docButton"));
+            docButton.addActionListener(this);
+            docButton.setEnabled(false);
+            classPanel.add(docButton, BorderLayout.EAST);
+        }
+
+        // create the centre Panel
+        JPanel centrePanel = new JPanel(new BorderLayout());
+        {
+            methodList = new JList();
+            methodList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+            methodList.addListSelectionListener(this);
+            methodList.setVisibleRowCount(8);
+            JScrollPane methodScrollPane = new JScrollPane(methodList);
+            methodScrollPane.setColumnHeaderView(new JLabel(
+                 Config.getString("callLibraryDialog.listHeading")));
+
+            MouseListener mouseListener = new MouseAdapter() {
+                    public void mouseClicked(MouseEvent e) {
+                        if (e.getClickCount() == 2) {
+                            doOk();
+                        }
+                    }
+                };
+            methodList.addMouseListener(mouseListener);
+
+            centrePanel.add(methodScrollPane, BorderLayout.CENTER);
+
+        }
+
+        // create the Button Panel
+        JPanel buttonPanel = new JPanel();
+        {
+            buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+
+            okButton = BlueJTheme.getOkButton();
+            okButton.addActionListener(this);
+            
+            cancelButton = BlueJTheme.getCancelButton();
+            cancelButton.addActionListener(this);
+            
+            DialogManager.addOKCancelButtons(buttonPanel, okButton, cancelButton);
+
+            getRootPane().setDefaultButton(okButton);
+            okButton.setEnabled(false);
+        }
+
+        //contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
+        contentPane.setLayout(new BorderLayout(6,6));
+        contentPane.setBorder(BlueJTheme.generalBorder);
+
+        contentPane.add(classPanel, BorderLayout.NORTH);
+        contentPane.add(centrePanel, BorderLayout.CENTER);
+        contentPane.add(buttonPanel, BorderLayout.SOUTH);
+
+        pack();
+        DialogManager.centreDialog(this);
+
+        // Close Action when close button is pressed
+        addWindowListener(new WindowAdapter() {
+                public void windowClosing(WindowEvent event) {
+                    setVisible(false);
+                }
+            });
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/MethodDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/MethodDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..e77feb8d4d98b31621e54fb0aaa89603a1672600
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/MethodDialog.java
@@ -0,0 +1,276 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.FocusListener;
+import java.util.Map;
+
+import javax.swing.BorderFactory;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+import bluej.Config;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugmgr.objectbench.ObjectBenchInterface;
+import bluej.utility.JavaNames;
+import bluej.views.CallableView;
+import bluej.views.LabelPrintWriter;
+import bluej.views.MethodView;
+
+
+/**
+ * This dialog is used for an interactive method call. The call
+ * can be an object creation or an invocation of an object method.
+ * A new instance of this dialog is created for each method.
+ *
+ * @author  Michael Kolling
+ * @author  Bruce Quig
+ * @author  Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class MethodDialog extends CallDialog implements FocusListener
+{
+    private boolean okCalled;
+    private boolean rawObject;
+
+    // Window Titles
+    private static final String appName = Config.getApplicationName(); 
+    static final String wCallRoutineTitle = appName + ":  " + Config.getString("pkgmgr.methodCall.titleCall");
+
+    static final String commentSlash = "   ";
+
+    private String methodName;
+    private MethodView method;
+    private Map<String,GenTypeParameter> typeParameterMap;
+
+    private JLabel callLabel;
+
+
+
+    /**
+     * MethodDialog constructor.
+     * 
+     * @param parentFrame  The parent window for the dialog
+     * @param ob           The object bench to listen for object selection on
+     * @param callHistory  The call history tracker
+     * @param instanceName The initial instance name (for a constructor dialog)
+     *                     or the object instance on which the method is being called
+     * @param method       The constructor or method being used
+     * @param typeMap      The mapping of type parameter names to runtime types
+     *                     (a Map of String -> GenType).
+     */
+    public MethodDialog(JFrame parentFrame, ObjectBenchInterface ob, CallHistory callHistory,
+            String instanceName, MethodView method, Map<String,GenTypeParameter> typeMap)
+    {
+        super(parentFrame, ob, "");
+
+        history = callHistory;
+
+        // Find out the type of dialog
+        methodName = method.getName();
+
+        this.method = method;
+        makeDialog(method.getClassName(), instanceName);
+        setInstanceInfo(instanceName, typeMap);
+    }
+
+    /**
+     * doOk - Process an "Ok" event to invoke a Constructor or Method.
+     * Collects arguments and calls watcher objects (Invoker).
+     */
+    public void doOk()
+    {
+        if(!okCalled) {
+            if (!parameterFieldsOk()) {
+                setErrorMessage(emptyFieldMsg);            
+            } else if(!typeParameterFieldsOk()) {     
+                setErrorMessage(emptyTypeFieldMsg);
+            } else {
+                setWaitCursor(true);
+                okButton.requestFocus();
+                SwingUtilities.invokeLater(new Runnable()
+                {
+                    public void run()
+                    {
+                        callWatcher(OK);
+                    }
+                });
+                okCalled = true;
+            }
+        }
+    }
+
+    /**
+     * setInstanceName - set the name of the instance shown in the label
+     * for method call dialogs, or in the text field for construction dialogs,
+     * and the assosciated type parameters.
+     */
+    public void setInstanceInfo(String instanceName, Map<String,GenTypeParameter> typeParams)
+    {
+        typeParameterMap = typeParams;
+        rawObject = instanceName != null && typeParams == null;
+        createDescription();
+        
+        // reset error label message
+        setErrorMessage("");
+
+        clearParameters();
+        startObjectBenchListening();
+
+        // focus requests have been wrapped in invokeLater method to resolve issues 
+        // with focus confusion on Mac OSX (BlueJ 2.0, JDK 1.4.2)
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run()
+            {
+                if (typeParameterList != null) {
+                    typeParameterList.getParameter(0).getEditor().getEditorComponent().requestFocusInWindow();
+                }
+                else if (parameterList != null) {
+                    parameterList.getParameter(0).getEditor().getEditorComponent().requestFocusInWindow();
+                }
+            }
+        });
+    }
+    
+    /**
+     * Create the description. This includes the comments for the method
+     * or constructor, together with its signature, and appears at the top
+     * of the dialog.
+     */
+    private void createDescription()
+    {
+        LabelPrintWriter writer = new LabelPrintWriter();
+        method.print(writer, typeParameterMap, 0);
+        setDescription(writer.getLabel());
+        setVisible(true);
+    }
+    
+    /*
+     * @see bluej.debugmgr.CallDialog#makeDialogInternal(java.lang.String, java.lang.String, javax.swing.JPanel)
+     */
+    @Override
+    protected void makeDialogInternal(String className, String instanceName, JPanel centerPanel)
+    {
+        makeCallDialog(className, instanceName, method, centerPanel);
+    }
+
+    /**
+     * makeCallDialog - create a dialog to make a method call
+     */
+    private void makeCallDialog(String className, String instanceName, CallableView method,
+            JPanel panel)
+    {
+        JPanel tmpPanel;
+        setTitle(wCallRoutineTitle);
+        MethodView methView = (MethodView) method;
+        tmpPanel = new JPanel();
+        tmpPanel.setOpaque(false);
+        GridBagLayout gridBag = new GridBagLayout();
+        tmpPanel.setLayout(gridBag);
+        GridBagConstraints constraints = new GridBagConstraints();
+        constraints.insets = INSETS;
+        callLabel = new JLabel("", JLabel.RIGHT);
+        if (method.isStatic()) {
+            setCallLabel(className);
+        }
+        else {
+            setCallLabel(instanceName);
+        }
+        if (methView.isMain()) {
+            defaultParamValue = "{ }";
+        }
+
+        setPreferredHeight(callLabel, getComboBoxHeight());
+
+        constraints.anchor = GridBagConstraints.NORTHWEST;
+        gridBag.setConstraints(callLabel, constraints);
+        tmpPanel.add(callLabel);
+        JPanel parameterPanel = createParameterPanel();
+        parameterPanel.setOpaque(false);
+        constraints.gridy++;
+        tmpPanel.add(parameterPanel, constraints);
+        tmpPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+        tmpPanel.setAlignmentX(LEFT_ALIGNMENT);
+        panel.add(tmpPanel);
+    }
+
+    /**
+     * Set the text of the label showing the call to be made.
+     */
+    public void setCallLabel(String instanceName)
+    {
+        callLabel.setText(JavaNames.stripPrefix(instanceName) + "." + methodName);
+    }
+    
+    /**
+     * Redefined setEnabled method to ensure that OK button gets disabled.
+     * As ActionListeners are also attached to combo boxes it can trigger 
+     * more than one OK action as the default button also catches an 
+     * action whther it has focus or not.
+     * 
+     * <p>Calling setEnabled on the Dialog alone does not prevent the default button 
+     * from getting action events. We therefore explicitly call setEnabled on the 
+     * default button (OK)
+     * 
+     * <p>The okCalled flag is used to prevent multiple rapid button presses before
+     * the button and dialog are disabled.
+     */
+    public void setEnabled(boolean state)
+    {
+        okButton.setEnabled(state);
+        super.setEnabled(state);
+        if(state) {
+            //reset ok called status when re-enabling dialog
+            okCalled = false;    
+        }
+    }
+    
+    /*
+     * @see bluej.debugmgr.CallDialog#getCallableView()
+     */
+    @Override
+    protected CallableView getCallableView()
+    {
+        return method;
+    }
+    
+    /*
+     * @see bluej.debugmgr.CallDialog#targetIsRaw()
+     */
+    @Override
+    protected boolean targetIsRaw()
+    {
+        return rawObject;
+    }
+
+    /*
+     * @see bluej.debugmgr.CallDialog#getTargetTypeArgs()
+     */
+    @Override
+    protected Map<String, GenTypeParameter> getTargetTypeArgs()
+    {
+        return typeParameterMap;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/NamedValue.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/NamedValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..d4cb0788e43be3f49fcbf2bad7032e9637f0d92e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/NamedValue.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import bluej.debugger.gentype.JavaType;
+
+/**
+ * A named value, such as an object on the object bench or a local variable
+ * in the code page.
+ * 
+ * @author Davin McCall
+ * @version $Id: NamedValue.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface NamedValue
+{
+    /**
+     * Get the name of the named value.
+     */
+    public String getName();
+
+    /**
+     * Check whether the value has been initialized. This is used to
+     * distinguish established values from values which are expected to be
+     * initialized by the user. If it returns false, the value is not yet
+     * available.
+     */
+    public boolean isInitialized();
+    
+    /**
+     * Check whether the value of this named value can be modified.
+     */
+    public boolean isFinal();
+    
+    /**
+     * Get the nominated type of this value.
+     */
+    public JavaType getGenType();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ResultWatcher.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ResultWatcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa505c6b638da61a3c48620a8f84c53cc1d8434a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ResultWatcher.java
@@ -0,0 +1,79 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.ExceptionDescription;
+
+import bluej.testmgr.record.*;
+
+
+/**
+ * Debugger interface implemented by classes interested in the result of an invocation.
+ * All methods should be called on the GUI thread.
+ *
+ * @author  Michael Kolling
+ * @author  Poul Henriksen
+ */
+public interface ResultWatcher
+{
+    /**
+     * The user has supplied any requested arguments, and compilation has begun. 
+     */
+    void beginCompile();
+    
+    /**
+     * Compilation (if needed) was successful, and execution has begun.
+     */
+    void beginExecution(InvokerRecord ir);
+    
+    /**
+     * An invocation has completed - here is the result.
+     * 
+     * @param result   The invocation result object.
+     *                 For a constructor call, the result object is the newly created instance.
+     *                 For any other invocation, the result is a wrapper object with a single
+     *                 field containing the actual result, or an object representing null if the
+     *                 invocation result type is void.
+     * @param name     The name of the result. For a constructed object, this
+     *                 is the name supplied by the user. Otherwise this is  the
+     *                 literal "result", or null if the result is void type.
+     * @param ir       The record for the completed invocation
+     */
+    void putResult(DebuggerObject result, String name, InvokerRecord ir);
+    
+    /**
+     * An invocation has failed (compilation error) - here is the error message.
+     */
+    void putError(String message, InvokerRecord ir);
+    
+    /**
+     * A runtime exception occurred - here is the exception text, and stack trace
+     */
+    void putException(ExceptionDescription exception, InvokerRecord ir);
+    
+    /**
+     * The debug VM terminated. This may have been due to an explicit user action in
+     * the UI, or the executing code called System.exit().
+     */
+    void putVMTerminated(InvokerRecord ir);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ValueCollection.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ValueCollection.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7700a76ba98a08e7d5c8ab01e71fd114ee0ee3f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/ValueCollection.java
@@ -0,0 +1,50 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr;
+
+import java.util.Iterator;
+
+
+/**
+ * A collection of named values (NameValue interface), which may be references
+ * (objects) or primitive values.
+ * 
+ * @author Davin McCall
+ * @version $Id: ValueCollection.java 6595 2009-09-02 14:30:49Z davmac $
+ */
+public interface ValueCollection
+{   
+    /**
+     * Get an iterator through the values in this collection.
+     */
+    public Iterator<? extends NamedValue> getValueIterator();
+    
+    /**
+     * Get a value by name, in this collection or in a parent scope. This may delegate to
+     * another collection to provide scoping, and in particular, may provide access to
+     * values not seen by the iterator returned by getValueIterator().
+     * 
+     * @param name   The name of the value to retrieve
+     * @return       The value, or null if it does not exist.
+     */
+    public NamedValue getNamedValue(String name);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/AssertPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/AssertPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9e65317ff2628861911b6058c8fa2109b94b25a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/AssertPanel.java
@@ -0,0 +1,281 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.inspector;
+
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugger.gentype.JavaType;
+import bluej.pkgmgr.Package;
+import bluej.testmgr.record.InvokerRecord;
+
+/**
+ * A panel that can record assertion statements.
+ * 
+ * @author  Andrew Patterson  
+ */
+public class AssertPanel extends JPanel
+{
+    private static final String equalToLabel =
+        Config.getString("debugger.assert.equalTo");
+    private static final String sameAsLabel =
+        Config.getString("debugger.assert.sameAs");
+    private static final String notSameAsLabel =
+        Config.getString("debugger.assert.notSameAs");
+    private static final String notNullLabel =
+        Config.getString("debugger.assert.notNull");
+    private static final String assertNullLabel =
+        Config.getString("debugger.assert.null");
+    private static final String equalToFloatingPointLabel =
+        Config.getString("debugger.assert.equalToFloatingPoint");
+
+    /**
+     * The panels and UI elements of this panel.
+     */
+    private JPanel standardPanel;
+    private JLabel assertLabel;
+    private JLabel deltaLabel;
+    private JTextField assertData;
+    // used for delta in float and double comparison
+    private JTextField deltaData; 
+    private JComboBox assertCombo;
+    protected JCheckBox assertCheckbox;
+    private int[] comboIndexes;
+    
+    private boolean[] firstLabelFieldNeeded = new boolean[] {
+            true, true, true, false, false, true
+        };
+
+    private boolean[] secondFieldNeeded = new boolean[] {
+            false, false, false, false, false, true
+        };
+
+    /**
+     * Assert labels together with the corresponding assertion method to be called
+     */
+    private String[][] labelStatements = new String[][] {
+            {equalToLabel, "assertEquals"},
+            {sameAsLabel, "assertSame"},
+            {notSameAsLabel, "assertNotSame"},
+            {notNullLabel, "assertNotNull"},
+            {assertNullLabel, "assertNull"},
+            {equalToFloatingPointLabel, "assertEquals"}
+    };
+    
+    private int[] fpIndexes = {5};
+    private int[] primitiveIndexes = {0};
+    private int[] objectIndexes = {0, 1, 2, 3, 4};
+        
+    /**
+     * A panel which presents an interface for making a single
+     * assertion about a result. 
+     */
+    public AssertPanel()
+    {
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+
+        // a checkbox which enables/disables all the assertion UI
+
+        assertCheckbox = new JCheckBox(Config.getString("debugger.assert.assertThat"), true);
+        {
+            assertCheckbox.setAlignmentX(LEFT_ALIGNMENT);
+            assertCheckbox.addItemListener(new ItemListener() {
+                public void itemStateChanged(ItemEvent ie)
+                {
+                    boolean isSelected = ie.getStateChange() == ItemEvent.SELECTED;
+                    assertCombo.setEnabled(isSelected);
+                    assertData.setEnabled(isSelected);
+                    assertLabel.setEnabled(isSelected);
+                    deltaData.setEnabled(isSelected);
+                    deltaLabel.setEnabled(isSelected);
+                }
+            });
+        }
+
+        standardPanel = new JPanel();
+        {
+            standardPanel.setBorder(BlueJTheme.generalBorder);
+            standardPanel.setLayout(new BoxLayout(standardPanel, BoxLayout.X_AXIS)); 
+            standardPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+            standardPanel.add(assertLabel = new JLabel(Config.getString("debugger.assert.resultIs")));
+            standardPanel.add(Box.createHorizontalStrut(BlueJTheme.componentSpacingSmall));
+
+            assertCombo = new JComboBox();
+            {
+                assertCombo.addItemListener(new ItemListener() {
+                    public void itemStateChanged(ItemEvent ie)
+                    {
+                        if (ie.getStateChange() == ItemEvent.SELECTED) {
+                            itemSelected(assertCombo.getSelectedIndex());
+                        }
+                    }
+                });
+            }                       
+
+            assertData = new JTextField(14);
+
+            deltaData = new JTextField(6);
+
+            standardPanel.add(assertCombo);
+            standardPanel.add(Box.createHorizontalStrut(BlueJTheme.componentSpacingSmall));
+
+            deltaLabel = new JLabel(Config.getString("debugger.assert.delta"));
+            standardPanel.add(assertData);
+            standardPanel.add(Box.createHorizontalStrut(BlueJTheme.componentSpacingSmall));
+            standardPanel.add(deltaLabel);
+            standardPanel.add(Box.createHorizontalStrut(BlueJTheme.componentSpacingSmall));
+            standardPanel.add(deltaData);
+
+            deltaData.setVisible(false);
+            deltaLabel.setVisible(false);
+
+            assertCombo.setEnabled(true);
+            assertData.setEnabled(true);
+            assertLabel.setEnabled(true);
+            deltaData.setEnabled(true);
+            deltaLabel.setEnabled(true);
+        }
+
+        add(assertCheckbox);
+        add(standardPanel);
+    }
+
+    /**
+     * An assertion type was selected from the combo box.
+     */
+    private void itemSelected(int index)
+    {
+        index = comboIndexes[index];
+
+        // we have to also take into account the assertion check box status.
+        // if it is not enabled, then we shouldn't enable the data controls either
+        if(index >= 0) {
+            boolean firstNeeded = firstLabelFieldNeeded[index] && assertCheckbox.isSelected();
+            boolean secondNeeded = secondFieldNeeded[index] && assertCheckbox.isSelected();
+
+            assertData.setEnabled(firstNeeded);
+            //assertData.setBackground(firstNeeded ? Color.white : Color.lightGray);
+
+            // if the second field is needed, we _always_ make it visible
+            // (but perhaps not enabled)
+            deltaLabel.setVisible(secondFieldNeeded[index]);
+            deltaData.setVisible(secondFieldNeeded[index]);
+
+            deltaLabel.setEnabled(secondNeeded);
+            deltaData.setEnabled(secondNeeded);
+        }
+    }
+    
+    /**
+     * Set the result type, used to determine which assertion methods may be applicable.
+     */
+    public void setResultType(JavaType type)
+    {
+        if (type.typeIs(JavaType.JT_FLOAT) || type.typeIs(JavaType.JT_DOUBLE)) {
+            comboIndexes = fpIndexes;
+            deltaData.setText("0.1");
+            itemSelected(0); // force display of delta box
+        }
+        else if (type.isPrimitive()) {
+            comboIndexes = primitiveIndexes;
+        }
+        else {
+            comboIndexes = objectIndexes;
+        }
+        
+        String [] comboLabels = new String[comboIndexes.length];
+        for (int i = 0; i < comboLabels.length; i++) {
+            comboLabels[i] = labelStatements[comboIndexes[i]][0];
+        }
+        
+        assertCombo.setModel(new DefaultComboBoxModel(comboLabels));
+    }
+    
+    /**
+     * Check whether the user has asked for an assertion to be recorded.
+     */
+    public boolean isAssertEnabled()
+    {
+        return assertCheckbox != null ? assertCheckbox.isSelected() : false;
+    }
+    
+    /**
+     * Check whether the necessary fields have been filled in to make a compilable
+     * assert statement.
+     */
+    public boolean isAssertComplete()
+    {
+        int index = comboIndexes[assertCombo.getSelectedIndex()];
+        
+        if (secondFieldNeeded[index]) {
+            if (deltaData.getText().trim().length() == 0) {
+                return false;
+            }
+        }
+        
+        if (firstLabelFieldNeeded[index]) {
+            if (assertData.getText().trim().length() == 0) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Return an assertion statement out of the data in the UI.
+     * 
+     * @return a String representing the assertion specified in this
+     *         assertion panel.
+     */
+    public String getAssertStatement()
+    {
+        // which type of assertion is selected
+        int index = comboIndexes[assertCombo.getSelectedIndex()];
+        
+        // for double/float assertEquals() assertions, we need a delta value
+        if (secondFieldNeeded[index]) {
+            return InvokerRecord.makeAssertionStatement(labelStatements[index][1],
+                                                        assertData.getText(),
+                                                        deltaData.getText());
+        }
+        else if (firstLabelFieldNeeded[index]) {
+            return InvokerRecord.makeAssertionStatement(labelStatements[index][1],
+                                                        assertData.getText());
+        }
+        else {
+            return InvokerRecord.makeAssertionStatement(labelStatements[index][1]);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/ClassInspector.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/ClassInspector.java
new file mode 100644
index 0000000000000000000000000000000000000000..5f07a455f7929e6210e033acac8df454adc9834a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/ClassInspector.java
@@ -0,0 +1,288 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.inspector;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JTabbedPane;
+import javax.swing.border.EmptyBorder;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerField;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.target.role.StdClassRole;
+import bluej.prefmgr.PrefMgr;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.DialogManager;
+import bluej.utility.JavaNames;
+
+/**
+ * A window that displays the static fields in an class.
+ * 
+ * @author Michael Kolling
+ * @author Poul Henriksen
+ * @version $Id: ClassInspector.java 9024 2011-06-21 03:07:08Z davmac $
+ */
+public class ClassInspector extends Inspector
+{
+    // === static variables ===
+
+    protected final static String CLASS_INSPECT_TITLE = Config.getString("debugger.inspector.class.title");
+    protected final static String CLASS_NAME_LABEL = Config.getString("debugger.inspector.class.nameLabel");
+
+    protected final static String ENUM_INSPECT_TITLE = Config.getString("debugger.inspector.enum.title");
+    protected final static String ENUM_NAME_LABEL = Config.getString("debugger.inspector.enum.nameLabel");
+
+    protected final static String INTERFACE_INSPECT_TITLE = Config.getString("debugger.inspector.interface.title");
+    protected final static String INTERFACE_NAME_LABEL = Config.getString("debugger.inspector.interface.nameLabel");
+
+    protected final static String noFieldsMsg = Config.getString("debugger.inspector.class.noFields");
+    
+    // === instance variables ===
+
+    protected DebuggerClass myClass;
+
+   
+
+    /**
+     * Note: 'pkg' may be null if getEnabled is false.
+     *  
+     */
+    public ClassInspector(DebuggerClass clss, InspectorManager inspectorManager, Package pkg, InvokerRecord ir, final JFrame parent)
+    {
+        super(inspectorManager, pkg, ir, new Color(249,230,207));
+
+        myClass = clss;
+
+        final ClassInspector insp = this;
+
+        makeFrame();
+        update();
+        updateLayout();
+        pack();
+        
+        if (parent instanceof Inspector) {
+            DialogManager.tileWindow(insp, parent);
+        }
+        else {
+            DialogManager.centreWindow(insp, parent);
+        }
+        installListenersForMoveDrag();
+    }
+
+    /**
+     * Build the GUI
+     */
+    protected void makeFrame()
+    {
+        setUndecorated(true);
+        
+        String className = JavaNames.stripPrefix(myClass.getName());
+        String headerString = null;
+        if(myClass.isEnum()) {
+            setTitle(ENUM_INSPECT_TITLE);
+            headerString = ENUM_NAME_LABEL + " " + className;
+        } else if (myClass.isInterface()) {
+            setTitle(INTERFACE_INSPECT_TITLE);
+            headerString = INTERFACE_NAME_LABEL + " " + className;
+        } else {
+            setTitle(CLASS_INSPECT_TITLE);
+            headerString = CLASS_NAME_LABEL + " " + className;
+        }
+        
+        // Create the header
+        JComponent header = new JPanel();
+        header.setOpaque(false);
+        header.setLayout(new BoxLayout(header, BoxLayout.Y_AXIS));        
+        JLabel headerLabel = new JLabel(headerString);
+
+        headerLabel.setAlignmentX(0.5f);
+        header.add(headerLabel);
+        header.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        JSeparator sep = new JSeparator();
+        sep.setForeground(new Color(217, 175, 150));
+        sep.setBackground(new Color(0, 0, 0, 0));
+        header.add(sep);
+
+        // Create the main panel (field list, Get/Inspect buttons)
+
+        JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
+        mainPanel.setOpaque(false);
+
+        if (getListData().size() != 0) {
+            JScrollPane scrollPane = createFieldListScrollPane();
+            mainPanel.add(scrollPane, BorderLayout.CENTER);
+        } else {
+            JLabel lab = new JLabel("  " + noFieldsMsg);
+            lab.setPreferredSize(new Dimension(200, 30));
+            lab.setFont(PrefMgr.getStandardFont().deriveFont(20.0f));
+            lab.setForeground(new Color(160, 120, 77));
+            mainPanel.add(lab);
+        }
+
+        JPanel inspectAndGetButtons = createInspectAndGetButtons();
+        mainPanel.add(inspectAndGetButtons, BorderLayout.EAST);
+
+        Insets insets = BlueJTheme.generalBorderWithStatusBar.getBorderInsets(mainPanel);
+        mainPanel.setBorder(new EmptyBorder(insets));
+
+        // create bottom button pane with "Close" button
+
+        JPanel bottomPanel = new JPanel();
+        bottomPanel.setOpaque(false);
+        bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS));
+        bottomPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 5));
+
+        JPanel buttonPanel;
+        buttonPanel = new JPanel(new BorderLayout());
+        buttonPanel.setOpaque(false);
+        JButton button = createCloseButton();
+        buttonPanel.add(button, BorderLayout.EAST);
+
+        bottomPanel.add(buttonPanel);
+
+        // add the components
+        JPanel contentPane = new JPanel() {
+            protected void paintComponent(Graphics g)
+            {
+                super.paintComponent(g);
+                Graphics2D g2d = (Graphics2D)g;
+                g2d.setPaint(new StdClassRole().getBackgroundPaint(getWidth(), getHeight()));
+                g2d.fillRect(0, 0, getWidth(), getHeight());
+                g2d.setColor(Color.BLACK);
+                g2d.drawRect(0, 0, getWidth()-1, getHeight()-1);
+            }
+        };
+        setContentPane(contentPane);
+        contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+        contentPane.setLayout(new BorderLayout());
+        contentPane.add(header, BorderLayout.NORTH);
+        contentPane.add(mainPanel, BorderLayout.CENTER);
+        contentPane.add(bottomPanel, BorderLayout.SOUTH);
+
+        getRootPane().setDefaultButton(button);
+    }
+
+    /**
+     * True if this inspector is used to display a method call result.
+     */
+    protected boolean showingResult()
+    {
+        return false;
+    }
+
+    /**
+     * True if this inspector is used to display a method call result.
+     */
+    protected List<FieldInfo> getListData()
+    {
+        List<DebuggerField> fields = myClass.getStaticFields();
+        List<FieldInfo> fieldInfos = new ArrayList<FieldInfo>(fields.size());
+        for (DebuggerField field : fields) {
+            String desc = Inspector.fieldToString(field);
+            String value = field.getValueString();
+            fieldInfos.add(new FieldInfo(desc, value));
+        }
+        return fieldInfos;
+    }
+
+    /**
+     * An element in the field list was selected.
+     */
+    protected void listElementSelected(int slot)
+    {
+        DebuggerField field = myClass.getStaticField(slot);
+        if (field.isReferenceType() && ! field.isNull()) {
+            setCurrentObj(field.getValueObject(null), field.getName(), field.getType().toString());
+
+            if (Modifier.isPublic(field.getModifiers())) {
+                setButtonsEnabled(true, true);
+            }
+            else {
+                setButtonsEnabled(true, false);
+            }
+        }
+        else {
+            setCurrentObj(null, null, null);
+            setButtonsEnabled(false, false);
+        }
+    }
+
+    /**
+     * Show the inspector for the class of an object.
+     */
+    protected void showClass()
+    {
+    // nothing to do here - this is the class already
+    }
+
+    /**
+     * We are about to inspect an object - prepare.
+     */
+    protected void prepareInspection()
+    {
+    // nothing to do here
+    }
+    
+    /**
+     * Remove this inspector.
+     */
+    protected void remove()
+    {
+        if(inspectorManager != null) {
+            inspectorManager.removeInspector(myClass);
+        }
+    }
+
+    /**
+     * Intialise additional inspector panels.
+     */
+    protected void initInspectors(JTabbedPane inspTabs)
+    {
+    // not supported for class inspectors.
+    }
+
+    protected int getPreferredRows()
+    {
+        return 8;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/FieldInfo.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/FieldInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c002221737b32c8882147a6627f611a0297911a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/FieldInfo.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.inspector;
+
+/**
+ * Plain old data type for field/value pairs.
+ * 
+ * @author Davin McCall
+ */
+public class FieldInfo
+{
+    private String description;
+    private String value;
+    
+    /**
+     * Construct a FieldInfo object with the given field description (modifiers, type, name) and value.
+     */
+    public FieldInfo(String description, String value)
+    {
+        this.description = description;
+        this.value = value;
+    }
+    
+    /**
+     * Get the field description (modifiers, type, name).
+     */
+    public String getDescription()
+    {
+        return description;
+    }
+    
+    /**
+     * Get the field value representation.
+     * @return
+     */
+    public String getValue()
+    {
+        return value;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/FieldList.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/FieldList.java
new file mode 100644
index 0000000000000000000000000000000000000000..95fd589190f91cd719637301528430f3034214d5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/FieldList.java
@@ -0,0 +1,281 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.inspector;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.Border;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+
+import bluej.Config;
+import bluej.debugger.DebuggerObject;
+
+/**
+ * A graphical representation of a list of fields from a class or object.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ *  
+ */
+public class FieldList extends JTable
+{
+    private int preferredWidth;
+
+    /**
+     * Creates a new fieldlist with no data.
+     * 
+     * @param preferredWidth
+     *            Used to determine the width of the columns. This will be the
+     *            default width of the list when the inspector is first shown.
+     * @param valueFieldColor
+     *            background color of the value field.
+     */
+    public FieldList(int preferredWidth, Color valueFieldColor)
+    {
+        super(new ListTableModel());
+
+        this.preferredWidth = preferredWidth;
+        this.setShowGrid(false);
+        this.setRowSelectionAllowed(true);
+        this.setColumnSelectionAllowed(false);
+        this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        this.setIntercellSpacing(new Dimension());
+        this.setDefaultRenderer(Object.class, new ListTableCellRenderer(valueFieldColor));
+
+        this.setRowHeight(25);
+        this.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+        this.getTableHeader().setVisible(false);
+    }
+
+    /**
+     * Notify that the component has been added as a child of a container.
+     */
+    public void addNotify()
+    {
+        // The table header gets added to the enclosing scrollpane from
+        // JTable.addNotify(). Remove it again immediately.
+        super.addNotify();
+        removeHeader();
+    }
+
+    /**
+     * A list of fields that should be shown in this list.
+     * 
+     * @param listData
+     *            The list of fields
+     */
+    public void setData(List<FieldInfo> listData)
+    {
+        ((ListTableModel) getModel()).setData(listData);
+
+        setColumnWidths(listData);
+        
+        revalidate();        
+    }
+
+    /**
+     * Calculate column widths based on the data.
+     */
+    private void setColumnWidths(List<FieldInfo> listData)
+    {
+        int colPrefWidth = preferredWidth/2;
+
+        for (int column = 0; column < 2; column++) {
+            TableColumn tableColumn = getColumnModel().getColumn(column);
+
+            int contentsMaxWidth = getMaxWidth(listData, column);
+            
+            // Make the minimum width look nice. A minimum width is always
+            // needed so short columns doesn't get squeezed by long columns.
+            if (contentsMaxWidth < colPrefWidth) {
+                tableColumn.setMinWidth(contentsMaxWidth);
+            }
+            else {
+                tableColumn.setMinWidth(colPrefWidth);
+            }
+            
+            tableColumn.setPreferredWidth(contentsMaxWidth);
+        }
+    }
+
+    /**
+     * Finds the maximum width among all the elements in the given column in the data.
+     */
+    private int getMaxWidth(List<FieldInfo> listData, int column)
+    {
+        TableCellRenderer ltcr = getDefaultRenderer(Object.class);
+        TableColumn tableColumn = getColumnModel().getColumn(column);
+        int contentsMaxWidth = tableColumn.getPreferredWidth();
+        for (int row = 0; row < listData.size(); row++) {
+            Component n = ltcr.getTableCellRendererComponent(this, dataModel.getValueAt(row, column),
+                    false, false, row, column);
+            contentsMaxWidth = Math.max(contentsMaxWidth, n.getPreferredSize().width);
+        }
+        return contentsMaxWidth;
+    }
+
+    /**
+     * Ensures that the header of the table is not shown at all!
+     */
+    private void removeHeader()
+    {
+        this.unconfigureEnclosingScrollPane();
+    }
+
+    static class ListTableModel extends AbstractTableModel
+    {
+        private String[][] cells;
+
+        public ListTableModel()
+        {
+            super();
+        }
+
+        public ListTableModel(List<FieldInfo> rows)
+        {
+            setData(rows);
+        }
+        
+        @Override
+        public String getValueAt(int row, int col)
+        {
+            return cells[row][col];
+        }
+
+        @Override
+        public int getColumnCount()
+        {
+            return 2;
+        }
+
+        @Override
+        public int getRowCount()
+        {
+            if (cells != null) {
+                return cells.length;
+            }
+            else {
+                return 0;
+            }
+        }
+
+        /**
+         * Set the field list data.
+         */
+        public void setData(List<FieldInfo> rows)
+        {
+            cells = new String[rows.size()][2];
+            Iterator<FieldInfo> f = rows.iterator();
+            for (int i = 0; i < rows.size(); i++) {
+                FieldInfo field = f.next();
+                cells[i][0] = field.getDescription();
+                cells[i][1] = field.getValue();
+            }
+        }
+
+        @Override
+        public boolean isCellEditable(int row, int column)
+        {
+            return false;
+        }
+    }
+
+    /**
+     * Cell renderer that makes a two column table look like a list.
+     * 
+     * @author Poul Henriksen
+     */
+    public static class ListTableCellRenderer extends DefaultTableCellRenderer
+    {
+        final static private ImageIcon objectrefIcon = Config.getImageAsIcon("image.inspector.objectref");
+        final private static Border valueBorder = BorderFactory.createLineBorder(Color.gray);
+        private Color bkColor;
+
+
+        public ListTableCellRenderer(Color bkColor)
+        {
+            this.bkColor = bkColor;
+            this.setOpaque(true);
+        }
+
+        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
+                boolean hasFocus, int row, int column)
+        {
+            String valueString = (String) value;
+
+            // It seems the JRE can pass in null in certain situations. Specifically,
+            // turning the Voiceover utility on in Mac OS X (10.6.2, Java 1.6.0_17)
+            // causes this method to be called with a null value every time the list
+            // selection changes.
+            if (valueString == null) {
+                return this;
+            }
+
+            if (valueString.equals(DebuggerObject.OBJECT_REFERENCE)) {
+                this.setIcon(objectrefIcon);
+                this.setText("");
+            }
+            else {
+                this.setIcon(null);
+                this.setText(valueString);
+                if (valueString.startsWith("\"")) {
+                    this.setToolTipText(valueString);
+                }
+                else {
+                    this.setToolTipText(null);
+                }
+            }
+
+            Color rowBackground = isSelected ? table.getSelectionBackground() : bkColor;
+            this.setBackground(rowBackground);
+            
+            Border b = BorderFactory.createLineBorder(rowBackground, 3);
+
+            super.setBorder(b);
+
+            // depending in which column we are in, we have to do some different
+            // things
+            if (column == 1) {
+                this.setBackground(new Color(255,255,255));
+                this.setHorizontalAlignment(JLabel.CENTER);
+                Border compoundBorder = BorderFactory.createCompoundBorder(getBorder(), valueBorder);
+                super.setBorder(compoundBorder);
+            }
+            else {
+                this.setHorizontalAlignment(JLabel.LEADING);
+            }
+            return this;
+        }
+    }
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/Inspector.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/Inspector.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f5b1ce1e564ac039c4ed562f9bbbe5606e51fde
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/Inspector.java
@@ -0,0 +1,747 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.inspector;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionAdapter;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JRootPane;
+import javax.swing.JScrollPane;
+import javax.swing.KeyStroke;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PackageEditor;
+import bluej.testmgr.record.GetInvokerRecord;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.testmgr.record.ObjectInspectInvokerRecord;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+
+/**
+ * 
+ * A window that displays the fields in an object or class. This class is
+ * subclassed for objects, classes and method results separately
+ * (ObjectInspector, ClassInspector, ResultInspector).
+ * 
+ * @author Michael Kolling
+ * @author Poul Henriksen
+ * @author Bruce Quig
+ */
+public abstract class Inspector extends JFrame
+    implements ListSelectionListener
+{
+    // === static variables ===
+
+    protected final static String showClassLabel = Config.getString("debugger.inspector.showClass");
+    protected final static String inspectLabel = Config.getString("debugger.inspector.inspect");
+    protected final static String getLabel = Config.getString("debugger.inspector.get");
+    protected final static String close = Config.getString("close");
+ 
+    // === instance variables ===
+
+    protected JScrollPane fieldListScrollPane = null;
+    protected FieldList fieldList = null;
+    private Color fieldListBackgroundColor;
+
+    protected JButton inspectButton;
+    protected JButton getButton;
+    protected AssertPanel assertPanel;
+
+    protected DebuggerObject selectedField; // the object currently selected in
+                                            // the list
+    protected String selectedFieldName; // the name of the field of the
+                                        // currently selected object
+    protected String selectedFieldType;
+    protected InvokerRecord selectedInvokerRecord; // an InvokerRecord for the
+                                                   // selected object (if possible, else null)
+
+    protected Package pkg;
+    protected InspectorManager inspectorManager;
+    protected InvokerRecord ir;
+    protected Point initialClick;
+    
+    // Each inspector is uniquely numbered in a session, for the purposes
+    // of data collection:
+    private static AtomicInteger nextUniqueId = new AtomicInteger(1);
+    private final int uniqueId;
+
+    //The width of the list of fields
+    private static final int MIN_LIST_WIDTH = 150;
+    private static final int MAX_LIST_WIDTH = 400;
+
+    /**
+     * Convert a field to a string representation, used to display the field in the inspector value list.
+     */
+    public static String fieldToString(DebuggerField field)
+    {
+        int mods = field.getModifiers();
+        String result = "";
+        if (Modifier.isPrivate(mods)) {
+            result = "private ";
+        }
+        else if (Modifier.isPublic(mods)) {
+            result = "public ";
+        }
+        else if (Modifier.isProtected(mods)) {
+            result = "protected ";
+        }
+        
+        if (field.isHidden()) {
+            result += "(hidden) ";
+        }
+        
+        result += field.getType().toString(true);
+        result += " " + field.getName();
+        return result;
+    }
+    
+    /**
+     * Constructor.
+     * 
+     * @param pkg
+     *            the package this inspector belongs to (or null)
+     * @param ir
+     *            the InvokerRecord for this inspector (or null)
+     */
+    protected Inspector(InspectorManager inspectorManager, Package pkg, InvokerRecord ir, Color valueFieldColor)
+    {
+        super(Config.isLinux() ? null : AWTUtilitiesWrapper.getBestGC());
+        
+        if(inspectorManager == null) {
+            throw new NullPointerException("An inspector must have an InspectorManager.");
+        }
+        Image icon = BlueJTheme.getIconImage();
+        if (icon != null) {
+            setIconImage(icon);
+        }
+
+        if (pkg == null && ir != null) {
+            // Get button cannot be enabled when pkg==null
+            ir = null;
+        }
+        this.inspectorManager = inspectorManager;
+        this.pkg = pkg;
+        this.ir = ir;
+        this.uniqueId = nextUniqueId.incrementAndGet();
+
+        // We want to be able to veto a close
+        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+        addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent E)
+            {
+                doClose(true);
+            }
+        });
+
+        fieldListBackgroundColor = valueFieldColor;
+        initFieldList();
+    }
+    
+    @Override
+    protected JRootPane createRootPane()
+    {
+        // Close the dialog if escape is pressed.
+        ActionListener actionListener = new ActionListener() {
+            public void actionPerformed(ActionEvent actionEvent) {
+              doClose(true);
+            }
+        };
+        JRootPane rootPane = super.createRootPane();
+        KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+        rootPane.registerKeyboardAction(actionListener, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
+        return rootPane;
+    }
+
+    /**
+     * Initializes the list of fields. This creates the component that shows the
+     * fields.
+     * @param valueFieldColor 
+     */
+    private void initFieldList()
+    {
+        fieldList = new FieldList(MAX_LIST_WIDTH, fieldListBackgroundColor);
+        fieldList.setBackground(this.getBackground());
+        fieldList.setOpaque(true);
+        fieldList.setSelectionBackground(Config.getSelectionColour());
+        fieldList.getSelectionModel().addListSelectionListener(this);
+        // add mouse listener to monitor for double clicks to inspect list
+        // objects. assumption is made that valueChanged will have selected
+        // object on first click
+        MouseListener mouseListener = new MouseAdapter() {
+            @Override
+            public void mouseClicked(MouseEvent e)
+            {
+                // monitor for double clicks
+                if (e.getClickCount() == 2) {
+                    doInspect();
+                }
+            }
+        };
+        fieldList.addMouseListener(mouseListener);
+        
+        //to make it possible to close dialogs with the keyboard (ENTER or ESCAPE), we
+        // grab the key event from the fieldlist. 
+        fieldList.addKeyListener(new KeyListener() {            
+            public void keyPressed(KeyEvent e)
+            {
+            }
+
+            public void keyReleased(KeyEvent e)
+            {
+            }
+
+            public void keyTyped(KeyEvent e)
+            {
+                // Enter or escape?
+                if (e.getKeyChar() == '\n' || e.getKeyChar() == 27) {
+                    // On MacOS, we'll never see escape here. We have set up an
+                    // action on the root pane which will handle it instead.
+                    doClose(true);
+                    e.consume();
+                }    
+            }
+        });        
+    }
+
+    protected boolean isGetEnabled()
+    {
+        return ir != null;
+    }
+
+    @Override
+    public void setVisible(boolean visible)
+    {
+        super.setVisible(visible);
+        if (visible)
+            fieldList.requestFocus(); // doesn't seem to work
+        // requestFocus seems to work only of the
+        // component is already visible
+    }
+
+    /**
+     * De-iconify the window (if necessary) and bring it to the front.
+     */
+    public void bringToFront()
+    {
+        setState(Frame.NORMAL); // de-iconify
+        toFront(); // window to front
+    }
+
+    // --- abstract interface to be implemented by subclasses ---
+
+    /**
+     * Returns the list of data.
+     */
+    abstract protected List<FieldInfo> getListData();
+
+    /**
+     * An element in the field list was selected.
+     */
+    abstract protected void listElementSelected(int slot);
+
+    /**
+     * Remove this inspector.
+     */
+    abstract protected void remove();
+
+    /**
+     * Return the preferred number of rows that should be shown in the list
+     * 
+     * @return The number of rows
+     */
+    abstract protected int getPreferredRows();
+
+    // --- end of abstract methods ---
+
+    /**
+     * Requests an update of the field values shown in this viewer to show current object
+     * values.
+     * 
+     */
+    public void update()
+    {
+        final List<FieldInfo> listData = getListData();
+        
+        fieldList.setData(listData);
+        fieldList.setTableHeader(null);
+        
+        // Ensures that an element (if any exist) is always selected
+        if (fieldList.getSelectedRow() == -1 && listData.size() > 0) {
+            fieldList.setRowSelectionInterval(0, 0);
+        }
+                
+        // if (assertPanel != null) {
+        //    assertPanel.updateWithResultData((String) listData[0]);
+        // }
+        
+        int slot = fieldList.getSelectedRow();
+        
+        // occurs if valueChanged picked up a clearSelection event from
+        // the list
+        if (slot != -1) {
+            listElementSelected(slot);
+        }
+        
+        repaint();
+    }
+
+    /**
+     * Call this method when you want the inspector to resize to its preferred
+     * size as calculated from the elements in the inspector.
+     */
+    public void updateLayout()
+    {
+        recalculateFieldlistSize();
+        
+        // limit the preferred size of the field list scrollpane
+        if (fieldListScrollPane != null) {
+            fieldListScrollPane.setPreferredSize(null);
+            Dimension d = fieldListScrollPane.getPreferredSize();
+            fieldListScrollPane.setMaximumSize(d);
+            d = new Dimension(d);
+            d.width = Math.min(d.width, MAX_LIST_WIDTH);
+            fieldListScrollPane.setPreferredSize(d);
+        }
+        
+        pack();
+        repaint();
+    }
+    
+    /**
+     * Re-calculate the preferred field list size according to the data in the list.
+     */
+    protected void recalculateFieldlistSize()
+    {
+        final List<FieldInfo> listData = getListData();
+        int height = fieldList.getPreferredSize().height;
+        int rows = listData.size();
+        int scrollBarWidth = 0;
+        if (rows > getPreferredRows()) {
+            height = fieldList.getRowHeight() * getPreferredRows();
+            scrollBarWidth = 32; // add some space for a scrollbar
+        }
+        
+        int width = fieldList.getPreferredSize().width;
+        width = Math.max(width, MIN_LIST_WIDTH);
+        
+        fieldList.setPreferredScrollableViewportSize(new Dimension(width + scrollBarWidth, height));
+    }
+
+    // ----- ListSelectionListener interface -----
+
+    /**
+     * The value of the list selection has changed. Update the selected object.
+     * 
+     * @param e
+     *            The event object describing the event
+     */
+    public void valueChanged(ListSelectionEvent e)
+    {
+        // ignore mouse down, dragging, etc.
+        if (e.getValueIsAdjusting()) {
+            return;
+        }
+
+        int slot = fieldList.getSelectedRow();
+
+        // occurs if valueChanged picked up a clearSelection event from
+        // the list
+        if (slot == -1) {
+            return;
+        }
+
+        listElementSelected(slot);
+    }
+
+    // ----- end of ListSelectionListener interface -----
+
+    /**
+     * Store the object currently selected in the list.
+     * 
+     * @param object
+     *            The new CurrentObj value
+     * @param name
+     *            The name of the selected field
+     * @param type
+     *            The type of the selected field
+     */
+    protected void setCurrentObj(DebuggerObject object, String name, String type)
+    {
+        selectedField = object;
+        selectedFieldName = name;
+        selectedFieldType = type;
+    }
+
+    /**
+     * Enable or disable the Inspect and Get buttons.
+     * 
+     * @param inspect
+     *            The new ButtonsEnabled value
+     * @param get
+     *            The new ButtonsEnabled value
+     */
+    protected void setButtonsEnabled(boolean inspect, boolean get)
+    {
+        inspectButton.setEnabled(inspect);
+        getButton.setEnabled(get && isGetEnabled());
+    }
+
+    /**
+     * The "Inspect" button was pressed. Inspect the selected object.
+     */
+    protected void doInspect()
+    {
+        if (selectedField != null) {
+            boolean isPublic = getButton.isEnabled();
+            
+            InvokerRecord newIr = new ObjectInspectInvokerRecord(selectedFieldName, ir);
+            inspectorManager.getInspectorInstance(selectedField, selectedFieldName, pkg, isPublic ? newIr : null, this);
+        }
+    }
+
+    /**
+     * The "Get" button was pressed. Get the selected object on the object
+     * bench.
+     */
+    protected void doGet()
+    {
+        if (selectedField != null) {
+            GetInvokerRecord getIr = new GetInvokerRecord(selectedFieldType, selectedFieldName, ir);
+            PackageEditor pkgEd = pkg.getEditor();
+            pkgEd.recordInteraction(getIr);
+            pkgEd.raisePutOnBenchEvent(this, selectedField, selectedField.getGenType(), getIr);
+        }
+    }
+
+    /**
+     * Close this inspector. The caller should remove it from the list of open
+     * inspectors.
+     * 
+     * @param handleAssertions   Whether assertions should be attached to the
+     *                           invoker record. If true, the user may be prompted
+     *                           to fill in assertion data. 
+     */
+    public void doClose(boolean handleAssertions)
+    {
+        boolean closeOk = true;
+
+        if (handleAssertions) {
+            // handleAssertions may veto the close
+            closeOk = handleAssertions();
+        }
+
+        if (closeOk) {
+            setVisible(false);
+            remove();
+            dispose();
+        }
+    }
+
+    protected boolean handleAssertions()
+    {
+        if (assertPanel != null && assertPanel.isAssertEnabled()) {
+            
+            if (! assertPanel.isAssertComplete()) {
+                int choice = DialogManager.askQuestion(this, "empty-assertion-text");
+                
+                if (choice == 0) {
+                    return false;
+                }
+            }
+            
+            ir.addAssertion(assertPanel.getAssertStatement());
+        }
+        return true;
+    }
+
+    protected JButton createCloseButton()
+    {
+        JButton button = new JButton(close);
+        button.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                doClose(true);
+            }
+        });
+        return button;
+    }
+
+    /**
+     * Creates a panel with an inspect button and a get button
+     * 
+     * @return A panel with two buttons
+     */
+    protected JPanel createInspectAndGetButtons()
+    {
+        // Create panel with "inspect" and "get" buttons
+        JPanel buttonPanel = new JPanel();
+        buttonPanel.setOpaque(false);
+        buttonPanel.setDoubleBuffered(false);
+        buttonPanel.setLayout(new GridLayout(0, 1));
+        inspectButton = new JButton(inspectLabel);
+        inspectButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                doInspect();
+            }
+        });
+        inspectButton.setEnabled(false);
+        buttonPanel.add(inspectButton);
+
+        getButton = new JButton(getLabel);
+        getButton.setEnabled(false);
+        getButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                doGet();
+            }
+        });
+        buttonPanel.add(getButton);
+
+        JPanel buttonFramePanel = new JPanel();
+        buttonFramePanel.setOpaque(false);
+        buttonFramePanel.setDoubleBuffered(false);
+        buttonFramePanel.setLayout(new BorderLayout(0, 0));
+        buttonFramePanel.add(buttonPanel, BorderLayout.NORTH);
+        return buttonFramePanel;
+    }
+
+    /**
+     * Creates a ScrollPane for the fieldList
+     */
+    protected JScrollPane createFieldListScrollPane()
+    {
+        fieldListScrollPane = new JScrollPane(fieldList);
+        fieldListScrollPane.setBorder(BorderFactory.createLineBorder(fieldListBackgroundColor, 10));
+        fieldListScrollPane.getViewport().setBackground(fieldListBackgroundColor);
+        return fieldListScrollPane;
+    }
+    
+    // Allow movement of the window by dragging
+    // Adapted from: http://www.stupidjavatricks.com/?p=4
+    // (with improvements).
+    protected void installListenersForMoveDrag()
+    {
+        addMouseListener( new MouseAdapter()
+        {
+            @Override
+            public void mousePressed( MouseEvent e )
+            {
+                initialClick = e.getPoint();
+            }
+
+            @Override
+            public void mouseReleased(MouseEvent e)
+            {
+                initialClick = null;
+            }
+        });
+     
+        // Move window when mouse is dragged
+        addMouseMotionListener( new MouseMotionAdapter()
+        {
+            @Override
+            public void mouseDragged( MouseEvent e )
+            {
+                if (initialClick == null) {
+                    initialClick = e.getPoint();
+                    return;
+                }
+
+                // Determine how much the mouse moved since the initial click
+                int newXPos = e.getXOnScreen() - initialClick.x;
+                int newYPos = e.getYOnScreen() - initialClick.y;
+                
+                // Move window to this position
+                setLocation(newXPos, newYPos);
+            }
+        });
+    }
+    
+   /**
+    * Taken from the source code at: http://java.sun.com/developer/technicalArticles/GUI/translucent_shaped_windows/
+    *
+    * @author Anthony Petrov
+    */
+   private static class AWTUtilitiesWrapper {
+
+       private static Class<?> awtUtilitiesClass;
+       private static Class<?> translucencyClass;
+       // private static Method mIsTranslucencySupported,  mSetWindowShape,  mSetWindowOpacity;
+       private static Method mIsTranslucencyCapable, mSetWindowOpaque;
+       //public static Object PERPIXEL_TRANSPARENT,  TRANSLUCENT,  PERPIXEL_TRANSLUCENT;
+
+       static void init() {
+           try {
+               awtUtilitiesClass = Class.forName("com.sun.awt.AWTUtilities");
+               translucencyClass = Class.forName("com.sun.awt.AWTUtilities$Translucency");
+               if (translucencyClass.isEnum()) {
+                   Object[] kinds = translucencyClass.getEnumConstants();
+                   if (kinds != null) {
+                       //PERPIXEL_TRANSPARENT = kinds[0];
+                       //TRANSLUCENT = kinds[1];
+                       //PERPIXEL_TRANSLUCENT = kinds[2];
+                   }
+               }
+               // mIsTranslucencySupported = awtUtilitiesClass.getMethod("isTranslucencySupported", translucencyClass);
+               mIsTranslucencyCapable = awtUtilitiesClass.getMethod("isTranslucencyCapable", GraphicsConfiguration.class);
+               // mSetWindowShape = awtUtilitiesClass.getMethod("setWindowShape", Window.class, Shape.class);
+               // mSetWindowOpacity = awtUtilitiesClass.getMethod("setWindowOpacity", Window.class, float.class);
+               mSetWindowOpaque = awtUtilitiesClass.getMethod("setWindowOpaque", Window.class, boolean.class);
+           } catch (ClassNotFoundException cnfe) {
+               Debug.log("Sun AWT translucency classes not available (ClassNotFoundException).");
+           } catch (Exception ex) {
+               Debug.reportError("Couldn't support AWTUtilities", ex);
+           }
+       }
+
+       static {
+           init();
+       }
+       
+       private static boolean isSupported(Method method, Object kind) {
+           if (awtUtilitiesClass == null ||
+                   method == null)
+           {
+               return false;
+           }
+           try {
+               Object ret = method.invoke(null, kind);
+               if (ret instanceof Boolean) {
+                   return ((Boolean)ret).booleanValue();
+               }
+           } catch (Exception ex) {
+               Debug.reportError("Couldn't support AWTUtilities", ex);
+           }
+           return false;
+       }
+       
+       /*
+       public static boolean isTranslucencySupported(Object kind) {
+           if (translucencyClass == null) {
+               return false;
+           }
+           return isSupported(mIsTranslucencySupported, kind);
+       }
+       */
+       
+       public static boolean isTranslucencyCapable(GraphicsConfiguration gc) {
+           return isSupported(mIsTranslucencyCapable, gc);
+       }
+       
+       private static void set(Method method, Window window, Object value) {
+           if (awtUtilitiesClass == null ||
+                   method == null || !isTranslucencyCapable(window.getGraphicsConfiguration()))
+           {
+               return;
+           }
+           try {
+               method.invoke(null, window, value);
+           } catch (Exception ex) {
+               Debug.reportError("Couldn't support AWTUtilities: ", ex);
+           }
+       }
+       
+       /*
+       public static void setWindowShape(Window window, Shape shape) {
+           set(mSetWindowShape, window, shape);
+       }
+
+       public static void setWindowOpacity(Window window, float opacity) {
+           set(mSetWindowOpacity, window, Float.valueOf(opacity));
+       }
+       */
+       
+       public static void setWindowOpaque(Window window, boolean opaque) {
+           set(mSetWindowOpaque, window, Boolean.valueOf(opaque));
+       }
+       
+       public static GraphicsConfiguration getBestGC() {
+           GraphicsConfiguration translucencyCapableGC = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
+           if (!AWTUtilitiesWrapper.isTranslucencyCapable(translucencyCapableGC)) {
+               translucencyCapableGC = null;
+
+               GraphicsEnvironment env =
+                       GraphicsEnvironment.getLocalGraphicsEnvironment();
+               GraphicsDevice[] devices = env.getScreenDevices();
+
+               for (int i = 0; i < devices.length && translucencyCapableGC == null; i++) {
+                   GraphicsConfiguration[] configs = devices[i].getConfigurations();
+                   for (int j = 0; j < configs.length && translucencyCapableGC == null; j++) {
+                       if (AWTUtilitiesWrapper.isTranslucencyCapable(configs[j])) {
+                           translucencyCapableGC = configs[j];
+                       }
+                   }
+               }
+           }
+           if (translucencyCapableGC == null) {
+               Debug.message("No translucency capable GC");
+           }
+           return translucencyCapableGC;
+       }
+   }
+   
+   protected void setWindowOpaque(boolean b)
+   {
+       AWTUtilitiesWrapper.setWindowOpaque(this, b);
+   }
+   
+   public int getUniqueId()
+   {
+       return uniqueId;
+   }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/InspectorManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/InspectorManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3120542a506245a8e9f6727c1dd48bb971bc7d1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/InspectorManager.java
@@ -0,0 +1,119 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.inspector;
+
+import javax.swing.JFrame;
+
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerObject;
+import bluej.debugmgr.ExpressionInformation;
+import bluej.pkgmgr.Package;
+import bluej.testmgr.record.InvokerRecord;
+
+
+/**
+ * 
+ * Interface for a manager that creates and holds references to inspectors
+ * 
+ * @author Poul Henriksen
+ */
+public interface InspectorManager
+{
+    /**
+     * 
+     * Remove and dispose the inspector.
+     * 
+     * @param obj Object that the inspector inspects
+     */
+    public void removeInspector(DebuggerObject obj);
+    
+    /**
+     * 
+     * Remove and dispose the inspector.
+     * 
+     * @param cls Class that the inspector inspects
+     */
+    public void removeInspector(DebuggerClass cls);
+    
+    /**
+     * Return an ObjectInspector for an object. The inspector is visible.
+     *
+     * @param obj
+     *            The object displayed by this viewer
+     * @param name
+     *            The name of this object or "null" if the name is unobtainable
+     * @param pkg
+     *            The package all this belongs to
+     * @param ir
+     *            the InvokerRecord explaining how we got this result/object if
+     *            null, the "get" button is permanently disabled
+     * @param info
+     *            The information about the the expression that gave this result
+     * @param parent
+     *            The parent frame of this frame
+     * @return The Viewer value
+     */
+    public ObjectInspector getInspectorInstance(DebuggerObject obj,
+            String name, Package pkg, InvokerRecord ir, JFrame parent);
+    
+    /**
+     * Return a ClassInspector for a class. The inspector is visible.
+     *
+     * @param clss
+     *            The class displayed by this viewer
+     * @param name
+     *            The name of this object or "null" if it is not on the object
+     *            bench
+     * @param pkg
+     *            The package all this belongs to
+     * @param getEnabled
+     *            if false, the "get" button is permanently disabled
+     * @param parent
+     *            The parent frame of this frame
+     * @return The Viewer value
+     */
+    public ClassInspector getClassInspectorInstance(DebuggerClass clss,
+            Package pkg, JFrame parent);
+
+    /**
+     * Return an ObjectInspector for an object. The inspector is visible.
+     * 
+     * @param obj The object displayed by this viewer
+     * @param name The name of this object or "null" if the name is unobtainable
+     * @param pkg The package all this belongs to
+     * @param ir the InvokerRecord explaining how we got this result/object if
+     *            null, the "get" button is permanently disabled
+     * @param info The information about the the expression that gave this
+     *            result
+     * @param parent The parent frame of this frame
+     * @return The Viewer value
+     */
+    public ResultInspector getResultInspectorInstance(DebuggerObject obj,
+        String name, Package pkg, InvokerRecord ir, ExpressionInformation info,
+        JFrame parent);
+    
+    /**
+     * Whether we are in testing mode. If true, the inspectors should show testing stuff.
+     * 
+     */
+    public boolean inTestMode();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/ObjectInspector.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/ObjectInspector.java
new file mode 100644
index 0000000000000000000000000000000000000000..8d7cd00539583f9d5b57a5813d77b46e76c70cf9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/ObjectInspector.java
@@ -0,0 +1,592 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.inspector;
+
+import java.awt.AlphaComposite;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Insets;
+import java.awt.RenderingHints;
+import java.awt.Transparency;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.Ellipse2D;
+import java.awt.image.BufferedImage;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.border.EmptyBorder;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PackageEditor;
+import bluej.prefmgr.PrefMgr;
+import bluej.testmgr.record.ArrayElementGetRecord;
+import bluej.testmgr.record.ArrayElementInspectorRecord;
+import bluej.testmgr.record.GetInvokerRecord;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.testmgr.record.ObjectInspectInvokerRecord;
+import bluej.utility.DialogManager;
+
+/**
+ * A window that displays the fields in an object or a method return value.
+ * 
+ * @author Michael Kolling
+ * @author Poul Henriksen
+ * @author Bruce Quig
+ */
+public class ObjectInspector extends Inspector
+{
+    // === static variables ===
+
+    protected final static String inspectTitle = Config.getString("debugger.inspector.object.title");
+    protected final static String noFieldsMsg = Config.getString("debugger.inspector.object.noFields");
+
+    // === instance variables ===
+    
+    /** A reference to the object being inspected */
+    protected DebuggerObject obj;
+
+    /**
+     * Name of the object, as it appears on the object bench, or null if the
+     * object being inspected is not on the object bench
+     */
+    protected String objName;
+
+    protected boolean queryArrayElementSelected = false;
+    private int selectedIndex;
+
+    /**
+     * array of Integers representing the array indexes from a large array that
+     * have been selected for viewing
+     */
+    //protected TreeSet arraySet = null;
+
+    /**
+     * list which is built when viewing an array that records the object slot
+     * corresponding to each array index
+     */
+    protected List<Integer> indexToSlotList = null; 
+
+    /**
+     *  Note: 'pkg' may be null if 'ir' is null.
+     * 
+     * @param obj
+     *            The object displayed by this viewer
+     * @param name
+     *            The name of this object or "null" if the name is unobtainable
+     * @param pkg
+     *            The package all this belongs to
+     * @param ir
+     *            the InvokerRecord explaining how we created this result/object
+     *            if null, the "get" button is permanently disabled
+     * @param parent
+     *            The parent frame of this frame
+     */
+    public ObjectInspector(DebuggerObject obj, InspectorManager inspectorManager, String name, Package pkg, InvokerRecord ir, final JFrame parent)
+    {
+        super(inspectorManager, pkg, ir, new Color(244, 158, 158));
+
+        this.obj = obj;
+        this.objName = name;
+
+        final ObjectInspector thisInspector = this;
+
+        makeFrame();
+        update();
+        updateLayout();
+        pack();
+        
+        if (parent instanceof Inspector) {
+            DialogManager.tileWindow(thisInspector, parent);
+        }
+        else {
+            DialogManager.centreWindow(thisInspector, parent);
+        }
+
+        if (Config.isMacOS() || Config.isWinOS()) {
+            // Window translucency doesn't seem to work on linux.
+            // We'll assume that it might not work on any OS other
+            // than those on which it's known to work: MacOS and Windows.
+            thisInspector.setWindowOpaque(false);
+        }
+        if (!Config.isMacOS()) {
+            // MacOS automatically makes tranparent windows draggable by their
+            // content - no need to do it ourselves.
+            thisInspector.installListenersForMoveDrag();
+        }
+    }
+
+    /**
+     * Build the GUI
+     */
+    protected void makeFrame()
+    {
+        setTitle(inspectTitle);
+        setUndecorated(true);
+        setLayout(new BorderLayout());
+        setBackground(new Color(232,230,218));
+
+        // Create the header
+
+        JComponent header = new JPanel();
+        header.setLayout(new BoxLayout(header, BoxLayout.Y_AXIS));
+        header.setOpaque(false);
+        header.setDoubleBuffered(false);
+        GenTypeClass objType = obj.getGenType();
+        String className = objType != null ? objType.toString(true) : "";
+
+        String fullTitle = null;
+        if(objName != null) {
+            fullTitle = objName + " : " + className;   
+        }
+        else {
+            fullTitle = " : " + className;
+        }
+        JLabel headerLabel = new JLabel(fullTitle, JLabel.CENTER);
+        Font font = headerLabel.getFont();
+        headerLabel.setFont(font.deriveFont(Font.BOLD));
+        headerLabel.setOpaque(false);
+        headerLabel.setAlignmentX(0.5f);
+        headerLabel.setForeground(Color.white);
+        header.add(headerLabel);
+        header.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        JSeparator sep = new JSeparator();
+        sep.setForeground(new Color(214, 92, 92));
+        sep.setBackground(new Color(0, 0, 0, 0));
+        header.add(sep);
+
+        // Create the main panel (field list, Get/Inspect buttons)
+
+        JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
+        mainPanel.setOpaque(false);
+        mainPanel.setDoubleBuffered(false);
+
+        if (!getListData().isEmpty()) {
+            JScrollPane scrollPane = createFieldListScrollPane();
+            mainPanel.add(scrollPane, BorderLayout.CENTER);
+        } else {
+            JLabel lab = new JLabel("  " + noFieldsMsg);
+            lab.setPreferredSize(new Dimension(200, 30));
+            lab.setFont(PrefMgr.getStandardFont().deriveFont(20.0f));
+            lab.setForeground(new Color(250, 160, 160));
+            mainPanel.add(lab);
+        }
+
+        JPanel inspectAndGetButtons = createInspectAndGetButtons();
+        mainPanel.add(inspectAndGetButtons, BorderLayout.EAST);
+
+        Insets insets = BlueJTheme.generalBorderWithStatusBar.getBorderInsets(mainPanel);
+        mainPanel.setBorder(new EmptyBorder(insets));
+
+        // create bottom button pane with "Close" button
+
+        JPanel bottomPanel = new JPanel();
+        bottomPanel.setOpaque(false);
+        bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS));
+        bottomPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 5));
+
+        JPanel buttonPanel;
+        buttonPanel = new JPanel(new BorderLayout());
+        buttonPanel.setOpaque(false);
+        JButton button = createCloseButton();
+        buttonPanel.add(button, BorderLayout.EAST);
+        JButton classButton = new JButton(showClassLabel);
+        classButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                showClass();
+            }
+        });
+        buttonPanel.add(classButton, BorderLayout.WEST);
+        buttonPanel.setDoubleBuffered(false);
+
+        bottomPanel.add(buttonPanel);
+        bottomPanel.setDoubleBuffered(false);
+
+        // add the components
+
+        JPanel contentPane = new JPanel() {
+
+            @Override
+            protected void paintComponent(Graphics g)
+            {               
+                Graphics2D g2d = (Graphics2D)g.create();
+                {
+                    GraphicsConfiguration gc = g2d.getDeviceConfiguration();
+                    BufferedImage img = gc.createCompatibleImage(getWidth(),
+                                    getHeight(),
+                                    Transparency.TRANSLUCENT);
+                    Graphics2D imgG = img.createGraphics();
+
+                    imgG.setComposite(AlphaComposite.Clear);
+                    imgG.fillRect(0, 0, getWidth(), getHeight());
+    
+                    imgG.setComposite(AlphaComposite.Src);
+                    imgG.setRenderingHint(
+                            RenderingHints.KEY_ANTIALIASING,
+                            RenderingHints.VALUE_ANTIALIAS_ON);
+                    imgG.setColor(Color.WHITE);
+                    imgG.fillRoundRect(0, 0, getWidth(), getHeight(), 30, 30);
+    
+                    imgG.setComposite(AlphaComposite.SrcAtop);
+                    imgG.setPaint(new GradientPaint(getWidth() / 2, getHeight() / 2, new Color(227, 71, 71)
+                                                   ,getWidth() / 2, getHeight(), new Color(205, 39, 39)));
+                    imgG.fillRect(0, 0, getWidth(), getHeight());
+                    
+                    imgG.setPaint(new GradientPaint(getWidth() / 2, 0, new Color(248, 120, 120)
+                                                   ,getWidth() / 2, getHeight() / 2, new Color(231, 96, 96)));
+                    imgG.fill(new Ellipse2D.Float(-2*getWidth(),-5*getHeight()/2,5*getWidth(),3*getHeight()));
+
+                    imgG.setColor(Color.BLACK);
+                    imgG.drawRoundRect(0, 0, getWidth()-1, getHeight()-1, 30, 30);                    
+                    
+                    imgG.dispose();
+                    g2d.drawImage(img, 0, 0, this);
+                }
+                g2d.dispose();
+            }
+        };
+        add(contentPane);
+
+        contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+        contentPane.setOpaque(false);
+        contentPane.setDoubleBuffered(false);
+        contentPane.setLayout(new BorderLayout());
+        contentPane.add(header, BorderLayout.NORTH);
+        contentPane.add(mainPanel, BorderLayout.CENTER);
+        contentPane.add(bottomPanel, BorderLayout.SOUTH);
+
+        getRootPane().setDefaultButton(button);
+    }
+
+    /**
+     * True if this inspector is used to display a method call result.
+     */
+    @Override
+    protected List<FieldInfo> getListData()
+    {
+        // if is an array (we potentially will compress the array if it is
+        // large)
+        if (obj.isArray()) {
+            return compressArrayList(obj);
+        }
+        else {
+            List<DebuggerField> fields = obj.getFields();
+            List<FieldInfo> fieldInfos = new ArrayList<FieldInfo>(fields.size());
+            for (DebuggerField field : fields) {
+                if (! Modifier.isStatic(field.getModifiers())) {
+                    String desc = Inspector.fieldToString(field);
+                    String value = field.getValueString();
+                    fieldInfos.add(new FieldInfo(desc, value));
+                }
+            }
+            return fieldInfos;
+        }
+    }
+
+    /**
+     * An element in the field list was selected.
+     */
+    protected void listElementSelected(int slot)
+    {
+        // add index to slot method for truncated arrays
+        if (obj.isArray()) {
+            slot = indexToSlot(slot);
+            if (slot >= 0) {
+                selectedIndex = slot;
+            }
+            // if selection is the first field containing array length
+            // we treat as special case and do nothing more
+            if (slot == ARRAY_LENGTH_SLOT_VALUE) {
+                setCurrentObj(null, null, null);
+                setButtonsEnabled(false, false);
+                return;
+            }
+
+            queryArrayElementSelected = (slot == (ARRAY_QUERY_SLOT_VALUE));
+            // for array compression..
+            if (queryArrayElementSelected) { // "..." in Array inspector
+                setCurrentObj(null, null, null); //  selected
+                if (! obj.getElementType().isPrimitive()) {
+                    setButtonsEnabled(true, false);
+                }
+                else {
+                    setButtonsEnabled(false, false);
+                }
+            }
+            else {
+                if (!obj.getElementType().isPrimitive()) {
+                    DebuggerObject elementObj = obj.getElementObject(slot);
+                    if (! elementObj.isNullObject()) {
+                        setCurrentObj(elementObj, "[" + slot + "]", obj.getElementType().toString());
+                        setButtonsEnabled(true, true);
+                        return;
+                    }
+                }
+                
+                // primitive or null
+                setCurrentObj(null, null, null);
+                setButtonsEnabled(false, false);
+            }
+            
+            return;
+        }
+
+        // Non-array
+        DebuggerField field = obj.getInstanceField(slot);
+        if (field.isReferenceType() && ! field.isNull()) {
+            setCurrentObj(field.getValueObject(null), field.getName(), field.getType().toString());
+
+            if (Modifier.isPublic(field.getModifiers())) {
+                setButtonsEnabled(true, true);
+            }
+            else {
+                setButtonsEnabled(true, false);
+            }
+        }
+        else {
+            setCurrentObj(null, null, null);
+            setButtonsEnabled(false, false);
+        }
+    }
+
+    /**
+     * Show the inspector for the class of an object.
+     */
+    protected void showClass()
+    {
+        inspectorManager.getClassInspectorInstance(obj.getClassRef(), pkg, this);
+    }
+
+    @Override
+    protected void doInspect()
+    {
+        if (queryArrayElementSelected) {
+            selectArrayElement();
+        }
+        else if (selectedField != null) {
+            boolean isPublic = getButton.isEnabled();
+            
+            if (! obj.isArray()) {
+                InvokerRecord newIr = new ObjectInspectInvokerRecord(selectedFieldName, ir);
+                inspectorManager.getInspectorInstance(selectedField, selectedFieldName, pkg, isPublic ? newIr : null, this);
+            }
+            else {
+                InvokerRecord newIr = new ArrayElementInspectorRecord(ir, selectedIndex);
+                inspectorManager.getInspectorInstance(selectedField, selectedFieldName, pkg, isPublic ? newIr : null, this);
+            }
+        }
+    }
+    
+    @Override
+    protected void doGet()
+    {
+        if (selectedField != null) {
+            InvokerRecord getIr;
+            if (! obj.isArray()) {
+                getIr = new GetInvokerRecord(selectedFieldType, selectedFieldName, ir);
+            }
+            else {
+                getIr = new ArrayElementGetRecord(selectedFieldType, selectedIndex, ir);
+            }
+                
+            PackageEditor pkgEd = pkg.getEditor();
+            pkgEd.recordInteraction(getIr);
+            pkgEd.raisePutOnBenchEvent(this, selectedField, selectedField.getGenType(), getIr);
+        }
+    }
+    
+    /**
+     * Remove this inspector.
+     */
+    protected void remove()
+    {
+        if(inspectorManager != null) {
+            inspectorManager.removeInspector(obj);
+        }
+    }
+
+    /**
+     * Shows a dialog to select array element for inspection
+     */
+    private void selectArrayElement()
+    {
+        String response = DialogManager.askString(this, "ask-index");
+
+        if (response != null) {
+            try {
+                int slot = Integer.parseInt(response);
+                // check if within bounds of array
+                if (slot >= 0 && slot < obj.getElementCount()) {
+                    // if its an object set as current object
+                    if (! obj.getElementType().isPrimitive() && ! obj.getElementObject(slot).isNullObject()) {
+                        boolean isPublic = getButton.isEnabled();
+                        InvokerRecord newIr = new ArrayElementInspectorRecord(ir, slot);
+                        setCurrentObj(obj.getElementObject(slot), "[" + slot + "]", obj.getElementType().toString());
+                        inspectorManager.getInspectorInstance(selectedField, selectedFieldName, pkg,
+                                isPublic ? newIr : null, this);
+                    }
+                    else {
+                        // it is not an object - a primitive, so lets
+                        // just display it in the array list display
+                        setButtonsEnabled(false, false);
+                        //arraySet.add(new Integer(slot));
+                        // TODO: this is currently broken. Primitive array elements re just
+                        //       not displayed right now. Would need to be added to display list.
+                        update();
+                    }
+                }
+                else { // not within array bounds
+                    DialogManager.showError(this, "out-of-bounds");
+                }
+            }
+            catch (NumberFormatException e) {
+                // input could not be parsed, eg. non integer value
+                setCurrentObj(null, null, null);
+                DialogManager.showError(this, "cannot-access-element");
+            }
+        }
+        else {
+            // set current object to null to avoid re-inspection of
+            // previously selected wildcard
+            setCurrentObj(null, null, null);
+        }
+    }
+
+    private final static int VISIBLE_ARRAY_START = 40; // show at least the
+                                                       // first 40 elements
+    private final static int VISIBLE_ARRAY_TAIL = 5; // and the last five
+                                                     // elements
+
+    private final static int ARRAY_QUERY_SLOT_VALUE = -2; // signal marker of
+                                                          // the [...] slot in
+                                                          // our
+    private final static int ARRAY_LENGTH_SLOT_VALUE = -1; // marker for having
+                                                           // selected the slot
+                                                           // containing array
+                                                           // length
+
+    /**
+     * Compress a potentially large array into a more displayable shortened
+     * form.
+     * 
+     * Compresses an array field name list to a maximum of VISIBLE_ARRAY_START
+     * which are guaranteed to be displayed at the start, then some [..]
+     * expansion slots, followed by VISIBLE_ARRAY_TAIL elements from the end of
+     * the array. When a selected element is chosen indexToSlot allows the
+     * selection to be converted to the original array element position.
+     * 
+     * @param fullArrayFieldList
+     *            the full field list for an array
+     * @return the compressed array
+     */
+    private List<FieldInfo> compressArrayList(DebuggerObject arrayObject)
+    {
+        // mimic the public length field that arrays possess
+        // according to the java spec...
+        indexToSlotList = new LinkedList<Integer>();
+        indexToSlotList.add(0, new Integer(ARRAY_LENGTH_SLOT_VALUE));
+
+        // the +1 here is due to the fact that if we do not have at least one
+        // more than
+        // the sum of start elements and tail elements, then there is no point
+        // in displaying
+        // the ... elements because there would be no elements for them to
+        // reveal
+        if (arrayObject.getElementCount() > (VISIBLE_ARRAY_START + VISIBLE_ARRAY_TAIL + 2)) {
+
+            // the destination list
+            List<FieldInfo> newArray = new ArrayList<FieldInfo>(2 + VISIBLE_ARRAY_START + VISIBLE_ARRAY_TAIL);
+            newArray.add(0, new FieldInfo("int length", "" + arrayObject.getElementCount()));
+            for (int i = 0; i <= VISIBLE_ARRAY_START; i++) {
+                // first 40 elements are displayed as per normal
+                newArray.add(new FieldInfo("[" + i + "]", arrayObject.getElementValueString(i)));
+                indexToSlotList.add(i);
+            }
+
+            // now the first of our expansion slots
+            newArray.add(new FieldInfo("[...]", ""));
+            indexToSlotList.add(new Integer(ARRAY_QUERY_SLOT_VALUE));
+
+            for (int i = VISIBLE_ARRAY_TAIL; i > 0; i--) {
+                // last 5 elements are displayed
+                int elNum = arrayObject.getElementCount() - i;
+                newArray.add(new FieldInfo("[" + elNum + "]", arrayObject.getElementValueString(elNum)));
+                indexToSlotList.add(arrayObject.getElementCount() - i);
+            }
+            return newArray;
+        }
+        else {
+            List<FieldInfo> fullArrayFieldList = new ArrayList<FieldInfo>(arrayObject.getElementCount() + 1);
+            fullArrayFieldList.add(0, new FieldInfo("int length", "" + arrayObject.getElementCount()));
+            
+            for (int i = 0; i < arrayObject.getElementCount(); i++) {
+                fullArrayFieldList.add(new FieldInfo("[" + i + "]", arrayObject.getElementValueString(i)));
+                indexToSlotList.add(i);
+            }
+            return fullArrayFieldList;
+        }
+    }
+
+    /**
+     * Converts list index position to that of array element position in arrays.
+     * Uses the List built in compressArrayList to do the mapping.
+     * 
+     * @param listIndexPosition
+     *            the position selected in the list
+     * @return the translated index of field array element
+     */
+    private int indexToSlot(int listIndexPosition)
+    {
+        Integer slot = indexToSlotList.get(listIndexPosition);
+
+        return slot.intValue();
+    }
+
+    protected int getPreferredRows()
+    {
+        return 8;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/ResultInspector.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/ResultInspector.java
new file mode 100644
index 0000000000000000000000000000000000000000..65812ad88da3ab98891df33c52dcd4118d2b471f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/inspector/ResultInspector.java
@@ -0,0 +1,413 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.inspector;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.ActionEvent;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.border.Border;
+import javax.swing.border.EmptyBorder;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugmgr.ExpressionInformation;
+import bluej.pkgmgr.Package;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.Debug;
+import bluej.utility.JavaUtils;
+import bluej.utility.MultiLineLabel;
+import bluej.views.Comment;
+import bluej.views.LabelPrintWriter;
+import bluej.views.MethodView;
+
+/**
+ * A window that displays a method return value.
+ * 
+ * @author Poul Henriksen
+ */
+public class ResultInspector extends Inspector
+{
+
+    // === static variables ===
+
+    protected final static String resultTitle = Config.getString("debugger.inspector.result.title");
+    protected final static String returnedString = Config.getString("debugger.inspector.result.returned");
+
+    // === instance variables ===
+
+    protected DebuggerObject obj;
+    protected String objName; // name on the object bench
+
+    private ExpressionInformation expressionInformation;
+    private JavaType resultType; // static result type
+
+    
+    /**
+     * Note: 'pkg' may be null if 'ir' is null.
+     * 
+     * @param obj
+     *            The object displayed by this viewer
+     * @param name
+     *            The name of this object or "null" if the name is unobtainable
+     * @param pkg
+     *            The package all this belongs to
+     * @param ir
+     *            the InvokerRecord explaining how we created this result/object
+     *            if null, the "get" button is permanently disabled
+     * @param info
+     *            The expression used to create the object (ie. the method call
+     *            information)
+     * @param parent
+     *            The parent frame of this frame
+     */
+    public ResultInspector(DebuggerObject obj, InspectorManager inspectorManager, String name,
+            Package pkg, InvokerRecord ir, ExpressionInformation info)
+    {
+        super(inspectorManager, pkg, ir, new Color(226, 224, 220));
+
+        expressionInformation = info;
+        this.obj = obj;
+        this.objName = name;
+
+        calcResultType();
+
+        makeFrame();
+        update();
+        updateLayout();
+    }
+
+    /**
+     * Determine the expected static type of the result.
+     */
+    private void calcResultType()
+    {
+        GenTypeClass instanceType = expressionInformation.getInstanceType();
+        // We know it's a MethodView, as we don't inspect the result of a
+        // constructor!
+        MethodView methodView = (MethodView) expressionInformation.getMethodView();
+        Method m = methodView.getMethod();
+
+        // Find the expected return type
+        JavaType methodReturnType = methodView.getGenericReturnType();
+
+        // TODO: infer type of generic parameters based on the actual
+        // arguments passed to the method.
+        // For now, use the base type of the any generic type parameters
+        if (methodReturnType instanceof GenTypeParameter) {
+            
+            // The return type may contain type parameters. First, get the
+            // type parameters of the object:
+            Map<String,GenTypeParameter> tparmap;
+            if (instanceType != null)
+                tparmap = instanceType.mapToSuper(m.getDeclaringClass().getName()).getMap();
+            else
+                tparmap = new HashMap<String,GenTypeParameter>();
+            
+            // It's possible the mapping result is a raw type.
+            if (tparmap == null) {
+                resultType = JavaUtils.getJavaUtils().getRawReturnType(m);
+                return;
+            }
+            
+            // Then put in the type parameters from the method itself,
+            // if there are any (ie. if the method is a generic method).
+            // Tpars from the method override those from the instance.
+            List<GenTypeDeclTpar> tpars = JavaUtils.getJavaUtils().getTypeParams(m);
+            if (tparmap != null) {
+                tparmap.putAll(JavaUtils.TParamsToMap(tpars));
+            }
+            
+            methodReturnType = methodReturnType.mapTparsToTypes(tparmap).getUpperBound();
+        }
+
+        resultType = methodReturnType;
+    }
+
+    /**
+     * Returns a single string representing the return value.
+     */
+    @Override
+    protected List<FieldInfo> getListData()
+    {
+        String fieldString;
+        DebuggerField resultField = obj.getField(0);
+        if (!resultType.isPrimitive()) {
+            DebuggerObject resultObject = resultField.getValueObject(resultType);
+            if (!resultObject.isNullObject()) {
+                fieldString = resultObject.getGenType().toString(true);
+            }
+            else {
+                fieldString = resultType.toString(true);
+            }
+        }
+        else {
+            fieldString = resultField.getType().toString(true);
+        }
+        
+        List<FieldInfo> rlist = new ArrayList<FieldInfo>(1);
+        rlist.add(new FieldInfo(fieldString, resultField.getValueString()));
+        return rlist;
+    }
+
+    /**
+     * Build the GUI
+     * 
+     * @param showAssert
+     *            Indicates if assertions should be shown.
+     */
+    protected void makeFrame()
+    {
+        setTitle(resultTitle);
+
+        // Create the header
+
+        JComponent header = new JPanel();
+        header.setOpaque(false);
+        header.setLayout(new BoxLayout(header, BoxLayout.Y_AXIS));
+
+        Comment comment = expressionInformation.getComment();
+        LabelPrintWriter commentLabelPrintWriter = new LabelPrintWriter();
+        comment.print(commentLabelPrintWriter);
+        MultiLineLabel commentLabel = commentLabelPrintWriter.getLabel();
+        commentLabel.setOpaque(false);
+        header.add(commentLabel);
+        JLabel sig = new JLabel(expressionInformation.getSignature());
+        sig.setForeground(Color.BLACK);
+
+        header.add(sig);
+        header.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        JSeparator sep = new JSeparator();
+        sep.setForeground(new Color(191,190,187));
+        sep.setBackground(new Color(0,0,0,0));
+        header.add(sep);
+
+        // Create the main part that shows the expression and the result
+
+        JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
+        mainPanel.setOpaque(false);
+
+        Box result = Box.createVerticalBox();
+        result.setOpaque(false);
+
+        final JLabel expression = new JLabel(expressionInformation.getExpression(), JLabel.LEFT);
+        expression.setAlignmentX(JComponent.LEFT_ALIGNMENT);
+        JPopupMenu copyPopup = new JPopupMenu();
+        copyPopup.add(new AbstractAction(Config.getString("editor.copyLabel")) {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+                try {
+                    StringSelection ss = new StringSelection(expression.getText());
+                    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, ss);
+                }
+                catch (IllegalStateException ise) {
+                    Debug.log("Copy: clipboard unavailable.");
+                }
+            }
+        });
+        expression.setComponentPopupMenu(copyPopup);
+
+        result.add(expression);
+        result.add(Box.createVerticalStrut(5));
+
+        JLabel returnedLabel = new JLabel("  " + returnedString, JLabel.LEADING);
+        returnedLabel.setAlignmentX(JComponent.LEFT_ALIGNMENT);
+        result.add(returnedLabel);
+        result.add(Box.createVerticalStrut(5));
+
+        JScrollPane scrollPane = createFieldListScrollPane();
+        scrollPane.setAlignmentX(JComponent.LEFT_ALIGNMENT);
+        scrollPane.setBorder(BorderFactory.createEmptyBorder());
+        result.add(scrollPane);
+        result.add(Box.createVerticalStrut(5));
+
+        Box resultPanel = new Box(BoxLayout.Y_AXIS) {
+            protected void paintComponent(Graphics g)
+            {
+                super.paintComponent(g);
+                
+                Graphics2D g2d = (Graphics2D)g;
+                int width = getWidth();
+                int height = getHeight();
+                
+                g2d.setPaint(new GradientPaint(width/4, 0, new Color(236,235,234),
+                                               width*3/4, height, new Color(220,218,214)));
+                g2d.fillRect(0, 0, width, height);
+            }
+        };
+        
+        result.setAlignmentX(CENTER_ALIGNMENT);
+        result.setAlignmentY(TOP_ALIGNMENT);
+        resultPanel.add(result);
+        
+        Border lineBorder = BorderFactory.createLineBorder(new Color(101, 101, 101), 1);
+        Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
+        Border resultPanelBorder = BorderFactory.createCompoundBorder(lineBorder, emptyBorder);
+        
+        resultPanel.setBorder(resultPanelBorder);
+        mainPanel.add(resultPanel, BorderLayout.CENTER);
+
+        JPanel inspectAndGetButtons = createInspectAndGetButtons();
+        mainPanel.add(inspectAndGetButtons, BorderLayout.EAST);
+
+        Insets insets = BlueJTheme.generalBorderWithStatusBar.getBorderInsets(mainPanel);
+        mainPanel.setBorder(new EmptyBorder(insets));
+
+        // create bottom button pane with "Close" button
+
+        JPanel bottomPanel = new JPanel();
+        bottomPanel.setOpaque(false);
+        bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS));
+        bottomPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 5));
+
+        if (inspectorManager != null && inspectorManager.inTestMode()) {
+            assertPanel = new AssertPanel();
+            {
+                assertPanel.setAlignmentX(LEFT_ALIGNMENT);
+                assertPanel.setResultType(resultType);
+                bottomPanel.add(assertPanel);
+            }
+        }
+        
+        JPanel buttonPanel;
+        buttonPanel = new JPanel(new BorderLayout());
+        buttonPanel.setOpaque(false);
+        JButton button = createCloseButton();
+        buttonPanel.add(button, BorderLayout.EAST);
+
+        bottomPanel.add(buttonPanel);
+        
+        // add the components
+        JPanel contentPane = new JPanel() {
+            protected void paintComponent(Graphics g)
+            {
+                super.paintComponent(g);
+                
+                Graphics2D g2d = (Graphics2D)g;
+                int width = getWidth();
+                int height = getHeight();
+                
+                g2d.setPaint(new GradientPaint(width/4, 0, new Color(230,229,228),
+                                               width*3/4, height, new Color(191,186,178)));
+                g2d.fillRect(0, 0, width, height);
+            }
+        };
+        setContentPane(contentPane);
+        contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+        contentPane.setLayout(new BorderLayout());
+        contentPane.add(header, BorderLayout.NORTH);
+        contentPane.add(mainPanel, BorderLayout.CENTER);
+        contentPane.add(bottomPanel, BorderLayout.SOUTH);
+
+        getRootPane().setDefaultButton(button);
+    }
+
+    /**
+     * An element in the field list was selected.
+     */
+    protected void listElementSelected(int slot)
+    {
+        DebuggerField field = obj.getInstanceField(0);
+        if (field.isReferenceType() && ! field.isNull()) {
+            // Don't use the name, since it is meaningless anyway (it is always "result")
+            setCurrentObj(field.getValueObject(resultType), null, resultType.toString(false));
+            setButtonsEnabled(true, true);
+        }
+        else {
+            setCurrentObj(null, null, null);
+            setButtonsEnabled(false, false);
+        }
+    }
+
+    @Override
+    protected void doInspect()
+    {
+        if (selectedField != null) {
+            boolean isPublic = getButton.isEnabled();
+            inspectorManager.getInspectorInstance(selectedField, selectedFieldName, pkg, isPublic ? ir : null, this);
+        }
+    }
+    
+    /**
+     * Remove this inspector.
+     */
+    protected void remove()
+    {
+        if(inspectorManager != null) {
+            inspectorManager.removeInspector(obj);
+        }
+    }
+
+    /**
+     * return a String with the result.
+     * 
+     * @return The Result value
+     */
+    public String getResult()
+    {
+        DebuggerField resultField = obj.getField(0);
+        
+        String result = resultField.getType() + " " + resultField.getName() + " = " + resultField.getValueString();
+        return result;
+    }
+
+    protected int getPreferredRows()
+    {
+        return 2;
+    }
+    
+    protected void doGet()
+    {
+        if (selectedField != null) {
+            pkg.getEditor().raisePutOnBenchEvent(this, selectedField, resultType.asClass(), ir);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ArrayWrapper.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ArrayWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..432072f2cf0a2dd6350b4b395e9f33d8a095679e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ArrayWrapper.java
@@ -0,0 +1,112 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.objectbench;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import bluej.debugger.*;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.prefmgr.PrefMgr;
+
+/**
+ * A wrapper around array objects.
+ * 
+ * The array wrapper is represented by a few red ovals that are visible on the
+ * object bench.
+ * 
+ * @author Andrew Patterson
+ * @author Bruce Quig
+ * @version $Id: ArrayWrapper.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class ArrayWrapper extends ObjectWrapper
+{
+    public static int WORD_GAP = 8;
+    public static int SHADOW_SIZE = 3;
+    public static int ARRAY_GAP = 3;
+    
+    
+
+    public ArrayWrapper(PkgMgrFrame pmf, ObjectBench ob, DebuggerObject obj, String instanceName)
+    {
+        super(pmf, ob, obj, obj.getGenType(), instanceName);
+    }
+
+    /**
+     * Creates the popup menu structure by parsing the object's class
+     * inheritance hierarchy.
+     * 
+     * @param className
+     *            class name of the object for which the menu is to be built
+     */
+    protected void createMenu(String className)
+    {
+        menu = new JPopupMenu(getName());
+        JMenuItem item;
+
+        //        item.addActionListener(
+        //            new ActionListener() {
+        //                public void actionPerformed(ActionEvent e) {
+        // /*invokeMethod(e.getSource());*/ }
+        //           });
+
+        // add inspect and remove options
+        menu.add(item = new JMenuItem(inspect));
+        item.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                inspectObject();
+            }
+        });
+        item.setFont(PrefMgr.getStandoutMenuFont());
+        item.setForeground(envOpColour);
+
+        menu.add(item = new JMenuItem(remove));
+        item.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                removeObject();
+            }
+        });
+        item.setFont(PrefMgr.getStandoutMenuFont());
+        item.setForeground(envOpColour);
+
+        add(menu);
+    }
+
+    /**
+     * draw a UML style object (array) instance
+     */
+    protected void drawUMLStyle(Graphics2D g)
+    {
+        g.setFont(PrefMgr.getStandardFont());
+
+        drawUMLObjectShape(g, HGAP + ARRAY_GAP*2, (VGAP / 2) + ARRAY_GAP*2, WIDTH - 10, HEIGHT - 10,  SHADOW_SIZE, 8);
+        drawUMLObjectShape(g, HGAP + ARRAY_GAP, (VGAP / 2) + ARRAY_GAP, WIDTH - 10, HEIGHT - 10,  SHADOW_SIZE, 8);
+        drawUMLObjectShape(g, HGAP, (VGAP / 2), WIDTH - 10, HEIGHT - 10,  SHADOW_SIZE, 8);
+
+        drawUMLObjectText(g, HGAP, (VGAP / 2), WIDTH - 10, 3, getName() + ":", displayClassName);
+
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/InvokeAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/InvokeAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..caac7a2514ce8bb6c9c5a50705e7508ff2aeaf4f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/InvokeAction.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.objectbench;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import bluej.views.MethodView;
+
+/**
+ * Simple action representing an interactive method invocation.
+ *  
+ * @author Davin McCall
+ * @version $Id: InvokeAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class InvokeAction extends AbstractAction
+{
+    MethodView methodView;
+    InvokeListener invokeListener;
+    
+    /**
+     * Constructor for an InvokeAction.
+     * 
+     * @param methodView   The method to be invoked
+     * @param il           The listener to be notified
+     * @param desc         The method description (as appearing on menu)
+     */
+    public InvokeAction(MethodView methodView, InvokeListener il, String desc)
+    {
+        super(desc);
+        this.methodView = methodView;
+        this.invokeListener = il;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        invokeListener.executeMethod(methodView);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/InvokeListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/InvokeListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..113ab95f5991dddaac780e261da7a30d5af524db
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/InvokeListener.java
@@ -0,0 +1,47 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.objectbench;
+
+import bluej.views.ConstructorView;
+import bluej.views.MethodView;
+
+/**
+ * Listener interface for some object to be notified when a method is to be
+ * interactively invoked.
+ * 
+ * @author Davin McCall
+ */
+public interface InvokeListener
+{
+    /**
+     * Execute a method. The listener must prompt for parameters, if appropriate,
+     * and then actually execute the method.
+     */
+    void executeMethod(MethodView mv);
+    
+    /**
+     * Execute a constructor. The listener must prompt for parameters, if appropriate,
+     * and the actually execute the constructor.
+     * @param cv
+     */
+    void callConstructor(ConstructorView cv);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBench.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBench.java
new file mode 100644
index 0000000000000000000000000000000000000000..eaa17b286285508306867386357492d8f7fe4929
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBench.java
@@ -0,0 +1,669 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.objectbench;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+import bluej.Config;
+import bluej.debugmgr.NamedValue;
+import bluej.debugmgr.ValueCollection;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.JavaNames;
+
+/**
+ * The class responsible for the panel that displays objects
+ * at the bottom of the package manager.
+ * 
+ * @author  Michael Cahill
+ * @author  Andrew Patterson
+ */
+public class ObjectBench extends JPanel implements ValueCollection,
+    FocusListener, KeyListener, MouseListener, ObjectBenchInterface
+{
+    private static final Color BACKGROUND_COLOR = Config.getOptionalItemColour("colour.objectbench.background");
+
+    private JScrollPane scroll;
+    private ObjectBenchPanel obp;
+    private List<ObjectWrapper> objects;
+    private ObjectWrapper selectedObject;
+    private PkgMgrFrame pkgMgrFrame;
+    
+    // All invocations done since our last reset.
+    private List<InvokerRecord> invokerRecords;
+   
+    /**
+     * Construct an object bench which is used to hold
+     * a bunch of object reference Components.
+     */
+    public ObjectBench(PkgMgrFrame pkgMgrFrame)
+    {
+        super();
+        objects = new ArrayList<ObjectWrapper>();
+        createComponent();
+        this.pkgMgrFrame = pkgMgrFrame;
+    }
+
+    /**
+     * Add an object (in the form of an ObjectWrapper) to this bench.
+     */
+    public void addObject(ObjectWrapper wrapper)
+    {
+        // check whether name is already taken
+
+        String newname = wrapper.getName();
+        int count = 1;
+        
+        if (JavaNames.isJavaKeyword(newname)) {
+            newname = "x" + newname;
+        }
+
+        while(hasObject(newname)) {
+            count++;
+            newname = wrapper.getName() + count;
+        }
+        wrapper.setName(newname);
+
+        // wrapper.addFocusListener(this); -- not needed
+        obp.add(wrapper);
+        objects.add(wrapper);
+        obp.revalidate();
+        obp.repaint();
+    }
+
+    
+    /**
+     * Return all the wrappers stored in this object bench in an array
+     */
+    public List<ObjectWrapper> getObjects()
+    {
+        return Collections.unmodifiableList(objects);
+    }
+
+    /**
+     * Return an iterator through all the objects on the bench (to meet
+     * the ValueCollection interface)
+     */
+    public Iterator<ObjectWrapper> getValueIterator()
+    {
+        return getObjects().iterator();
+    }
+    
+    /**
+     * Get the object with name 'name', or null, if it does not
+     * exist.
+     *
+     * @param name  The name to check for.
+     * @return  The named object wrapper, or null if not found.
+     */
+    public ObjectWrapper getObject(String name)
+    {
+        for(Iterator<ObjectWrapper> i = objects.iterator(); i.hasNext(); ) {
+            ObjectWrapper wrapper = i.next();
+            if(wrapper.getName().equals(name))
+                return wrapper;
+        }
+        return null;
+    }
+    
+    public NamedValue getNamedValue(String name)
+    {
+        return getObject(name);
+    }
+
+    /**
+     * Check whether the bench contains an object with name 'name'.
+     *
+     * @param name  The name to check for.
+     */
+    public boolean hasObject(String name)
+    {
+        return getObject(name) != null;
+    }
+
+    
+    /**
+     * Count of object bench copmponents that are object wrappers
+     * @return number of ObjectWrappers on the bench
+     */
+    public int getObjectCount()
+    {
+        return objects.size();
+    }
+
+    
+    /**
+     * Remove all objects from the object bench.
+     */
+    public void removeAllObjects(String scopeId)
+    {
+        setSelectedObject (null);
+
+        for(Iterator<ObjectWrapper> i = objects.iterator(); i.hasNext(); ) {
+            ObjectWrapper wrapper = i.next();
+            wrapper.prepareRemove();
+            wrapper.getPackage().getDebugger().removeObject(scopeId, wrapper.getName());
+            obp.remove(wrapper);
+        }
+        objects.clear();
+        resetRecordingInteractions();
+        obp.revalidate();
+        obp.repaint();
+    }
+
+    
+    /**
+     * Remove an object from the object bench. When this is done, the object
+     * is also removed from the scope of the package (so it is not accessible
+     * as a parameter anymore) and the bench is redrawn.
+     */
+    public void removeObject(ObjectWrapper wrapper, String scopeId)
+    {
+        if(wrapper == selectedObject)
+            setSelectedObject(null);
+     
+        wrapper.prepareRemove();
+        wrapper.getPackage().getDebugger().removeObject(scopeId, wrapper.getName());
+        obp.remove(wrapper);
+        objects.remove(wrapper);
+
+        obp.revalidate();
+        obp.repaint();
+    }
+
+    
+    /**
+     * Remove the selected object from the bench. If no object is selected,
+     * do nothing.
+     */
+    public void removeSelectedObject(String scopeId)
+    {
+        ObjectWrapper wrapper = getSelectedObject();
+        if(wrapper != null)
+            removeObject(wrapper, scopeId);
+    }
+    
+    
+    /**
+     * Sets what is the currently selected ObjectWrapper, null can be given to 
+     * signal that no wrapper is selected.
+     */
+    public void setSelectedObject(ObjectWrapper aWrapper)
+    {
+        if (selectedObject != null) {
+            selectedObject.setSelected(false);
+        }
+        selectedObject = aWrapper;
+        
+        if (selectedObject != null) {
+            selectedObject.setSelected(true);
+            selectedObject.requestFocusInWindow();
+        }
+    }
+
+    
+    /**
+     * Returns the currently selected object wrapper. 
+     * If no wrapper is selected null is returned.
+     */
+    public ObjectWrapper getSelectedObject()
+    {
+        return selectedObject;
+    }
+
+    
+    /**
+     * Add a listener for object events to this bench.
+     * @param l  The listener object.
+     */
+    public void addObjectBenchListener(ObjectBenchListener l)
+    {
+        listenerList.add(ObjectBenchListener.class, l);
+    }
+    
+
+    /**
+     * Remove a listener for object events to this bench.
+     * @param l  The listener object.
+     */
+    public void removeObjectBenchListener(ObjectBenchListener l)
+    {
+        listenerList.remove(ObjectBenchListener.class, l);
+    }
+    
+    
+    /**
+     * Fire an object event for the named object. This will
+     * notify all listeners that have registered interest for
+     * notification on this event type.
+     */
+    public void fireObjectEvent(ObjectWrapper wrapper)
+    {
+        setSelectedObject(wrapper);
+        // guaranteed to return a non-null array
+        Object[] listeners = listenerList.getListenerList();
+        // process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length-2; i>=0; i-=2) {   // I don't understand this - why step 2? (mik)
+            if (listeners[i] == ObjectBenchListener.class) {
+                ((ObjectBenchListener)listeners[i+1]).objectEvent(
+                        new ObjectBenchEvent(this,
+                                ObjectBenchEvent.OBJECT_SELECTED, wrapper));
+            }
+        }
+    }
+    
+    /**
+     * Do the usual enabling/disabling, while also removing the focus
+     * border when disabling.
+     */
+    public void setEnabled(boolean enable)
+    {
+        super.setEnabled(enable);
+        if(!enable) {
+            showFocusHiLight(false);
+        }
+    }
+    
+    /**
+     * Show or hide the focus highlight (an emphasised border around
+     * the bench).
+     */
+    public void showFocusHiLight(boolean hiLight)
+    {
+        if(hiLight)
+            scroll.setBorder(Config.focusBorder);
+        else
+            scroll.setBorder(Config.normalBorder);
+        repaint();
+    }
+
+    // --- FocusListener interface ---
+    
+    /**
+     * Note that the object bench got keyboard focus.
+     */
+    public void focusGained(FocusEvent e) 
+    {
+        showFocusHiLight(true);
+    }
+
+    
+    /**
+     * Note that the object bench lost keyboard focus.
+     */
+    public void focusLost(FocusEvent e) 
+    {
+        if (!e.isTemporary()) {
+            showFocusHiLight(false);
+        }
+    }
+
+    // --- end of FocusListener interface ---
+
+    // --- KeyListener interface ---
+
+    /**
+     * A key was pressed in the object bench.
+     * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
+     */
+    public void keyPressed(KeyEvent e) 
+    {
+        int selectedObjectIndex;
+        if(selectedObject == null)
+            selectedObjectIndex = -1;
+        else
+            selectedObjectIndex = objects.indexOf(selectedObject);
+        int key = e.getKeyCode();
+        
+        switch (key){
+            case KeyEvent.VK_LEFT:
+                if (selectedObjectIndex > 0) {
+                    selectedObjectIndex--;
+                }
+                else {
+                    selectedObjectIndex = 0;
+                }
+                setSelectedObjectByIndex(selectedObjectIndex);
+                break;
+
+            case KeyEvent.VK_RIGHT:
+                if (selectedObjectIndex < objects.size() - 1) {
+                    setSelectedObjectByIndex(selectedObjectIndex + 1);
+                }
+                break;
+
+            case KeyEvent.VK_UP:
+                selectedObjectIndex = selectedObjectIndex - obp.getNumberOfColumns();
+                if (selectedObjectIndex >= 0) {
+                    setSelectedObjectByIndex(selectedObjectIndex);
+                }
+                break;
+
+            case KeyEvent.VK_DOWN:
+                selectedObjectIndex = selectedObjectIndex + obp.getNumberOfColumns();
+                if (selectedObjectIndex < objects.size()) {
+                    setSelectedObjectByIndex(selectedObjectIndex);
+                }
+                break;
+
+            case KeyEvent.VK_ENTER:
+                showPopupMenu();
+                break;
+
+            case KeyEvent.VK_SPACE:
+                showPopupMenu();
+                break;
+
+            case KeyEvent.VK_ESCAPE:
+                setSelectedObject(null);
+                repaint();
+                break;
+        }
+    }
+
+    /**
+     * Sets the selected object from an index in the objects list.
+     * The index MUST be valid.
+     */
+    private void setSelectedObjectByIndex(int i)
+    {
+        setSelectedObject((ObjectWrapper) objects.get(i));
+        repaint();
+    }
+    
+    /**
+     * A key was released in the object bench.
+     * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
+     */
+    public void keyReleased(KeyEvent e) {}
+
+    
+    /**
+     * A key was typed in the object bench.
+     * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
+     */
+    public void keyTyped(KeyEvent e) {}
+    
+    // --- end of KeyListener interface ---
+
+    // --- MouseListener interface ---
+
+    /**
+     * The mouse was clicked in the object bench.
+     * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
+     */
+    public void mouseClicked(MouseEvent e)
+    {
+        setSelectedObject(null);
+    }
+    
+    /**
+     * The mouse entered the object bench.
+     * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
+     */
+    public void mouseEntered(MouseEvent e) {}
+    
+    /**
+     * The mouse left the object bench.
+     * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
+     */
+    public void mouseExited(MouseEvent e) {}
+
+    /**
+     * The mouse was pressed in the object bench.
+     * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
+     */
+    public void mousePressed(MouseEvent e) {
+        requestFocus();
+    }
+    
+    /**
+     * The mouse was released in the object bench.
+     * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
+     */
+    public void mouseReleased(MouseEvent e) {}
+    
+
+    // --- end of MouseListener interface ---
+
+
+    /**
+     * Post the object menu for the selected object.
+     */
+    private void showPopupMenu() 
+    {
+        if(selectedObject != null) {
+            selectedObject.showMenu();
+        }
+    }
+
+    // --- methods for interaction recording ---
+    
+    /**
+     * Reset the recording of invocations.
+     */
+    public void resetRecordingInteractions()
+    {
+        invokerRecords = new LinkedList<InvokerRecord>();
+    }
+
+    public void addInteraction(InvokerRecord ir)
+    {
+        if (invokerRecords == null)
+            resetRecordingInteractions();
+            
+        invokerRecords.add(ir);    
+    }
+    
+    /**
+     * Get the recorded interaction fixture declarations as Java code.
+     */
+    public String getFixtureDeclaration(String firstIndent)
+    {
+        StringBuffer sb = new StringBuffer();
+        Iterator<InvokerRecord> it = invokerRecords.iterator();
+        
+        while(it.hasNext()) {
+            InvokerRecord ir = it.next();
+            
+            if (ir.toFixtureDeclaration(firstIndent) != null) {
+                sb.append(ir.toFixtureDeclaration(firstIndent));
+            }
+        }                    
+
+        return sb.toString();
+    }
+    
+    /**
+     * Get the recorded interaction fixture setup as Java code.
+     */
+    public String getFixtureSetup(String secondIndent)
+    {
+        StringBuffer sb = new StringBuffer();
+        Iterator<InvokerRecord> it = invokerRecords.iterator();
+        
+        while(it.hasNext()) {
+            InvokerRecord ir = it.next();
+            
+            if (ir.toFixtureSetup(secondIndent) != null) {
+                sb.append(ir.toFixtureSetup(secondIndent));
+            }
+        }                    
+
+        return sb.toString();
+    }
+    
+    /**
+     * Get the recorded interactions as Java code.
+     */
+    public String getTestMethod(String secondIndent)
+    {
+        StringBuffer sb = new StringBuffer();
+        Iterator<InvokerRecord> it = invokerRecords.iterator();
+        
+        while(it.hasNext()) {
+            InvokerRecord ir = it.next();
+
+            String testMethod = ir.toTestMethod(pkgMgrFrame, secondIndent);
+            if (testMethod != null) {
+                sb.append(testMethod);
+            }
+        }                    
+
+        return sb.toString();
+    }
+
+    
+    /**
+     * Create the object bench as a good looking Swing component.
+     */
+    private void createComponent()
+    {
+        setLayout(new BorderLayout());
+
+        // a panel holding the actual object components
+        obp = new ObjectBenchPanel();
+        obp.setBackground(BACKGROUND_COLOR);
+        obp.setOpaque(false);
+        setOpaque(false);
+        
+        scroll = new JScrollPane(obp);
+        scroll.setBorder(Config.normalBorder);
+        scroll.setOpaque(false);
+        Dimension sz = obp.getMinimumSize();
+        Insets in = scroll.getInsets();
+        sz.setSize(sz.getWidth()+in.left+in.right, sz.getHeight()+in.top+in.bottom);
+        scroll.setMinimumSize(sz);
+        scroll.setPreferredSize(sz);
+        scroll.getVerticalScrollBar().setUnitIncrement(20);
+        
+        add(scroll, BorderLayout.CENTER);
+
+        // start with a clean slate recording invocations
+        resetRecordingInteractions();
+        //when empty, the objectbench is focusable
+        setFocusable(true);
+
+        addFocusListener(this);
+        addKeyListener(this);
+        obp.addMouseListener(this);
+    }
+
+    
+    // ------------- nested class ObjectBenchPanel --------------
+
+    /**
+     * This is the panel that lives inside the object bench's scrollpane
+     * and actually holds the object wrapper components.
+     */
+    private final class ObjectBenchPanel extends JPanel
+    {
+        public ObjectBenchPanel()
+        {
+            setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
+            setMinimumSize(new Dimension(ObjectWrapper.WIDTH, ObjectWrapper.HEIGHT));
+        }
+
+        /**
+         * Add the component (like any other JPanel) and then set our preferred size
+         * so that all components would be visible.
+         */
+        public Component add(Component comp)
+        {
+            super.add(comp);
+            return comp;
+        }
+
+        /**
+         * Return the preferred size of this component.
+         */
+        public Dimension getPreferredSize()
+        {
+            int rows = getNumberOfRows();
+            return new Dimension(ObjectWrapper.WIDTH, ObjectWrapper.HEIGHT * rows);                
+        }
+        
+        /**
+         * Return the current number of rows or objects on this bench.
+         */
+        public int getNumberOfRows()
+        {
+            int objects = getComponentCount();
+            if(objects == 0) {
+                return 1;
+            }
+            else {
+                int objectsPerRow = getWidth() / ObjectWrapper.WIDTH;
+                return (objects + objectsPerRow - 1) / objectsPerRow;
+            }            
+        }
+        
+        /**
+         * Return the current number of rows or objects on this bench.
+         */
+        public int getNumberOfColumns()
+        {
+            return getWidth() / ObjectWrapper.WIDTH;
+        }
+
+        protected void paintComponent(Graphics g)
+        {
+            super.paintComponent(g);
+            
+            if (g instanceof Graphics2D && false == pkgMgrFrame.isEmptyFrame()) {
+                Graphics2D g2d = (Graphics2D)g;
+                
+                int w = getWidth();
+                int h = getHeight();
+                
+                boolean codePadVisible = pkgMgrFrame.isTextEvalVisible();
+                 
+                // Paint a gradient from top to bottom:
+                GradientPaint gp;
+                if (codePadVisible) {
+                    gp = new GradientPaint(
+                            w/4, 0, new Color(209, 203, 179),
+                            w*3/4, h, new Color(235, 230, 200));
+                } else {
+                    gp = new GradientPaint(
+                        w/4, 0, new Color(235, 230, 200),
+                        w*3/4, h, new Color(209, 203, 179));
+                }
+   
+                g2d.setPaint(BACKGROUND_COLOR != null ? BACKGROUND_COLOR : gp);
+                g2d.fillRect(0, 0, w+1, h+1);
+            }
+        }
+        
+        
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBenchEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBenchEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..acb26438586fb0c2972c168a8465ff3440d7855c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBenchEvent.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.objectbench;
+
+import java.util.*;
+
+import bluej.debugmgr.NamedValue;
+
+/**
+ * The event which occurs when  performing actions with the ObjectBench.
+ *
+ * @author  Andrew Patterson
+ * @version $Id: ObjectBenchEvent.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class ObjectBenchEvent extends EventObject
+{
+    public final static int OBJECT_SELECTED = 1;
+
+    protected NamedValue value;
+    protected int id;
+
+    public ObjectBenchEvent(Object source, int id, NamedValue value)
+    {
+        super(source);
+
+        this.id = id;
+        this.value = value;
+    }
+
+    public int getID()
+    {
+        return id;
+    }
+
+    public NamedValue getValue()
+    {
+        return value;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBenchInterface.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBenchInterface.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c2be3459ecfc93743f927e7b00d46584c2a37ad
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBenchInterface.java
@@ -0,0 +1,49 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.objectbench;
+
+/**
+ * An interface for listening for object selection events.
+ * 
+ * @author Davin McCall
+ */
+public interface ObjectBenchInterface
+{
+    /**
+     * Add a listener for events on this object bench.
+     * @param l  The listener to add
+     */
+    public void addObjectBenchListener(ObjectBenchListener l);
+    
+    /**
+     * Remove a listener so that it no longer receives events.
+     * @param l  The listener to remove
+     */
+    public void removeObjectBenchListener(ObjectBenchListener l);
+    
+    /**
+     * Check whether the bench contains an object with name 'name'.
+     *
+     * @param name  The name to check for.
+     */
+    public boolean hasObject(String name);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBenchListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBenchListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..0cd9b8d046b7214866f2cd203b2ac23e1ecda4b8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectBenchListener.java
@@ -0,0 +1,35 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.objectbench;
+
+import java.util.*;
+
+/**
+ * The listener for ObjectBench events.
+ *
+ * @author  Andrew Patterson
+ * @version $Id: ObjectBenchListener.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface ObjectBenchListener extends EventListener
+{
+    void objectEvent(ObjectBenchEvent e);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectWrapper.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..77035a872b7633b2b9874674d63624aedaf89a2c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/objectbench/ObjectWrapper.java
@@ -0,0 +1,865 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.objectbench;
+
+import java.awt.AWTEvent;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Stroke;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.Action;
+import javax.swing.JComponent;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import bluej.BlueJEvent;
+import bluej.Config;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugmgr.ExecutionEvent;
+import bluej.debugmgr.ExpressionInformation;
+import bluej.debugmgr.Invoker;
+import bluej.debugmgr.NamedValue;
+import bluej.debugmgr.ResultWatcher;
+import bluej.extensions.BObject;
+import bluej.extensions.ExtensionBridge;
+import bluej.extmgr.MenuManager;
+import bluej.extmgr.ObjectMenuObject;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.prefmgr.PrefMgr;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.testmgr.record.ObjectInspectInvokerRecord;
+import bluej.utility.Debug;
+import bluej.utility.JavaNames;
+import bluej.utility.JavaReflective;
+import bluej.utility.Utility;
+import bluej.views.ConstructorView;
+import bluej.views.MethodView;
+import bluej.views.View;
+import bluej.views.ViewFilter;
+
+/**
+ * A wrapper around a Java object that handles calling methods, inspecting, etc.
+ *
+ * <p>The wrapper is represented by the red oval that is visible on the
+ * object bench.
+ *
+ * @author  Michael Kolling
+ */
+public class ObjectWrapper extends JComponent implements InvokeListener, NamedValue
+{
+    // Strings
+    static String methodException = Config.getString("debugger.objectwrapper.methodException");
+    static String invocationException = Config.getString("debugger.objectwrapper.invocationException");
+    static String inspect = Config.getString("debugger.objectwrapper.inspect");
+    static String remove = Config.getString("debugger.objectwrapper.remove");
+    static String redefinedIn = Config.getString("debugger.objectwrapper.redefined");
+    static String inheritedFrom = Config.getString("debugger.objectwrapper.inherited");
+
+    // Colors
+    static final Color envOpColour = Config.ENV_COLOUR;
+    static final Color textColour = Color.white;
+    
+    // Images
+    private static final Image objectImage = Config.getImageAsIcon("image.bench.object").getImage();
+    private static final Image selectedObjectImage = Config.getImageAsIcon("image.bench.object-selected").getImage();
+    
+    // Strokes
+    static final Stroke selectedStroke = new BasicStroke(2.0f);
+    static final Stroke normalStroke = new BasicStroke(1.0f);
+
+    // vertical offset between instance and class name
+    public static final int WORD_GAP = 20;
+    public static final int SHADOW_SIZE = 5;
+    
+    protected static final int HGAP = 5;    // horiz. gap between objects (left of each object)
+    protected static final int VGAP = 6;    // vert. gap between objects (above and below of each object)
+    public static final int WIDTH = objectImage.getWidth(null);    // width including gap
+    public static final int HEIGHT = objectImage.getHeight(null);   // height including gap
+
+    private static int itemHeight = 19;   // wild guess until we find out
+    private static boolean itemHeightKnown = false;
+    private static int itemsOnScreen;
+
+    /** The Java object that this wraps */
+    protected DebuggerObject obj;
+    protected GenTypeClass iType;
+
+    /** Fully qualified type this object represents, including type parameters */
+    private String className;
+    private String instanceName;
+    protected String displayClassName;
+    protected JPopupMenu menu;
+
+    // back references to the containers that we live in
+    private Package pkg;
+    private PkgMgrFrame pmf;
+    private ObjectBench ob;
+
+    private boolean isSelected = false;
+    
+    /**
+     * Get an object wrapper for a user object. 
+     * 
+     * @param pmf   The package manager frame
+     * @param ob    The object bench
+     * @param obj   The object to wrap
+     * @param iType   The static type of the object, used as a fallback if
+     *                the runtime type is inaccessible
+     * @param instanceName  The name for the object reference
+     * @return
+     */
+    static public ObjectWrapper getWrapper(PkgMgrFrame pmf, ObjectBench ob,
+                                            DebuggerObject obj,
+                                            GenTypeClass iType,
+                                            String instanceName)
+    {
+        if (obj.isArray()) {
+            return new ArrayWrapper(pmf, ob, obj, instanceName);
+        }
+        else {
+            return new ObjectWrapper(pmf, ob, obj, iType, instanceName);
+        }
+    }
+
+    protected ObjectWrapper(PkgMgrFrame pmf, ObjectBench ob, DebuggerObject obj, GenTypeClass iType, String instanceName)
+    {
+        // first one we construct will give us more info about the size of the screen
+        if(!itemHeightKnown) {
+            itemsOnScreen = (int)Config.screenBounds.getHeight() / itemHeight;
+        }
+
+        this.pmf = pmf;
+        this.pkg = pmf.getPackage();
+        this.ob = ob;
+        this.obj = obj;
+        this.iType = iType;
+        this.setName(instanceName);
+        if (obj.isNullObject()) {
+            className = "";
+            displayClassName = "";
+        }
+        else {
+            GenTypeClass objType = obj.getGenType();
+            className = objType.toString();
+            displayClassName = objType.toString(true);
+        }
+
+        createMenu(findIType());
+                
+        enableEvents(AWTEvent.MOUSE_EVENT_MASK);
+        
+        setMinimumSize(new Dimension(WIDTH, HEIGHT));
+        setSize(WIDTH, HEIGHT);
+        setFocusable(false);
+        setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+        ob.setSelectedObject(this);
+    }
+
+    public Package getPackage()
+    {
+        return pkg;
+    }
+
+    /**
+     * Get the PkgMgrFrame which is housing this object wrapper.
+     */
+    public PkgMgrFrame getFrame()
+    {
+        return pmf;
+    }
+    
+    public String getClassName()
+    {
+        return obj.getClassName();
+    }
+    
+    public String getTypeName()
+    {
+        return className;
+    }
+
+    /**
+     * Return the invocation type for this object. The invocation type is the
+     * type which should be written in the shell file. It is not necessarily the
+     * same as the actual (dynamic) type of the object.
+     */
+    @Override
+    public JavaType getGenType()
+    {
+        return iType;
+    }
+    
+    // --------- NamedValue interface --------------
+    
+    @Override
+    public boolean isFinal()
+    {
+        return true;
+    }
+    
+    @Override
+    public boolean isInitialized()
+    {
+        return true;
+    }
+    
+    // ----------------------------------------------
+    
+    private BObject singleBObject;  // Every ObjectWrapper has none or one BObject
+    
+    /**
+     * Return the extensions BObject associated with this ObjectWrapper.
+     * There should be only one BObject object associated with each Package.
+     * @return the BPackage associated with this Package.
+     */
+    public synchronized final BObject getBObject ()
+    {
+        if ( singleBObject == null )
+          singleBObject = ExtensionBridge.newBObject(this);
+          
+        return singleBObject;
+    }
+    
+    /**
+     * Perform any necessary cleanup before removal from the object bench.
+     */
+    public void prepareRemove()
+    {
+        pkg.getProject().removeInspectorInstance(obj);
+    }
+
+    /**
+     * Check whether the given class is accessible (from this wrapper's package)
+     * 
+     * @param cl  The class to check for accessibility
+     * @return    True if the class is accessible, false otherwise
+     */
+    private boolean classIsAccessible(Class<?> cl)
+    {
+        int clMods = cl.getModifiers();
+        String classPackage = JavaNames.getPrefix(cl.getName());
+        if (Modifier.isProtected(clMods) && ! pkg.getQualifiedName().equals(classPackage)
+                || Modifier.isPrivate(clMods)) {
+            return false;
+        }
+        else {
+            return true;
+        }
+    }
+    
+    /**
+     * Determine an appropriate type to use for this object in shell files.
+     * The type must be accessible in the current package.
+     * 
+     * iType will be set to the chosen type.
+     * 
+     * @return  The class of the chosen type.
+     */
+    private Class<?> findIType()
+    {
+        String className = obj.getClassName();
+        Class<?> cl = pkg.loadClass(className);
+        
+        // If the class is inaccessible, use the invocation type.
+        if (cl != null) {
+            if (! classIsAccessible(cl)) {
+                cl = pkg.loadClass(iType.classloaderName());
+                while (cl != null && ! classIsAccessible(cl)) {
+                    cl = cl.getSuperclass();
+                    if (cl != null) {
+                        iType = iType.mapToSuper(cl.getName());
+                    }
+                    else {
+                        JavaReflective objectReflective = new JavaReflective(Object.class);
+                        iType = new GenTypeClass(objectReflective);
+                    }
+                }
+            }
+            else {
+                // If the class type *is* accessible, on the other hand,
+                // use it as the invocation type.
+                iType = obj.getGenType();
+            }
+        }
+
+        return cl;
+    }
+    
+    /**
+     * Creates the popup menu structure by parsing the object's
+     * class inheritance hierarchy.
+     */
+    protected void createMenu(Class<?> cl)
+    {
+        menu = new JPopupMenu(getName() + " operations");
+
+        // add the menu items to call the methods
+        createMethodMenuItems(menu, cl, iType, this, obj, pkg.getQualifiedName(), true);
+
+        // add inspect and remove options
+        JMenuItem item;
+        menu.add(item = new JMenuItem(inspect));
+        item.addActionListener(
+            new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) { inspectObject(); }
+            });
+        item.setFont(PrefMgr.getStandoutMenuFont());
+        item.setForeground(envOpColour);
+  
+        menu.add(item = new JMenuItem(remove));
+        item.addActionListener(
+            new ActionListener() {
+                public void actionPerformed(ActionEvent e) { removeObject(); }
+            });
+        item.setFont(PrefMgr.getStandoutMenuFont());
+        item.setForeground(envOpColour);
+
+        MenuManager menuManager = new MenuManager (menu); 
+        menuManager.setAttachedObject(new ObjectMenuObject(this));
+        menuManager.addExtensionMenu(pkg.getProject());
+
+        add(menu);
+    }
+    
+    /**
+     * Creates the menu items for all the methods in the class, which is a raw
+     * class type.
+     * 
+     * @param menu  The menu to add the menu items to
+     * @param cl    The class whose methods to add
+     * @param il    The invoke listener to notify when a method is called
+     * @param obj   The object to apply the methods to
+     * @param currentPackageName Name of the package that this object will be
+     *            shown from (used to determine wheter to show package protected
+     *            methods)
+     * @param showObjectMethods Whether to show the submenu with methods from java.lang.Object
+     */
+    public static void createMethodMenuItems(JPopupMenu menu, Class<?> cl, InvokeListener il, DebuggerObject obj,
+            String currentPackageName, boolean showObjectMethods)
+    {
+        GenTypeClass gt = new GenTypeClass(new JavaReflective(cl));
+        createMethodMenuItems(menu, cl, gt, il, obj, currentPackageName, showObjectMethods);
+    }
+    
+    /**
+     * Creates the menu items for all the methods in the class
+     * 
+     * @param menu  The menu to add the menu items to
+     * @param cl    The class whose methods to add
+     * @param gtype  The generic type of the class
+     * @param il    The invoke listener to notify when a method is called
+     * @param obj   The object to apply the methods to
+     * @param currentPackageName Name of the package that this object will be
+     *            shown from (used to determine wheter to show package protected
+     *            methods)
+     * @param showObjectMethods Whether to show the submenu for methods inherited from java.lang.Object
+     */
+    public static void createMethodMenuItems(JPopupMenu menu, Class<?> cl, GenTypeClass gtype, InvokeListener il, DebuggerObject obj,
+            String currentPackageName, boolean showObjectMethods)
+    {
+        if (cl != null) {
+            View view = View.getView(cl);
+            Hashtable<JMenuItem, MethodView> actions = new Hashtable<JMenuItem, MethodView>();
+            Hashtable<String, String> methodsUsed = new Hashtable<String, String>();
+            List<Class<?>> classes = getClassHierarchy(cl);
+
+            // define two view filters for different package visibility
+            ViewFilter samePackageFilter = new ViewFilter(ViewFilter.INSTANCE | ViewFilter.PACKAGE);
+            ViewFilter otherPackageFilter = new ViewFilter(ViewFilter.INSTANCE | ViewFilter.PUBLIC);
+            
+            // define a view filter
+            ViewFilter filter;
+            if (currentPackageName != null && currentPackageName.equals(view.getPackageName()))
+                filter = samePackageFilter;
+            else
+                filter = otherPackageFilter;
+
+            menu.addSeparator();
+
+            // get declared methods for the class
+            MethodView[] declaredMethods = view.getDeclaredMethods();
+            
+            // create method entries for locally declared methods
+            GenTypeClass curType = gtype;
+            if (curType == null) {
+                curType = new GenTypeClass(new JavaReflective(cl));
+            }
+            
+            // HACK to make it work in greenfoot.
+            if(itemsOnScreen <= 0 ) {
+                itemsOnScreen = 30; 
+            }
+
+            int itemLimit = itemsOnScreen - 8 - classes.size();
+          
+            createMenuItems(menu, declaredMethods, il, filter, itemLimit, curType.getMap(), actions, methodsUsed);
+
+            // create submenus for superclasses
+            for(int i = 1; i < classes.size(); i++ ) {
+                Class<?> currentClass = classes.get(i);
+                view = View.getView(currentClass);
+                
+                // Determine visibility of package private / protected members
+                if (currentPackageName != null && currentPackageName.equals(view.getPackageName()))
+                    filter = samePackageFilter;
+                else
+                    filter = otherPackageFilter;
+                
+                // map generic type paramaters to the current superclass
+                curType = curType.mapToSuper(currentClass.getName());
+                
+                if (!"java.lang.Object".equals(currentClass.getName()) || showObjectMethods) { 
+                    declaredMethods = view.getDeclaredMethods();
+                    JMenu subMenu = new JMenu(inheritedFrom + " "
+                                   + JavaNames.stripPrefix(currentClass.getName()));
+                    subMenu.setFont(PrefMgr.getStandoutMenuFont());
+                    createMenuItems(subMenu, declaredMethods, il, filter, (itemsOnScreen / 2), curType.getMap(), actions, methodsUsed);
+                    menu.insert(subMenu, 0);
+                }
+            }
+
+            menu.addSeparator();
+        }
+    }
+    
+    /**
+     * creates the individual menu items for an object's popup menu.
+     * The method checks for previously defined methods with the same signature
+     * and appends information referring to this.
+     *
+     * @param menu      the menu that the items are to be created for
+     * @param methods   the methods for which menu items should be created
+     * @param il the listener to be notified when a method should be called
+     *            interactively
+     * @param filter    the filter which decides on which methods should be shown
+     * @param sizeLimit the limit to which the menu should grow before openeing
+     *                  submenus
+     * @param genericParams the mapping of generic type parameter names to their
+     *            corresponding types in the object instance (a map of String ->
+     *            GenType).
+     * @param methodsUsed 
+     * @param actions 
+     */
+    private static void createMenuItems(JComponent menu, MethodView[] methods, InvokeListener il, ViewFilter filter,
+            int sizeLimit, Map<String,GenTypeParameter> genericParams, Hashtable<JMenuItem, MethodView> actions, Hashtable<String, String> methodsUsed)
+    {
+        JMenuItem item;
+        boolean menuEmpty = true;
+
+        Arrays.sort(methods);
+        for(int i = 0; i < methods.length; i++) {
+            try {
+                MethodView m = methods[i];
+                if(!filter.accept(m))
+                    continue;
+
+                menuEmpty = false;
+                String methodSignature = m.getCallSignature();   // uses types for params
+                String methodDescription = m.getLongDesc(genericParams); // uses names for params
+
+                // check if method signature has already been added to a menu
+                if(methodsUsed.containsKey(methodSignature)) {
+                    methodDescription = methodDescription
+                             + "   [ " + redefinedIn + " "
+                             + JavaNames.stripPrefix(
+                                   methodsUsed.get(methodSignature))
+                             + " ]";
+                }
+                else {
+                    methodsUsed.put(methodSignature, m.getClassName());
+                }
+
+                Action a = new InvokeAction(m, il, methodDescription);
+                item = new JMenuItem(a);
+               
+                item.setFont(PrefMgr.getPopupMenuFont());
+                actions.put(item, m);
+
+                // check whether it's time for a submenu
+
+                int itemCount;
+                if(menu instanceof JMenu)
+                    itemCount =((JMenu)menu).getMenuComponentCount();
+                else
+                    itemCount = menu.getComponentCount();
+                if(itemCount >= sizeLimit) {
+                    JMenu subMenu = new JMenu(Config.getString("debugger.objectwrapper.moreMethods"));
+                    subMenu.setFont(PrefMgr.getStandoutMenuFont());
+                    subMenu.setForeground(envOpColour);
+                    menu.add(subMenu);
+                    menu = subMenu;
+                    sizeLimit = itemsOnScreen / 2;
+                }
+                menu.add(item);
+            } catch(Exception e) {
+                Debug.reportError(methodException + e);
+                e.printStackTrace();
+            }
+        }
+        
+        // If there are no accessible methods, insert a message which says so.
+        if (menuEmpty) {
+            JMenuItem mi = new JMenuItem(Config.getString("debugger.objectwrapper.noMethods"));
+            mi.setFont(PrefMgr.getStandoutMenuFont());
+            mi.setForeground(envOpColour);
+            mi.setEnabled(false);
+            menu.add(mi);
+        }
+    }
+
+    /**
+     * Creates a List containing all classes in an inheritance hierarchy
+     * working back to Object
+     *
+     * @param   derivedClass    the class whose hierarchy is mapped (including self)
+     * @return                  the List containng the classes in the inheritance hierarchy
+     */
+    public static List<Class<?>> getClassHierarchy(Class<?> derivedClass)
+    {
+        Class<?> currentClass = derivedClass;
+        List<Class<?>> classVector = new ArrayList<Class<?>>();
+        while(currentClass != null) {
+            classVector.add(currentClass);
+            currentClass = currentClass.getSuperclass();
+        }
+        return classVector;
+    }
+
+    @Override
+    public Dimension getMinimumSize()
+    {
+        return new Dimension(WIDTH, HEIGHT);
+    }
+
+    @Override
+    public Dimension getPreferredSize()
+    {
+        return new Dimension(WIDTH, HEIGHT);
+    }
+
+    @Override
+    public Dimension getMaximumSize()
+    {
+        return new Dimension(WIDTH, HEIGHT);
+    }
+
+    @Override
+    public String getName()
+    {
+        return instanceName;
+    }
+
+    @Override
+    public void setName(String newName)
+    {
+        instanceName = newName;
+    }
+
+    public DebuggerObject getObject()
+    {
+        return obj;
+    }
+
+
+    @Override
+    public void paintComponent(Graphics g)
+    {
+        super.paintComponent(g);            //paint background
+
+        Graphics2D g2 = (Graphics2D)g;
+        drawUMLStyle(g2);
+    }
+    
+    /**
+     * Draw the body of an object wrapper (everything, except the text).
+     */
+    protected void drawUMLObjectShape(Graphics2D g, int x, int y, int w, int h, int shad, int corner)
+    {
+        boolean isSelected = isSelected() && ob.hasFocus();
+        g.drawImage(isSelected ? selectedObjectImage : objectImage, x, y, null);
+    }
+
+    /**
+     * Draw the text onto an object wrapper (objectname: classname).
+     */
+    protected void drawUMLObjectText(Graphics2D g, int x, int y, int w, int shad, 
+            String objName, String className)
+    {
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        g.setColor(textColour);
+        g.setFont(PrefMgr.getTargetFont());
+
+        FontMetrics fm = g.getFontMetrics();
+        int fontHeight = fm.getAscent() + 5;
+
+        int maxWidth = w - shad - 4;    // our uml object will be (w-shad) pixels wide
+                                        // we leave 2 pixels of space either side of shape
+
+        // 54 is a hard hack; the height of the red part of the object image:
+        int totalGap = 54 - (fontHeight + fm.getAscent()); 
+        int start = totalGap / 2;
+        
+        // draw top string (normally instance name)
+        int aWidth = fm.stringWidth(objName);
+        if(aWidth > maxWidth) {
+            aWidth = maxWidth;
+        }
+
+        Utility.drawCentredText(g, objName, x+2, y+start, maxWidth, fontHeight);
+
+        // draw bottom string (normally class name)
+        int bWidth = fm.stringWidth(className);
+        if(bWidth > maxWidth)
+            bWidth = maxWidth;
+
+        Utility.drawCentredText(g, className, x+2, y+start+fontHeight, maxWidth, fontHeight);
+    }
+
+    /**
+     * draw a UML style object instance
+     */
+    protected void drawUMLStyle(Graphics2D g)
+    {
+        drawUMLObjectShape(g, HGAP, (VGAP / 2), WIDTH-HGAP, HEIGHT-VGAP, SHADOW_SIZE, 8);
+        drawUMLObjectText(g, HGAP, (VGAP / 2), WIDTH-HGAP, SHADOW_SIZE,
+                            getName() + ":", displayClassName);
+    }
+
+    /**
+     * Process a mouse click into this object. If it was a popup event, show the object's
+     * menu. If it was a double click, inspect the object. If it was a normal mouse click,
+     * insert it into a parameter field (if any).
+     */
+    @Override
+    protected void processMouseEvent(MouseEvent evt)
+    {
+        super.processMouseEvent(evt);
+        if(evt.isPopupTrigger()) {
+            showMenu(evt.getX(), evt. getY());
+        }
+        else if(evt.getID() == MouseEvent.MOUSE_CLICKED) {
+            if (evt.getClickCount() > 1) // double click
+                inspectObject();
+            else { //single click
+                ob.fireObjectEvent(this);
+            }
+
+        }
+        //manage focus
+        if (evt.getID() == MouseEvent.MOUSE_CLICKED || evt.isPopupTrigger()) {
+            ob.setSelectedObject(this);
+            ob.requestFocusInWindow();
+        }
+    }
+
+    // --- popup menu actions ---
+    
+    private int calcOffset()
+    {
+        int menuOffset;
+        if(!itemHeightKnown) {
+            int height = ((JComponent)menu.getComponent(0)).getHeight();
+
+            // first time, before it's shown, we won't get the real height
+            if(height > 1) {
+                itemHeight = height;
+                itemsOnScreen = (int)Config.screenBounds.getHeight() /
+                itemHeight;
+                itemHeightKnown = true;
+            }
+        }
+        // try tp position menu so that the pointer is near the method items
+        int offsetFactor = 4;
+        int menuCount = menu.getComponentCount();
+        // typically there are a minimum of 4 menu items for most objects
+        // arrays however do not (at present) so calculation is adjusted to compensate 
+        if( menuCount < 4)
+            offsetFactor = menuCount;
+        menuOffset = (menu.getComponentCount() - offsetFactor) * itemHeight;
+        return menuOffset;
+    }
+
+    public void showMenu(int x, int y)
+    {
+        int menuOffset;
+
+        if(menu == null) {
+            return;
+        }
+
+        menuOffset = calcOffset();
+        menu.show(this, x + 1, y - menuOffset);
+    }
+
+    public void showMenu()
+    {
+        showMenu(WIDTH/2, HEIGHT/2);
+    }
+
+    /**
+     * Open this object for inspection.
+     */
+    protected void inspectObject()
+    {
+        InvokerRecord ir = new ObjectInspectInvokerRecord(getName());
+        pkg.getProject().getInspectorInstance(obj, getName(), pkg, ir, pmf);  // shows the inspector
+    }
+
+    protected void removeObject()
+    {
+        ob.removeObject(this, pkg.getId());
+    }
+    
+    /**
+     * Execute an interactive method call. If the method has results,
+     * create a watcher to watch out for the result coming back, do the
+     * actual invocation, and update open object viewers after the call.
+     */
+    @Override
+    public void executeMethod(final MethodView method)
+    {
+        ResultWatcher watcher = null;
+
+        pkg.forgetLastSource();
+
+        watcher = new ResultWatcher() {
+            private ExpressionInformation expressionInformation = new ExpressionInformation(method,getName(),obj.getGenType());
+            
+            @Override
+            public void beginCompile()
+            {
+                pmf.setWaitCursor(true);
+            }
+            
+            @Override
+            public void beginExecution(InvokerRecord ir)
+            {
+                BlueJEvent.raiseEvent(BlueJEvent.METHOD_CALL, ir);
+                pmf.setWaitCursor(false);
+            }
+            
+            @Override
+            public void putResult(DebuggerObject result, String name, InvokerRecord ir)
+            {
+                ExecutionEvent executionEvent = new ExecutionEvent(pkg, obj.getClassName(), instanceName);
+                executionEvent.setMethodName(method.getName());
+                executionEvent.setParameters(method.getParamTypes(false), ir.getArgumentValues());
+                executionEvent.setResult(ExecutionEvent.NORMAL_EXIT);
+                executionEvent.setResultObject(result);
+                BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+                
+                pkg.getProject().updateInspectors();
+                expressionInformation.setArgumentValues(ir.getArgumentValues());
+                ob.addInteraction(ir);
+                
+                // a void result returns a name of null
+                if (result != null && ! result.isNullObject()) {
+                    pkg.getProject().getResultInspectorInstance(result, name, pkg,
+                            ir, expressionInformation, pmf);
+                }
+            }
+            
+            @Override
+            public void putError(String msg, InvokerRecord ir)
+            {
+                pmf.setWaitCursor(false);
+            }
+            
+            @Override
+            public void putException(ExceptionDescription exception, InvokerRecord ir)
+            {
+                ExecutionEvent executionEvent = new ExecutionEvent(pkg, obj.getClassName(), instanceName);
+                executionEvent.setParameters(method.getParamTypes(false), ir.getArgumentValues());
+                executionEvent.setResult(ExecutionEvent.EXCEPTION_EXIT);
+                executionEvent.setException(exception);
+                BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+                
+                pkg.getProject().updateInspectors();
+                pkg.exceptionMessage(exception);
+            }
+            
+            @Override
+            public void putVMTerminated(InvokerRecord ir)
+            {
+                ExecutionEvent executionEvent = new ExecutionEvent(pkg, obj.getClassName(), instanceName);
+                executionEvent.setParameters(method.getParamTypes(false), ir.getArgumentValues());
+                executionEvent.setResult(ExecutionEvent.TERMINATED_EXIT);
+                BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+            }
+        };
+
+        if (pmf.checkDebuggerState()) {
+            Invoker invoker = new Invoker(pmf, method, this, watcher);
+            invoker.invokeInteractive();
+        }
+    }
+    
+    public void callConstructor(ConstructorView cv)
+    {
+        // do nothing (satisfy the InvokeListener interface)
+    }
+
+    /**
+     * @return Returns the isSelected.
+     */
+    public boolean isSelected() 
+    {
+        return isSelected;
+    }
+
+    /**
+     * @param isSelected The isSelected to set.
+     */
+    public void setSelected(boolean isSelected) 
+    {
+        this.isSelected = isSelected;
+        if(isSelected) {
+            pmf.setStatus(getName() + " : " + displayClassName);
+        }
+        repaint();
+        scrollRectToVisible(new Rectangle(0, 0, WIDTH, HEIGHT));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/DeclaredVar.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/DeclaredVar.java
new file mode 100644
index 0000000000000000000000000000000000000000..9735b90534ce6925b68ea897122fd1fbcbf5d651
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/DeclaredVar.java
@@ -0,0 +1,77 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.texteval;
+
+import bluej.debugger.gentype.JavaType;
+
+/**
+ * A class to represent a variable declared by a statement. This contains
+ * the variable name and type, and whether or not it was initialized.
+ */
+public class DeclaredVar
+{
+    private boolean isVarInit = false;
+    private JavaType declVarType;
+    private String varName;
+    private boolean isFinal = false;
+    
+    public DeclaredVar(boolean isVarInit, boolean isFinal, JavaType varType, String varName)
+    {
+        this.isVarInit = isVarInit;
+        this.declVarType = varType;
+        this.varName = varName;
+        this.isFinal = isFinal;
+    }
+    
+    /**
+     * Check whether the variable declaration included an initialization.
+     */
+    public boolean isInitialized()
+    {
+        return isVarInit;
+    }
+    
+    /**
+     * Get the type of variable which was declared by the recently parsed
+     * statement. 
+     */
+    public JavaType getDeclaredType()
+    {
+        return declVarType;
+    }
+    
+    /**
+     * Get the name of the declared variable.
+     */
+    public String getName()
+    {
+        return varName;
+    }
+    
+    /**
+     * Check whether the variable was declared "final".
+     */
+    public boolean isFinal()
+    {
+        return isFinal;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/DragAndDropHelper.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/DragAndDropHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..117e60d2c30568d001793cc55ba36065ab23aa5a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/DragAndDropHelper.java
@@ -0,0 +1,256 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.texteval;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+import bluej.Config;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.debugger.DebuggerObject;
+import bluej.debugmgr.objectbench.ObjectBench;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * This class manages the dragging of object icons, and the drop onto
+ * drop targets.
+ * 
+ * @author Michael Kolling
+ */
+public class DragAndDropHelper 
+    implements MouseListener, MouseMotionListener
+{
+    private static final Image plusDragImage =
+        Config.getImageAsIcon("image.eval.dragobject-plus").getImage();
+    private static final Image noPlusDragImage =
+        Config.getImageAsIcon("image.eval.dragobject-noplus").getImage();
+   // private static final int imageWidth = plusDragImage.getWidth(null);
+   // private static final int imageHeight = plusDragImage.getHeight(null);
+
+    private static DragAndDropHelper instance;
+    
+    /**
+     * Lazy instantiation singleton factory method.
+     * @return The singleton instance
+     */
+    public static DragAndDropHelper getInstance()
+    {
+        if(instance == null) {
+            instance = new DragAndDropHelper();
+        }
+        return instance;
+    }
+    
+    // ==================== instance ====================
+    
+    private PkgMgrFrame frame;
+    private Component eventSource;
+    private DragGlassPane glassPane;
+    private ObjectBench target;
+
+    // the last object that we handled (this can be operated on)
+    private DebuggerObject object;
+    // the invoker record of the last successful call
+    private InvokerRecord invokerRecord;
+
+    private boolean targetHiLightOn;
+    private Image dragImage;
+    
+    private MouseMotionListener[] mml;  // other listeners
+    
+    /**
+     * Construct the helper.
+     */
+    private DragAndDropHelper()
+    {
+    }
+    
+    public void startDrag(Component source, PkgMgrFrame frame, 
+                          DebuggerObject object, InvokerRecord invokerRecord)
+    {
+        eventSource = source;
+        this.frame = frame;
+        target = frame.getObjectBench();
+        glassPane = new DragGlassPane();
+        frame.setGlassPane(glassPane);
+        dragImage = noPlusDragImage;
+        this.object = object;
+        this.invokerRecord = invokerRecord;
+
+        registerListeners();
+        glassPane.setVisible(true);
+    }
+    
+    /**
+     * The drag operation has ended. Check where we are and decide what to do.
+     * If we are over the target, drop the object.
+     */
+    private void stopDrag(int x, int y)
+    {
+        glassPane.setVisible(false);
+        deregisterListeners();
+        
+        if(pointInTarget(x, y)) {
+            // POLLE Create invoker record for this that allows "Get"?
+            frame.getPackage().getEditor().raisePutOnBenchEvent(target, object, object.getGenType(), invokerRecord);
+        }
+        target.showFocusHiLight(false);
+    }
+
+    private void checkTargetHiLight(int x, int y)
+    {
+        if(pointInTarget(x, y)) {
+            if(!targetHiLightOn) {
+                target.showFocusHiLight(true);
+                dragImage = plusDragImage;
+            }
+        }
+        else {
+            if(!targetHiLightOn) {
+                target.showFocusHiLight(false);
+                dragImage = noPlusDragImage;
+            }
+        }
+    }
+    
+    /**
+     * Check whether the specified point (in the event source's coordinate
+     * system) is inside the target component.
+     */
+    private boolean pointInTarget(int x, int y)
+    {
+        Point pt = SwingUtilities.convertPoint(eventSource, x, y, target);
+        return target.contains(pt);
+    }
+    
+    /**
+     * Register us as a mouse and motion listener, and disable
+     * all other motion listeners (we handle this one).
+     */
+    private void registerListeners()
+    {
+        eventSource.addMouseListener(this);
+        // temporarily remove other motion listeners
+        mml = eventSource.getMouseMotionListeners();
+        for(int i=0; i<mml.length; i++) {
+            eventSource.removeMouseMotionListener(mml[i]);
+        }
+        eventSource.addMouseMotionListener(this);
+    }
+    
+    /**
+     * De-register our mouse and motion listener, and enable
+     * the original motion listeners again.
+     */
+    private void deregisterListeners()
+    {
+        eventSource.removeMouseMotionListener(this);
+        eventSource.removeMouseListener(this);
+        // restore other motion listeners
+        for(int i=0; i<mml.length; i++) {
+            eventSource.addMouseMotionListener(mml[i]);
+        }        
+    }
+    
+    // ---- MouseMotionListener interface: ----
+    
+    public void mouseDragged(MouseEvent evt)
+    {
+        // make sure that we have left mouse button and not Mac ctrl-click
+        if(!evt.isPopupTrigger() &&
+           ((evt.getModifiers() & MouseEvent.BUTTON1_MASK) != 0)) {
+            int x = evt.getX();
+            int y = evt.getY();
+
+            checkTargetHiLight(x, y);
+
+            // translate point to glassPane coords and add object offset
+            Point pt = SwingUtilities.convertPoint(eventSource, x, y, glassPane);
+            glassPane.setObjectLocation(pt);
+            glassPane.repaint();
+        }
+    }
+    
+
+    public void mouseMoved(MouseEvent evt) {}
+
+    // ---- end of MouseMotionListener interface ----
+
+    // ---- MouseListener interface ----
+    
+    /**
+     * A full mouse button click was completed.
+     */
+    public void mouseClicked(MouseEvent evt) {}
+    
+
+    /**
+     * The mouse button was pressed.
+     */
+    public void mousePressed(MouseEvent evt) {}
+    
+
+    /**
+     * The mouse button was released.
+     */
+    public void mouseReleased(MouseEvent evt)
+    {
+        stopDrag(evt.getX(), evt.getY());
+    }
+
+
+    /**
+     * The mouse pointer entered this component.
+     */
+    public void mouseEntered(MouseEvent e) {}
+
+    
+    /**
+     * The mouse pointer exited this component.
+     */
+    public void mouseExited(MouseEvent e) {}
+
+    // ---- end of MouseListener interface ----
+
+    /**
+     * We have to provide our own glass pane so that it can paint the dragged object.
+     */
+    class DragGlassPane extends JComponent
+    {
+        private Point objectLocation;
+
+        @Override
+        protected void paintComponent(Graphics g) 
+        {
+            if (objectLocation != null) {
+                g.drawImage(dragImage, objectLocation.x-30, objectLocation.y-30, null);
+
+            }
+        }
+
+        public void setObjectLocation(Point p) 
+        {
+            objectLocation = p;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalArea.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalArea.java
new file mode 100644
index 0000000000000000000000000000000000000000..5a619d89930e70dd1900e4958456a336a5658258
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalArea.java
@@ -0,0 +1,215 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.texteval;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.prefmgr.PrefMgr;
+
+/**
+ * A customised text area for use in the BlueJ Java text evaluation.
+ *
+ * @author  Michael Kolling
+ * @version $Id: TextEvalArea.java 7725 2010-05-24 17:05:43Z nccb $
+ */
+public final class TextEvalArea extends JScrollPane
+    implements KeyListener, FocusListener
+{
+    private static final Color selectionColour = Config.getSelectionColour();
+
+    private TextEvalPane text;
+    
+    private boolean frameEmpty;
+    
+    /**
+     * Create a new text area with given size.
+     */
+    public TextEvalArea(PkgMgrFrame frame, Font font)
+    {
+        createComponent(frame, font);
+        frameEmpty = frame.isEmptyFrame();
+    }
+
+    /**
+     * Request to get the keyboard focus into the text evaluation area.
+     */
+    public void requestFocus()
+    {
+        text.requestFocus();
+    }
+
+    /**
+     * Sets whether or not this component is enabled.  
+     */
+    public void setEnabled(boolean enabled)
+    {
+        text.setEnabled(enabled);
+    }
+
+    /**
+     * Clear all text in this text area, and remove
+     * all local variables.
+     */
+    public void clear()
+    {
+        text.clear();
+        text.clearVars();
+    }
+    
+    /**
+     * Reset the font size according to preferences.
+     */
+    public void resetFontSize()
+    {
+        int fontsize = getFontSize();
+        if (fontsize != 0) {
+            Font codepadFont = text.getFont();
+            if (codepadFont.getSize() != fontsize) {
+                text.setFont(codepadFont.deriveFont((float) fontsize));
+            }
+        }
+    }
+    
+    /**
+     * Get the font size according to preferences. Might return 0.
+     */
+    private int getFontSize()
+    {
+        int fontsize = Config.getPropInteger("bluej.codepad.fontsize", 0);
+        if (fontsize == 0) {
+            // If not set specifically for codepad, use the editor font size
+            fontsize = PrefMgr.getEditorFontSize();
+        }
+        return fontsize;
+    }
+
+    // --- FocusListener interface ---
+    
+    /**
+     * Note that the object bench got keyboard focus.
+     */
+    public void focusGained(FocusEvent e) 
+    {
+        if (!e.isTemporary()) {
+            setBorder(Config.focusBorder);        
+            repaint();
+        }
+    }
+
+    
+    /**
+     * Note that the object bench lost keyboard focus.
+     */
+    public void focusLost(FocusEvent e) 
+    {
+        setBorder(Config.normalBorder);
+        repaint();
+    }
+
+    // --- end of FocusListener interface ---
+
+
+    //   --- KeyListener interface ---
+
+    /**
+     * Workaround for JDK 1.4 bug: backspace and tab keys are still handled 
+     * internally even when replaced in the keymap. So we explicitly remove them 
+     * here. This method (and the whole keylistener interface) can be removed
+     * when we don't support 1.4 anymore. (Fixed in JDK 5.0.)
+     */
+    public void keyTyped(KeyEvent e)
+    {
+        char ch = e.getKeyChar();
+        final char DEL = 127;
+        if(ch == '\b' || ch == '\t' || ch == DEL) {
+            e.consume();
+        }
+    }  
+
+    public void keyPressed(KeyEvent e) {}  
+    public void keyReleased(KeyEvent e) {}  
+
+    //   --- end of KeyListener interface ---
+
+    /**
+     * Create the Swing component representing the text area.
+     */
+    private void createComponent(PkgMgrFrame frame, Font font)
+    {
+        text = new TextEvalPane(frame);
+        text.setMargin(new Insets(2,2,2,2));
+
+        text.addKeyListener(this);
+        text.addFocusListener(this);
+        int fontSize = getFontSize();
+        if (fontSize != 0) {
+            font = font.deriveFont((float) fontSize);
+        }
+        text.setFont(font);
+        text.setSelectionColor(selectionColour);
+        text.setOpaque(false);
+        //To get fill working properly under Nimbus L&F, set background to transparent, too:
+        text.setBackground(new Color(0,0,0,0));
+
+        setViewportView(text);
+        updateBackground(frame.isEmptyFrame());
+
+        setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_ALWAYS);
+        setPreferredSize(new Dimension(300,100));
+    }
+    
+    protected void paintComponent(Graphics g)
+    {
+        super.paintComponent(g);
+        
+        if (g instanceof Graphics2D && false == frameEmpty) {
+            Graphics2D g2d = (Graphics2D)g;
+            
+            int w = getWidth();
+            int h = getHeight();
+           
+            GradientPaint gp = new GradientPaint(
+                w/4, 0, new Color(235, 230, 200),
+                w, h, new Color(209, 203, 179));
+
+            g2d.setPaint(gp);
+            // We don't draw the outermost pixel, so that when the border is empty, it
+            // shows the gradient from the window beneath (grey)
+            // rather than our gradient (beige) outside the grey bevel border
+            g2d.fillRect(1, 1, w-2, h-2);
+        }
+    }
+
+    public void updateBackground(boolean frameEmpty)
+    {
+        this.frameEmpty = frameEmpty;
+        
+        getViewport().setOpaque(frameEmpty);
+        setOpaque(frameEmpty);
+        
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalButtonModel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalButtonModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..4587cf14a289e7c21684a15fdcc940df8d09bf39
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalButtonModel.java
@@ -0,0 +1,55 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.texteval;
+
+import javax.swing.JToggleButton;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * ButtonModel for the "Show Text Evaluation" checkBoxItem in the menu.
+ * This model takes care that the right things happen when the checkbox
+ * is shown or changed.
+ *
+ * @author Michael Kolling
+ */
+public class TextEvalButtonModel extends JToggleButton.ToggleButtonModel
+{
+    private PkgMgrFrame pmf;
+    
+    public TextEvalButtonModel(PkgMgrFrame pmf)
+    {
+        super();
+        this.pmf = pmf;
+    }
+
+    public boolean isSelected()
+    {
+
+        return pmf.isTextEvalVisible();
+    }
+
+    public void setSelected(boolean b)
+    {
+        pmf.showHideTextEval(b);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalCaret.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalCaret.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ce6cb165852294bc7fb9791c03eae8af901bbef
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalCaret.java
@@ -0,0 +1,88 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.texteval;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.text.*;
+
+/**
+ * A customised caret for Moe. It gets most of its bahaviour from
+ * Swing's "DefaultCaret" and adds some functionality.
+ *
+ * @author  Michael Kolling
+ */
+
+public class TextEvalCaret extends DefaultCaret  
+{
+    /**
+     * Constructs a Moe Caret
+     */
+    public TextEvalCaret()
+    {
+        super();
+        setBlinkRate(0);
+    }
+
+    /**
+     * Redefinition of caret positioning (after mouse click). Here, we
+     * first check whether the click was in the tag line. If it was, we
+     * toggle the breakpoint, if not we just position the caret as usual.
+     */
+    protected void positionCaret(MouseEvent e) 
+    {
+        Point pt = new Point(e.getX(), e.getY());
+        Position.Bias[] biasRet = new Position.Bias[1];
+        int pos = getComponent().getUI().viewToModel(getComponent(), pt, biasRet);
+
+        if (e.getX() > TextEvalSyntaxView.TAG_WIDTH) {
+            if (pos >= 0) {
+                setDot(pos);
+            }
+        }
+        else {
+            ((TextEvalPane)getComponent()).tagAreaClick(pos, e.getClickCount());
+        }
+    }
+
+    /**
+     * Tries to move the position of the caret from
+     * the coordinates of a mouse event, using viewToModel(). 
+     * This will cause a selection if the dot and mark
+     * are different.
+     *
+     * @param e the mouse event
+     */
+    protected void moveCaret(MouseEvent e) 
+    {
+        if (e.getX() > TextEvalSyntaxView.TAG_WIDTH) {
+            Point pt = new Point(e.getX(), e.getY());
+            Position.Bias[] biasRet = new Position.Bias[1];
+            int pos = getComponent().getUI().viewToModel(getComponent(), pt, biasRet);
+            if (pos >= 0) {
+                moveDot(pos);
+            }
+        }
+    }
+}
+
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalPane.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalPane.java
new file mode 100644
index 0000000000000000000000000000000000000000..f667c549b3246b100ca3434abb6516952b07355b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalPane.java
@@ -0,0 +1,1175 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+
+package bluej.debugmgr.texteval;
+
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Event;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JEditorPane;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Caret;
+import javax.swing.text.Element;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.Keymap;
+import javax.swing.text.SimpleAttributeSet;
+
+import bluej.BlueJEvent;
+import bluej.Config;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugmgr.ExecutionEvent;
+import bluej.debugmgr.IndexHistory;
+import bluej.debugmgr.Invoker;
+import bluej.debugmgr.NamedValue;
+import bluej.debugmgr.ResultWatcher;
+import bluej.debugmgr.ValueCollection;
+import bluej.editor.moe.MoeSyntaxDocument;
+import bluej.editor.moe.MoeSyntaxEditorKit;
+import bluej.parser.TextAnalyzer;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.Debug;
+import bluej.utility.Utility;
+
+/**
+ * A modified editor pane for the text evaluation area.
+ * The standard JEditorPane is adjusted to take the tag line to the left into
+ * account in size computations.
+ * 
+ * @author Michael Kolling
+ */
+public class TextEvalPane extends JEditorPane 
+    implements ValueCollection, ResultWatcher, MouseMotionListener
+{
+    // The cursor to use while hovering over object icon
+    private static final Cursor defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR);
+    private static final Cursor objectCursor = new Cursor(Cursor.HAND_CURSOR);
+    private static final Cursor textCursor = new Cursor(Cursor.TEXT_CURSOR);
+    
+    private static final String nullLabel = "null";
+    
+    private static final String uninitializedWarning = Config.getString("pkgmgr.codepad.uninitialized");
+    
+    private PkgMgrFrame frame;
+    private MoeSyntaxDocument doc;  // the text document behind the editor pane
+    private String currentCommand = "";
+    private IndexHistory history;
+    private Invoker invoker = null;
+    private TextAnalyzer textParser = null;
+    
+    // Keeping track of invocation
+    private boolean firstTry;
+    private boolean wrappedResult;
+    private String errorMessage;
+    
+    private boolean mouseInTag = false;
+    private boolean mouseOverObject = false;
+    private boolean busy = false;
+    private Action softReturnAction;
+    
+    private List<CodepadVar> localVars = new ArrayList<CodepadVar>();
+    private List<CodepadVar> newlyDeclareds;
+    private List<String> autoInitializedVars;
+
+    public TextEvalPane(PkgMgrFrame frame)
+    {
+        super();
+        this.frame = frame;
+        setEditorKit(new MoeSyntaxEditorKit(true, null));
+        doc = (MoeSyntaxDocument) getDocument();
+        doc.enableParser(true);
+        defineKeymap();
+        clear();
+        history = new IndexHistory(20);
+        addMouseMotionListener(this);
+        setCaret(new TextEvalCaret());
+        setAutoscrolls(false);          // important - dragging objects from this component
+                                        // does not work correctly otherwise
+    }
+    
+    public Dimension getPreferredSize() 
+    {
+        Dimension d = super.getPreferredSize();
+        d.width += TextEvalSyntaxView.TAG_WIDTH + 8;  // bit of empty space looks nice
+        return d;
+    }
+    
+    /**
+     * Make sure, when we are scrolling to follow the caret,
+     * that we can see the tag area as well.
+     */
+    public void scrollRectToVisible(Rectangle rect)
+    {
+        super.scrollRectToVisible(new Rectangle(rect.x - (TextEvalSyntaxView.TAG_WIDTH + 4), rect.y,
+                rect.width + TextEvalSyntaxView.TAG_WIDTH + 4, rect.height));
+    }
+    
+    /**
+     * Clear all text in this text area.
+     */
+    public void clear()
+    {
+        setText(" ");
+        caretToEnd();
+    }
+    
+    /**
+     * Clear the local variables.
+     */
+    public void clearVars()
+    {
+        localVars.clear();
+        if (textParser != null) {
+            textParser.newClassLoader(frame.getProject().getClassLoader());
+        }
+    }
+
+    /**
+     * Paste the contents of the clipboard.
+     */
+    public void paste()
+    {
+        ensureLegalCaretPosition();
+        super.paste();
+    }
+
+    /**
+     * This is called when we get a 'paste' action (since we are handling 
+     * ordinary key input differently with the InsertCharacterAction.
+     * So: here we assume that we have a potential multi-line paste, and we
+     * want to treat it accordingly (as multi-line input).
+     */
+    public void replaceSelection(String content)
+    {
+        ensureLegalCaretPosition();
+
+        String[] lines = content.split("\n");
+        super.replaceSelection(lines[0]);
+        for(int i=1; i< lines.length;i++) {
+            softReturnAction.actionPerformed(null);
+            super.replaceSelection(lines[i]);
+        }
+    }
+    
+    //   --- ValueCollection interface ---
+    
+    /*
+     * @see bluej.debugmgr.ValueCollection#getValueIterator()
+     */
+    public Iterator<CodepadVar> getValueIterator()
+    {
+        return localVars.iterator();
+    }
+    
+    /*
+     * @see bluej.debugmgr.ValueCollection#getNamedValue(java.lang.String)
+     */
+    public NamedValue getNamedValue(String name)
+    {
+        NamedValue nv = getLocalVar(name);
+        if (nv != null) {
+            return nv;
+        }
+        else {
+            return frame.getObjectBench().getNamedValue(name);
+        }
+    }
+    
+    /**
+     * Search for a named local variable, but do not fall back to the object
+     * bench if it cannot be found (return null in this case).
+     * 
+     * @param name  The name of the variable to search for
+     * @return    The named variable, or null
+     */
+    private NamedValue getLocalVar(String name)
+    {
+        Iterator<CodepadVar> i = localVars.iterator();
+        while (i.hasNext()) {
+            NamedValue nv = (NamedValue) i.next();
+            if (nv.getName().equals(name))
+                return nv;
+        }
+        
+        // not found
+        return null;
+    }
+    
+    //   --- ResultWatcher interface ---
+
+    /*
+     * @see bluej.debugmgr.ResultWatcher#beginExecution()
+     */
+    public void beginCompile() { }
+    
+    /*
+     * @see bluej.debugmgr.ResultWatcher#beginExecution()
+     */
+    public void beginExecution(InvokerRecord ir)
+    { 
+        BlueJEvent.raiseEvent(BlueJEvent.METHOD_CALL, ir);
+    }
+    
+    /**
+     * An invocation has completed - here is the result.
+     * If the invocation has a void result (note that is a void type), result == null.
+     */
+    public void putResult(final DebuggerObject result, final String name, final InvokerRecord ir)
+    {
+        frame.getObjectBench().addInteraction(ir);
+        frame.getPackage().getProject().updateInspectors();
+        
+        // Newly declared variables are now initialized
+        if (newlyDeclareds != null) {
+            Iterator<CodepadVar> i = newlyDeclareds.iterator();
+            while (i.hasNext()) {
+                CodepadVar cpv = (CodepadVar) i.next();
+                cpv.setInitialized();
+            }
+            newlyDeclareds = null;
+        }
+        
+        append(" ");
+        boolean giveUninitializedWarning = autoInitializedVars != null && autoInitializedVars.size() != 0; 
+        
+        if (giveUninitializedWarning && Utility.firstTimeThisRun("TextEvalPane.uninitializedWarning")) {
+            // Some variables were automatically initialized - warn the user that
+            // this won't happen in "real" code.
+            
+            String warning = uninitializedWarning;
+            
+            int findex = 0;
+            while (findex < warning.length()) {
+                int nindex = warning.indexOf('\n', findex);
+                if (nindex == -1)
+                    nindex = warning.length();
+                
+                String warnLine = warning.substring(findex, nindex);
+                append(warnLine);
+                markAs(TextEvalSyntaxView.ERROR, Boolean.TRUE);
+                findex = nindex + 1; // skip the newline character
+            }
+            
+            autoInitializedVars.clear();
+        }
+        
+        if (result != null && !result.isNullObject()) {
+            DebuggerField resultField = result.getField(0);
+            String resultString = resultField.getValueString();
+            
+            if(resultString.equals(nullLabel)) {
+                output(resultString);
+            }
+            else {
+                boolean isObject = resultField.isReferenceType();
+                
+                if(isObject) {
+                    DebuggerObject resultObject = resultField.getValueObject(null);
+                    String resultType = resultObject.getGenType().toString(true);
+                    String resultOutputString = resultString + "   (" + resultType + ")";
+                    objectOutput(resultOutputString,  new ObjectInfo(resultObject, ir));
+                }
+                else {
+                    String resultType = resultField.getType().toString(true);
+                    String resultOutputString = resultString + "   (" + resultType + ")";
+                    output(resultOutputString);
+                }
+            }            
+        } 
+        
+        ExecutionEvent executionEvent = new ExecutionEvent(frame.getPackage());
+        executionEvent.setCommand(currentCommand);
+        executionEvent.setResult(ExecutionEvent.NORMAL_EXIT);
+        executionEvent.setResultObject(result);
+        BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+        
+        currentCommand = "";
+        textParser.confirmCommand();
+        setEditable(true);    // allow next input
+        busy = false;
+    }
+    
+    /**
+     * An invocation has failed - here is the error message
+     */
+    public void putError(String message, InvokerRecord ir)
+    {
+        if(firstTry) {
+            if (wrappedResult) {
+                // We thought we knew what the result type should be, but there
+                // was a compile time error. So try again, assuming that we
+                // got it wrong, and we'll use the dynamic result type (meaning
+                // we won't get type arguments).
+                wrappedResult = false;
+                errorMessage = null; // use the error message from this second attempt
+                invoker = new Invoker(frame, this, currentCommand, TextEvalPane.this);
+                invoker.setImports(textParser.getImportStatements());
+                invoker.doFreeFormInvocation("");
+            }
+            else {
+                // We thought there was going to be a result, but compilation failed.
+                // Try again, but assume we have a statement this time.
+                firstTry = false;
+                invoker = new Invoker(frame, this, currentCommand, TextEvalPane.this);
+                invoker.setImports(textParser.getImportStatements());
+                invoker.doFreeFormInvocation(null);
+                if (errorMessage == null) {
+                    errorMessage = message;
+                }
+            }
+        }
+        else {
+            if (errorMessage == null) {
+                errorMessage = message;
+            }
+            
+            // An error. Remove declared variables.
+            if (autoInitializedVars != null) {
+                autoInitializedVars.clear();
+            }
+            
+            removeNewlyDeclareds();
+            showErrorMsg(errorMessage);
+            errorMessage = null;
+        }
+    }
+    
+    /**
+     * A runtime exception occurred.
+     */
+    public void putException(ExceptionDescription exception, InvokerRecord ir)
+    {
+        ExecutionEvent executionEvent = new ExecutionEvent(frame.getPackage());
+        executionEvent.setCommand(currentCommand);
+        executionEvent.setResult(ExecutionEvent.EXCEPTION_EXIT);
+        executionEvent.setException(exception);
+        BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+        frame.getPackage().getProject().updateInspectors();
+        
+        if (autoInitializedVars != null) {
+            autoInitializedVars.clear();
+        }
+        
+        removeNewlyDeclareds();
+        String message = exception.getClassName() + " (" + exception.getText() + ")";
+        showExceptionMsg(message);
+    }
+    
+    /**
+     * The remote VM terminated before execution completed (or as a result of
+     * execution).
+     */
+    public void putVMTerminated(InvokerRecord ir)
+    {
+        if (autoInitializedVars != null)
+            autoInitializedVars.clear();
+        
+        removeNewlyDeclareds();
+        
+        
+        String message = Config.getString("pkgmgr.codepad.vmTerminated");
+        append(message);
+        markAs(TextEvalSyntaxView.ERROR, Boolean.TRUE);
+        
+        completeExecution();
+    }
+    
+    /**
+     * Remove the newly declared variables from the value collection.
+     * (This is needed if compilation fails, or execution bombs with an exception).
+     */
+    private void removeNewlyDeclareds()
+    {
+        if (newlyDeclareds != null) {
+            Iterator<CodepadVar> i = newlyDeclareds.iterator();
+            while (i.hasNext()) {
+                localVars.remove(i.next());
+            }
+            newlyDeclareds = null;
+        }
+    }
+    
+    //   --- end of ResultWatcher interface ---
+    
+    /**
+     * Show an error message, and allow further command input.
+     */
+    private void showErrorMsg(final String message)
+    {
+        append(" ");
+        error("Error: " + message);
+        completeExecution();
+    }
+    
+    /**
+     * Show an exception message, and allow further command input.
+     */
+    private void showExceptionMsg(final String message)
+    {
+        append(" ");
+        error("Exception: " + message);
+        completeExecution();
+    }
+    
+    /**
+     * Execution of the current command has finished (one way or another).
+     * Allow further command input.
+     */
+    private void completeExecution()
+    {
+        currentCommand = "";
+        setEditable(true);
+        busy = false;
+    }
+
+    /**
+     * We had a click in the tag area. Handle it appropriately.
+     * Specifically: If the click (or double click) is on an object, then
+     * start an object drag (or inspect).
+     * @param pos   The text position where we got the click.
+     * @param clickCount  Number of consecutive clicks
+     */
+    public void tagAreaClick(int pos, int clickCount)
+    {
+        ObjectInfo objInfo = objectAtPosition(pos);
+        if(objInfo != null) {
+            if(clickCount == 1) {
+                DragAndDropHelper dnd = DragAndDropHelper.getInstance();
+                dnd.startDrag(this, frame, objInfo.obj, objInfo.ir);
+            }
+            else if(clickCount == 2) {   // double click
+                inspectObject(objInfo);
+            }
+        }
+    }
+    
+    /**
+     * Inspect the given object.
+     * This is done with a delay, because we are in the middle of a mouse click,
+     * and focus gets weird otherwise.
+     */
+    private void inspectObject(TextEvalPane.ObjectInfo objInfo)
+    {
+        final TextEvalPane.ObjectInfo oi = objInfo;
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                frame.getProject().getInspectorInstance(oi.obj, null, frame.getPackage(), oi.ir, frame);
+            }
+        });
+    }
+
+    /**
+     * Write a (non-error) message to the text area.
+     * @param s The message
+     */
+    private void output(String s)
+    {
+        try {
+            doc.insertString(doc.getLength(), s, null);
+            markAs(TextEvalSyntaxView.OUTPUT, Boolean.TRUE);
+        }
+        catch(BadLocationException exc) {
+            Debug.reportError("bad location in terminal operation");
+        }
+    }
+    
+    /**
+     * Write a (non-error) message to the text area.
+     * @param s The message
+     */
+    private void objectOutput(String s, ObjectInfo objInfo)
+    {
+        try {
+            doc.insertString(doc.getLength(), s, null);
+            markAs(TextEvalSyntaxView.OBJECT, objInfo);
+        }
+        catch(BadLocationException exc) {
+            Debug.reportError("bad location in terminal operation");
+        }
+    }
+    
+    /**
+     * Write an error message to the text area.
+     * @param s The message
+     */
+    private void error(String s)
+    {
+        try {
+            doc.insertString(doc.getLength(), s, null);
+            markAs(TextEvalSyntaxView.ERROR, Boolean.TRUE);
+        }
+        catch(BadLocationException exc) {
+            Debug.reportError("bad location in terminal operation");
+        }
+    }
+    
+    /**
+     * Append some text to this area.
+     * @param s The text to append.
+     */
+    private void append(String s)
+    {
+        try {
+            doc.insertString(doc.getLength(), s, null);
+            caretToEnd();
+        }
+        catch(BadLocationException exc) {
+            Debug.reportError("bad location in terminal operation");
+        }
+    }
+    
+    /**
+     * Move the caret to the end of the text.
+     */
+    private void caretToEnd() 
+    {
+        setCaretPosition(doc.getLength());
+    }
+
+    /**
+     * Ensure that the caret position (including the whole
+     * selection, if any) is within the editale area (the last 
+     * line of text). If it isn't, adjust it so that it is.
+     */
+    private void ensureLegalCaretPosition()
+    {
+        Caret caret = getCaret();
+        boolean dotOK = isLastLine(caret.getDot());
+        boolean markOK = isLastLine(caret.getMark());
+        
+        if(dotOK && markOK)     // both in last line - no problem
+            return;
+        
+        if(!dotOK && !markOK) { // both not in last line - append at end
+            setCaretPosition(getDocument().getLength());
+        }
+        else {                  // selection reaches into last line
+            caret.setDot(Math.max(caret.getDot(), caret.getMark()));
+            caret.moveDot(startOfLastLine());
+        }
+    }
+    
+    /**
+     * Check whether the given text position is within the area
+     * intended for editing (the last line).
+     * 
+     * @param pos  The position to be checked
+     * @return  True if this position is within the last text line.
+     */
+    private boolean isLastLine(int pos)
+    {
+        return pos >= startOfLastLine();
+    }
+    
+    /**
+     * Return the text position of the start of the last text line
+     * (the start of the area editable by the user).
+     * 
+     * @return  The position of the start of the last text line.
+     */
+    private int startOfLastLine()
+    {
+        AbstractDocument doc = (AbstractDocument) getDocument();
+        Element line = doc.getParagraphElement(doc.getLength());
+        return line.getStartOffset() + 1;  // ignore space at front
+    }
+    
+    /**
+     * Get the text of the current line (the last line) of this area.
+     * @return The text of the last line.
+     */
+    private String getCurrentLine()
+    {
+        Element line = doc.getParagraphElement(doc.getLength());
+        int lineStart = line.getStartOffset() + 1;  // ignore space at front
+        int lineEnd = line.getEndOffset() - 1;      // ignore newline char
+        
+        try {
+            return doc.getText(lineStart, lineEnd-lineStart);
+        }
+        catch(BadLocationException exc) {
+            Debug.reportError("bad location in text eval operation");
+            return "";
+        }
+    }
+    
+    /**
+     * Return the current column number.
+     */
+    private int getCurrentColumn()
+    {
+        Caret caret = getCaret();
+        int pos = Math.min(caret.getMark(), caret.getDot());
+        return getColumnFromPosition(pos);
+    }
+
+    /**
+     * Return tha column for a given position.
+     */
+    private int getColumnFromPosition(int pos)
+    {
+        int lineStart = doc.getParagraphElement(pos).getStartOffset();
+        return (pos - lineStart);       
+    }
+    
+    /**
+     * Mark the last line of the text area as output. and start a new 
+     * line after that one.
+     */
+    private void markAs(String flag, Object value)
+    {
+        append("\n ");          // ensure space at the beginning of every line
+        SimpleAttributeSet a = new SimpleAttributeSet();
+        a.addAttribute(flag, value);
+        doc.setParagraphAttributes(doc.getLength()-2, a);
+        repaint();
+    }
+    
+    /**
+     * Mark the current line of the text area as output.
+     */
+    private void markCurrentAs(String flag, Object value)
+    {
+        SimpleAttributeSet a = new SimpleAttributeSet();
+        a.addAttribute(flag, value);
+        doc.setParagraphAttributes(doc.getLength(), a);
+    }
+    
+     /**
+     * Replace the text of the current line with some new text.
+     * @param s The new text for the line.
+     */
+    private void replaceLine(String s)
+    {
+        Element line = doc.getParagraphElement(doc.getLength());
+        int lineStart = line.getStartOffset() + 1;  // ignore space at front
+        int lineEnd = line.getEndOffset() - 1;      // ignore newline char
+        
+        try {
+                doc.replace(lineStart, lineEnd-lineStart, s, null);
+        }
+        catch(BadLocationException exc) {
+            Debug.reportError("bad location in text eval operation");
+        }
+    }
+    
+    /**
+     * Return the object stored with the line at position 'pos'.
+     * If that line does not have an object, return null.
+     */
+    private ObjectInfo objectAtPosition(int pos)
+    {
+        Element line = getLineAt(pos);
+        return (ObjectInfo) line.getAttributes().getAttribute(TextEvalSyntaxView.OBJECT);
+    }
+
+    /**
+     *  Find and return a line by text position
+     */
+    private Element getLineAt(int pos)
+    {
+        return doc.getParagraphElement(pos);
+    }
+
+    /**
+     * Check whether a given point on screen is over an object icon.
+     */
+    private boolean pointOverObjectIcon(int x, int y)
+    {
+        int pos = getUI().viewToModel(this, new Point(x, y));
+        ObjectInfo objInfo = objectAtPosition(pos);
+        return objInfo != null;        
+    }
+    
+    // ---- MouseMotionListener interface: ----
+    
+    public void mouseDragged(MouseEvent evt) {}
+
+    /**
+     * When the mouse is moved, check whether we should change the 
+     * mouse cursor.
+     */
+    public void mouseMoved(MouseEvent evt) 
+    {
+        int x = evt.getX();
+        int y = evt.getY();
+        
+        if(mouseInTag) {
+            if(x > TextEvalSyntaxView.TAG_WIDTH) {    // moved out of tag area
+                setCursor(textCursor);
+                mouseInTag = false;
+            }
+            else 
+                setTagAreaCursor(x, y);
+        }
+        else {
+            if(x <= TextEvalSyntaxView.TAG_WIDTH) {   // moved into tag area
+                setCursor(defaultCursor);
+                mouseOverObject = false;
+                setTagAreaCursor(x, y);
+                mouseInTag = true;
+            }
+        }
+    }
+
+    /**
+     * Set the mouse cursor for the tag area. 
+     */
+    private void setTagAreaCursor(int x, int y)
+    {
+        if(pointOverObjectIcon(x, y) != mouseOverObject) {  // entered or left object
+            mouseOverObject = !mouseOverObject;
+            if(mouseOverObject)
+                setCursor(objectCursor);
+            else
+                setCursor(defaultCursor);
+        }        
+    }
+
+    // ---- end of MouseMotionListener interface ----
+
+    /**
+     * Set the keymap for this text area. Especially: take care that cursor 
+     * movement is restricted so that the cursor remains in the last line,
+     * and interpret Return keys to evaluate commands.
+     */
+    private void defineKeymap()
+    {
+        Keymap newmap = JTextComponent.addKeymap("texteval", getKeymap());
+
+        Action action = new InsertCharacterAction();
+        newmap.setDefaultAction(action);
+
+        action = new ExecuteCommandAction();
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), action);
+
+        softReturnAction = new ContinueCommandAction();
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Event.SHIFT_MASK), softReturnAction);
+
+        action = new BackSpaceAction();
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), action);
+        
+        action = new CursorLeftAction();
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), action);
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_KP_LEFT, 0), action);
+
+        action = new HistoryBackAction();
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), action);
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_KP_UP, 0), action);
+
+        action = new HistoryForwardAction();
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), action);
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_KP_DOWN, 0), action);
+
+        action = new TransferFocusAction(true);
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), action);
+
+        action = new TransferFocusAction(false);
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, Event.SHIFT_MASK), action);
+        
+        action = new CursorHomeAction();
+        newmap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), action);
+
+        setKeymap(newmap);
+    }
+    
+    
+    final class InsertCharacterAction extends AbstractAction {
+
+        /**
+         * Create a new action object. This action executes the current command.
+         */
+        public InsertCharacterAction()
+        {
+            super("InsertCharacter");
+        }
+        
+        /**
+         * Insert a character into the text.
+         */
+        final public void actionPerformed(ActionEvent event)
+        {
+            if(!isEditable())
+                return;
+            
+            String s = event.getActionCommand();  // will always be length 1
+            if(s.charAt(0) != '\n') {             // bug workaround: enter goes through default
+                                                  //  action as well as set action
+                replaceSelection(s);
+            }
+        }
+    }
+
+    final class ExecuteCommandAction extends AbstractAction {
+
+        /**
+         * Create a new action object. This action executes the current command.
+         */
+        public ExecuteCommandAction()
+        {
+            super("ExecuteCommand");
+        }
+        
+        /**
+         * Execute the text of the current line in the text area as a Java command.
+         */
+        final public void actionPerformed(ActionEvent event)
+        {
+            if (busy) {
+                return;
+            }
+            
+            String line = getCurrentLine();
+            currentCommand = (currentCommand + line).trim();
+            if(currentCommand.length() != 0) {
+                       
+                history.add(line);
+                append("\n");      // ensure space at the beginning of every line, because
+                                    // line properties do not work otherwise
+                markCurrentAs(TextEvalSyntaxView.OUTPUT, Boolean.TRUE);
+                firstTry = true;
+                setEditable(false);    // don't allow input while we're thinking
+                busy = true;
+                if (textParser == null) {
+                    textParser = new TextAnalyzer(frame.getProject().getEntityResolver(),
+                            frame.getPackage().getQualifiedName(), TextEvalPane.this);
+                }
+                String retType;
+                retType = textParser.parseCommand(currentCommand);
+                wrappedResult = (retType != null && retType.length() != 0);
+                
+                // see if any variables were declared
+                if (retType == null) {
+                    firstTry = false; // Only try once.
+                    currentCommand = textParser.getAmendedCommand();
+                    List<DeclaredVar> declaredVars = textParser.getDeclaredVars();
+                    if (declaredVars != null) {
+                        Iterator<DeclaredVar> i = declaredVars.iterator();
+                        while (i.hasNext()) {
+                            if (newlyDeclareds == null) {
+                                newlyDeclareds = new ArrayList<CodepadVar>();
+                            }
+                            if (autoInitializedVars == null) {
+                                autoInitializedVars = new ArrayList<String>();
+                            }
+                            
+                            DeclaredVar dv = i.next();
+                            String declaredName = dv.getName();
+                            
+                            if (getLocalVar(declaredName) != null) {
+                                // The variable has already been declared
+                                String errMsg = Config.getString("pkgmgr.codepad.redefinedVar");
+                                errMsg = Utility.mergeStrings(errMsg, declaredName);
+                                showErrorMsg(errMsg);
+                                removeNewlyDeclareds();
+                                return;
+                            }
+                            
+                            CodepadVar cpv = new CodepadVar(dv.getName(), dv.getDeclaredType(), dv.isFinal());
+                            newlyDeclareds.add(cpv);
+                            localVars.add(cpv);
+
+                            // If the variable was declared but not initialized, the codepad
+                            // auto-initializes it. We add to a list so that we can display
+                            // a warning to that effect, once the command has completed.
+                            if (! dv.isInitialized()) {
+                                autoInitializedVars.add(dv.getName());
+                            }
+                        }
+                    }
+                }
+                
+                invoker = new Invoker(frame, TextEvalPane.this, currentCommand, TextEvalPane.this);
+                invoker.setImports(textParser.getImportStatements());
+                if (!invoker.doFreeFormInvocation(retType)) {
+                    // Invocation failed
+                    firstTry = false;
+                    putError("Invocation failed.", null);
+                }
+            }
+            else {
+                markAs(TextEvalSyntaxView.OUTPUT, Boolean.TRUE);
+            }
+        }
+    }
+
+    final class ContinueCommandAction extends AbstractAction {
+        
+        /**
+         * Create a new action object. This action reads the current
+         * line as a start for a new command and continues reading the 
+         * command in the next line.
+         */
+        public ContinueCommandAction()
+        {
+            super("ContinueCommand");
+        }
+        
+        /**
+         * Read the text of the current line in the text area as the
+         * start of a Java command and continue reading in the next line.
+         */
+        final public void actionPerformed(ActionEvent event)
+        {
+            if (busy)
+                return;
+            
+            String line = getCurrentLine();
+            currentCommand += line + " ";
+            history.add(line);
+            markAs(TextEvalSyntaxView.CONTINUE, Boolean.TRUE);
+        }
+    }
+
+    final class BackSpaceAction extends AbstractAction {
+
+        /**
+         * Create a new action object.
+         */
+        public BackSpaceAction()
+        {
+            super("BackSpace");
+        }
+        
+        /**
+         * Perform a backspace action.
+         */
+        final public void actionPerformed(ActionEvent event)
+        {
+            if (busy)
+                return;
+            
+            if(getCurrentColumn() > 1) {
+                try {
+                    if(getSelectionEnd() == getSelectionStart()) { // no selection
+                        doc.remove(getCaretPosition()-1, 1);
+                    }
+                    else {
+                        replaceSelection("");
+                    }
+                }
+                catch(BadLocationException exc) {
+                    Debug.reportError("bad location in text eval operation");
+                }
+            }
+        }
+    }
+
+    final class CursorLeftAction extends AbstractAction {
+
+        /**
+         * Create a new action object.
+         */
+        public CursorLeftAction()
+        {
+            super("CursorLeft");
+        }
+
+        /**
+         * Move the cursor left (if allowed).
+         */
+        final public void actionPerformed(ActionEvent event)
+        {
+            if (busy)
+                return;
+            
+            if(getCurrentColumn() > 1) {
+                Caret caret = getCaret();
+                caret.setDot(caret.getDot() - 1);
+            }
+        }
+    }
+    
+    final class CursorHomeAction extends AbstractAction {
+        
+        /**
+         * Create a new action object.
+         */
+        public CursorHomeAction()
+        {
+            super("CursorHome");
+        }
+        
+        /**
+         * Home the cursor. This overrides the default behaviour (move to
+         * column 0) to "move to column 1".
+         */
+        public void actionPerformed(ActionEvent event)
+        {
+            if (busy)
+                return;
+            
+            Caret caret = getCaret();
+            int curCol = getColumnFromPosition(caret.getDot());
+            if (curCol != 1)
+                caret.setDot(caret.getDot() - curCol + 1);
+        }
+    }
+
+    final class HistoryBackAction extends AbstractAction {
+
+        /**
+         * Create a new action object.
+         */
+        public HistoryBackAction()
+        {
+            super("HistoryBack");
+        }
+        
+        /**
+         * Set the current line to the previous input history entry.
+         */
+        final public void actionPerformed(ActionEvent event)
+        {
+            if (busy)
+                return;
+            
+            String line = history.getPrevious();
+            if(line != null) {
+                replaceLine(line);
+            }
+        }
+
+    }
+
+    final class HistoryForwardAction extends AbstractAction {
+
+        /**
+         * Create a new action object.
+         */
+        public HistoryForwardAction()
+        {
+            super("HistoryForward");
+        }
+        
+        /**
+         * Set the current line to the next input history entry.
+         */
+        final public void actionPerformed(ActionEvent event)
+        {
+            if (busy)
+                return;
+            
+            String line = history.getNext();
+            if(line != null) {
+                replaceLine(line);
+            }
+        }
+
+    }
+
+    final class TransferFocusAction extends AbstractAction {
+        private boolean forward;
+        /**
+         * Create a new action object.
+         */
+        public TransferFocusAction(boolean forward)
+        {
+            super("TransferFocus");
+            this.forward = forward;
+        }
+        
+        /**
+         * Transfer the keyboard focus to another component.
+         */
+        final public void actionPerformed(ActionEvent event)
+        {
+            if(forward)
+                transferFocus();
+            else
+                transferFocusBackward();
+        }
+
+    }    
+
+    final class ObjectInfo {
+        DebuggerObject obj;
+        InvokerRecord ir;
+        
+        /**
+         * Create an object holding information about an invocation.
+         */
+        public ObjectInfo(DebuggerObject obj, InvokerRecord ir) {
+            this.obj = obj;
+            this.ir = ir;
+        }
+    }
+    
+    final class CodepadVar implements NamedValue {
+        
+        String name;
+        boolean finalVar;
+        boolean initialized = false;
+        JavaType type;
+        
+        public CodepadVar(String name, JavaType type, boolean finalVar)
+        {
+            this.name = name;
+            this.finalVar = finalVar;
+            this.type = type;
+        }
+        
+        public String getName()
+        {
+            return name;
+        }
+        
+        public JavaType getGenType()
+        {
+            return type;
+        }
+        
+        public boolean isFinal()
+        {
+            return finalVar;
+        }
+        
+        public boolean isInitialized()
+        {
+            return initialized;
+        }
+        
+        public void setInitialized()
+        {
+            initialized = true;
+        }
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalSyntaxView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalSyntaxView.java
new file mode 100644
index 0000000000000000000000000000000000000000..c8d63c7aa19be532a37c735c373998fd4ec8aa4b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/debugmgr/texteval/TextEvalSyntaxView.java
@@ -0,0 +1,136 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.debugmgr.texteval;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.text.Element;
+import javax.swing.text.Segment;
+import javax.swing.text.TabExpander;
+import javax.swing.text.Utilities;
+
+import bluej.Config;
+import bluej.editor.moe.BlueJSyntaxView;
+import bluej.editor.moe.MoeSyntaxDocument;
+
+/**
+ * Syntax colouring for the codepad.
+ *
+ * @author Bruce Quig
+ * @author Michael Kolling
+ *
+ * @version $Id: TextEvalSyntaxView.java 9133 2011-07-27 04:19:22Z davmac $
+ */
+
+public class TextEvalSyntaxView extends BlueJSyntaxView
+{
+    public static final short TAG_WIDTH = 14;
+    protected static final int BREAKPOINT_OFFSET = TAG_WIDTH + 2;
+    protected static final int LEFT_MARGIN = BREAKPOINT_OFFSET;
+
+    // Attributes for lines and document
+    public static final String OUTPUT = "output";
+    public static final String ERROR = "error";
+    public static final String CONTINUE = "continue";
+    public static final String OBJECT = "object-ref";
+
+    static final Image promptImage =
+        Config.getImageAsIcon("image.eval.prompt").getImage();
+    static final Image continueImage =
+        Config.getImageAsIcon("image.eval.continue").getImage();
+    static final Image objectImage =
+        Config.getImageAsIcon("image.eval.object").getImage();
+
+    static final Color outputColor = new Color(0, 120, 0);
+    static final Color errorColor = new Color(200, 0, 20);
+    
+    /**
+     * Creates a new TextEvalSyntaxView for painting the specified element.
+     * @param elem The element
+     */
+    public TextEvalSyntaxView(Element elem)
+    {
+        super(elem, LEFT_MARGIN);
+    }
+
+    /**
+     * Draw a line for the text eval area.
+     */
+    public void paintTaggedLine(Segment lineText, int lineIndex, Graphics g, int x, int y, 
+            MoeSyntaxDocument document, Color def, Element line, TabExpander tx) 
+    {
+        if(hasTag(line, OUTPUT)) {
+            g.setColor(outputColor);
+            Utilities.drawTabbedText(lineText, x, y, g, tx, 0);
+        }
+        else if(hasTag(line, ERROR)) {
+            g.setColor(errorColor);
+            Utilities.drawTabbedText(lineText, x, y, g, tx, 0);
+        }
+        else if(hasObject(line, OBJECT)) {
+            g.drawImage(objectImage, x-1-BREAKPOINT_OFFSET, y+3-objectImage.getHeight(null), null);
+            g.setColor(outputColor);
+            Utilities.drawTabbedText(lineText, x, y, g, tx, 0);
+        }
+        else if(hasTag(line, CONTINUE)) {
+            g.drawImage(continueImage, x-1-BREAKPOINT_OFFSET, y+3-continueImage.getHeight(null), null);
+            paintSyntaxLine(lineText, lineIndex, x, y, g, 
+                    document, def, tx);   
+        }
+        else {
+            g.drawImage(promptImage, x-1-BREAKPOINT_OFFSET, y+3-promptImage.getHeight(null), null);
+            paintSyntaxLine(lineText, lineIndex, x, y, g, 
+                    document, def, tx);   
+        }
+    }
+    
+    /**
+     * Check whether a given line is tagged with a given tag.
+     * @param line The line to check
+     * @param tag  The name of the tag
+     * @return     True, if the tag is set
+     */
+    protected final boolean hasObject(Element line, String tag)
+    {
+        return line.getAttributes().getAttribute(tag) != null;
+    }
+    
+    /**
+     * redefined paint method to paint breakpoint area
+     */
+    public void paint(Graphics g, Shape allocation)
+    {
+        Rectangle bounds = allocation.getBounds();
+
+        // paint the lines
+        super.paint(g, allocation);
+
+        // paint the tag separator line
+        g.setColor(Color.lightGray);
+        g.drawLine(bounds.x + TAG_WIDTH, 0,
+                bounds.x + TAG_WIDTH, bounds.y + bounds.height);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/Editor.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/Editor.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ee9719455e4b900732a82d1968d1186230111af
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/Editor.java
@@ -0,0 +1,390 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor;
+
+import java.awt.Rectangle;
+import java.awt.print.PrinterJob;
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+
+import bluej.compiler.Diagnostic;
+import bluej.parser.SourceLocation;
+import bluej.parser.nodes.ParsedCUNode;
+
+
+/**
+ * Interface between an editor and the rest of BlueJ
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ */
+public interface Editor
+{
+    /**
+     * Read a file into the editor buffer and show the editor. If the editor
+     * already contains text, it is cleared first. If the file cannot be read,
+     * the editor should not be displayed.
+     * 
+     * @param filename    the file to be read
+     * @param compiled    true if this is a compiled class
+     * 
+     * @return false is there was a problem, true otherwise
+     */
+    boolean showFile(String filename, Charset charset, boolean compiled, String docFilename, Rectangle bounds);
+
+    /**
+     * Reload and display the same file that was displayed before.
+     * This should generated a modificationEvent followed by a saveEvent.
+     */
+    void reloadFile();
+
+    /**
+     * Clear the current buffer. The editor is not redisplayed after a call to
+     * this function. It is typically used in a sequence "clear; [insertText];
+     * show".
+     */
+    void clear();
+
+    /**
+     * Insert a string into the buffer. The editor is not immediately
+     * redisplayed. This function is typically used in a sequence "clear;
+     * [insertText]; show".
+     * 
+     * @param text        the text to be inserted
+     * @param caretBack    move the caret to the beginning of the inserted text
+     */
+    void insertText(String text, boolean caretBack);
+
+    /**
+     * Set the selection of the editor to be a len characters on the line
+     * lineNumber, starting with column columnNumber
+     * 
+     * @param lineNumber the line to select characters on
+     * @param column the column to start selection at (1st column is 1 - not 0)
+     * @param len the number of characters to select
+     */
+    void setSelection(int lineNumber, int column, int len);
+
+    /**
+     * Request to the editor to mark the text between begin and end as selected.
+     *
+     * @param  begin                      where to start the selection
+     * @param  end                        where to end the selection
+     * @throws  IllegalArgumentException  if either of the specified TextLocations
+     * represent a position which does not exist in the text.
+     */
+    public void setSelection(SourceLocation begin, SourceLocation end);
+    
+    /**
+     * Set the selection of the editor to be a len characters on the line
+     * lineNumber, starting with column columnNumber
+     * 
+     * @param lineNumber the line to select characters on
+     * @param column the column to start selection at (1st column is 1 - not 0)
+     * @param len the number of characters to select
+     */
+    void setSelection(int firstlineNumber, int firstColumn,
+                      int secondLineNumber, int SecondColumn);
+
+    /**
+     * Show the editor window. This includes whatever is necessary of the
+     * following: make visible, de-iconify, bring to front of window stack.
+     * 
+     * @param vis  true to make the editor visible, or false to hide it.
+     */
+    void setVisible(boolean vis);
+
+    /**
+     * True is the editor is on screen.
+     * 
+     * @return true if editor is on screen
+     */
+    boolean isShowing();
+
+    /**
+     * Save the buffer to disk under the current file name. This is an error if
+     * the editor has not been given a file name (ie. if readFile was not
+     * executed).
+     * 
+     * If save() is called on an unmodified file, it returns immediately without
+     * re-writing the file to disk.
+     */
+    void save() throws IOException;
+
+    /**
+     * Close the editor window.
+     */
+    void close();
+
+    /**
+     * Refresh the editor display (needed if font size has changed)
+     */
+    void refresh();
+
+    /**
+     * Display a message (used for compile/runtime errors). An editor must
+     * support at least two lines of message text, so the message can contain
+     * a newline character.
+     * 
+     * @param message    the message to be displayed
+     * @param lineNumber    the line to move the cursor to (the line is also
+     *        highlighted)
+     * @param column        the column to move the cursor to
+     * @param beep        if true, do a system beep
+     * @param setStepMark    if true, set step mark (for single stepping)
+     * @param help        name of help group (may be null); this should be the compiler
+     *                    name such as "javac".
+     */
+    void displayMessage(String message, int lineNumber, int column, 
+                        boolean beep, boolean setStepMark, String help);
+
+    /**
+     * Display a diagnostic message from the compiler.
+     * 
+     * @param diagnostic  The diagnostic to be displayed.
+     */
+    void displayDiagnostic(Diagnostic diagnostic);
+    
+    /**
+     *  Display a message into the info area.
+     *  The message will be cleared when the caret is moved.
+     *  
+     *  @param msg the message to display
+     */
+    public void writeMessage(String msg);
+
+
+    /**
+     * Remove the step mark (the mark that shows the current line when
+     * single-stepping through code). If it is not currently displayed, do
+     * nothing.
+     */
+    void removeStepMark();
+
+    /**
+     * Change class name.
+     * 
+     * @param title        new window title
+     * @param filename     new file name
+     * @param docFileName  new documentation file name
+     */
+    void changeName(String title, String filename, String docFileName);
+
+    /**
+     * Set the "compiled" status
+     * 
+     * @param compiled    true if the class has been compiled
+     */
+    void setCompiled(boolean compiled);
+
+    /**
+     * All breakpoints have been cleared for this class, update the
+     * editor display to reflect this.
+     */
+    void removeBreakpoints();
+    
+    /**
+     * Breakpoints have been reset due to compilation or
+     * similar. Re-initialize the breakpoints by re-setting them via the
+     * EditorWatcher interface.
+     */
+    void reInitBreakpoints();
+
+    /**
+     * Determine whether this editor has been modified from the version on disk
+     * 
+     * @return a boolean indicating whether the file is modified
+     */
+    boolean isModified();
+
+    /**
+     * Prints the contents of the editor
+     */
+    void print(PrinterJob printerJob);
+
+    /**
+     * Set the 'read-only' property of this editor.
+     * @param readOnlyStatus  If true, editor is non-editable.
+     */
+    void setReadOnly(boolean readOnly);
+
+    /**
+     * Test if this editor is 'read-only'.
+     * @return the readOnlyStatus. If true, editor is non-editable.
+     */
+    boolean isReadOnly();
+    
+    /**
+     * Set the view of this editor to display either the source or the interface
+     * of the class.
+     * @param interfaceStatus If true, display class interface, otherwise source.
+     */
+    void showInterface(boolean interfaceStatus);
+
+    /**
+     *  Tell whether the editor is currently displaying the interface or the
+     *  source of the class.
+     *  @return  True, if interface is currently shown, false otherwise.
+     */
+    boolean isShowingInterface();
+
+    /**
+     * Gets the bounds for this editor window.
+     * This method is used to store the bounds between sessions.
+     * 
+     * @return The bounds
+     */
+    Rectangle getBounds();
+    
+    /**
+     * Get the source document that this editor is currently editing. Certain
+     * operations (such as reload) might change the document; that is, the
+     * returned document may become invalid at some later point in time.
+     * 
+     * @return  the document being edited.
+     */
+    Document getSourceDocument(); 
+
+    /**
+     * Returns the current caret location within the edited text.
+     *
+     * @return    the LineColumn object.
+     */
+    public SourceLocation getCaretLocation();
+    
+    /**
+     * Sets the current Caret location within the edited text.
+     *
+     * @param  location                   The location in the text to set the Caret to.
+     * @throws  IllegalArgumentException  if the specified TextLocation represents a position which does not exist in the text.
+     */
+    public void setCaretLocation(SourceLocation location);
+
+
+    /**
+     * Returns the location at which current selection begins.
+     *
+     * @return    the current beginning of the selection or null if no text is selected.
+     */
+    public SourceLocation getSelectionBegin();
+    
+    /**
+     * Returns the location where the current selection ends.
+     *
+     * @return    the current end of the selection or null if no text is selected.
+     */
+    public SourceLocation getSelectionEnd();
+
+    /**
+     * Returns the text which lies between the two LineColumn.
+     *
+     * @param  begin                      The beginning of the text to get
+     * @param  end                        The end of the text to get
+     * @return                            The text value
+     * @throws  IllegalArgumentException  if either of the specified SourceLocations represent a position which does not exist in the text.
+     */
+    public String getText( SourceLocation begin, SourceLocation end );    
+
+    /**
+     * Request to the editor to replace the text between beginning and end with the given newText
+     * If begin and end points to the same location, the text is inserted.
+     *
+     * @param  begin                      where to start to replace
+     * @param  end                        where to end to replace
+     * @param  newText                    The new text value
+     * @throws  IllegalArgumentException  if either of the specified LineColumn
+     * represent a position which does not exist in the text.
+     * @throws  BadLocationException  if internally the text points outside a location in the text.
+     */
+    public void setText(SourceLocation begin, SourceLocation end, String newText)
+        throws BadLocationException;
+        
+    /**
+     * Returns the LineColumn object from the given offset in the text.
+     *
+     * @return    the LineColumn object or null if the offset points outside the text.
+     */
+    public SourceLocation getLineColumnFromOffset(int offset);
+    
+    /**
+     * Translates a LineColumn into an offset into the text held by the editor.
+     *
+     * @param  location  position to be translated
+     * @return           the offset into the content of this editor
+     * @throws  IllegalArgumentException  if the specified LineColumn
+     * represent a position which does not exist in the text.
+     */
+    public int getOffsetFromLineColumn(SourceLocation location);
+    
+    /**
+     * Returns a property of the current editor.
+     *
+     * @param  propertyKey  The propertyKey of the property to retrieve.
+     * @return              the property value or null if it is not found
+     */
+    public Object getProperty(String propertyKey);
+
+    /**
+     * Set a property for the current editor. Any existing property with
+     * this key will be overwritten.
+     *
+     * @param  propertyKey  The property key of the new property
+     * @param  value        The new property value
+     */
+    public void setProperty(String propertyKey, Object value);
+    
+    /**
+     * Returns the length of the line indicated in the edited text.
+     *
+     * @param  line  the line in the text for which the length should be calculated, starting from 0
+     * @return       the length of the line, -1 if line is invalid
+     */
+    public int getLineLength(int line);
+    
+    /**
+     * Return the number of lines in the document.
+     */
+    public int numberOfLines();
+    
+    /**
+     * Returns the length of the data.  This is the number of
+     * characters of content that represents the users data.
+     *
+     * It is possible to obtain the line and column of the last character of text by using
+     * the getLineColumnFromOffset() method.
+     *
+     * @return the length >= 0
+     */
+    public int getTextLength ();    
+    
+    /**
+     * Get a node representing the the parsed structure of the source
+     * document as a tree.
+     * 
+     * @return A ParsedNode instance, or null if not supported.
+     */
+    public ParsedCUNode getParsedNode();
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/EditorManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/EditorManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..a755207f36a1dce0d6623ac14ce3bffdfdc45da6
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/EditorManager.java
@@ -0,0 +1,112 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor;
+
+import java.awt.Rectangle;
+import java.nio.charset.Charset;
+
+import bluej.editor.moe.MoeEditorManager;
+import bluej.parser.entity.EntityResolver;
+import bluej.pkgmgr.JavadocResolver;
+
+/**
+ * Interface between the editor manager and the rest of BlueJ.
+ *
+ * @author  Michael Cahill
+ * @author  Michael Kolling
+ * @author  Bruce Quig
+ * @version $Id: EditorManager.java 8887 2011-04-21 03:29:25Z davmac $
+ */
+public abstract class EditorManager
+{
+
+    private static EditorManager theEditorManager = new MoeEditorManager();
+
+    /**
+     * Singleton factory method to return an EditorManager instance;
+     *
+     * @returns the singleton EditorManager instance
+     */
+    public static EditorManager getEditorManager()
+    {
+        return theEditorManager;
+    }
+
+    /**
+     * Open an editor to display a class. The filename may be "null"
+     * to open an empty editor (e.g. for displaying a view). The editor
+     * is initially hidden; a call to "Editor.show()" is needed to make
+     * it visible after opening it.
+     *
+     * @param filename     name of the source file to open (may be null)
+     * @param docFilename  name of the corresponding javadoc file
+     * @param charset      the character set of the file contents 
+     * @param windowTitle  title of window (usually class name)
+     * @param watcher      an watcher to be notified of edit events
+     * @param compiled     true, if the class has been compiled
+     * @param bounds       the bounds of the window to appear on screen
+     * @param projectResolver   A resolver for external symbols
+     * @param javadocResolver   A resolver for javadoc on external methods
+     * 
+     * @return          the new editor, or null if there was a problem
+     */
+    public abstract Editor openClass(String filename, 
+        String docFilename,
+        Charset charset,
+        String windowTitle, 
+        EditorWatcher watcher, 
+        boolean compiled, 
+        Rectangle bounds,
+        EntityResolver projectResolver,
+        JavadocResolver javadocResolver);
+
+
+    /**
+     * Open an editor to display a text document. The difference to
+     * "openClass" is that code specific functions (such as compile,
+     * debug, view) are disabled in the editor. The filename may be
+     * "null" to open an empty editor. The editor is initially hidden.
+     * A call to "Editor::show" is needed to make is visible after
+     * opening it.
+     *
+     * @param filename          name of the source file to open (may be null)
+     * @param windowTitle       title of window (usually class name)
+     * @param watcher           an object interested in editing events
+     * @returns                 the new editor, or null if there was a problem
+     */
+    public abstract Editor openText(String filename, Charset charset, String windowTitle,
+                                    Rectangle bounds );
+
+    /**
+     * Indicate to the manager that all resources used by this editor
+     * should be discarded.
+     */
+    protected abstract void discardEditor(Editor ed);
+
+    /**
+     * Refresh the display of all showing editors (usually because
+     * an editor property such as font has changed)
+     */
+    public abstract void refreshAll();
+
+
+} // end interface EditorManager
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/EditorWatcher.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/EditorWatcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..596dc8f7ce3d50550e3c48f766c17e3c6c02bbb6
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/EditorWatcher.java
@@ -0,0 +1,77 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor;
+
+
+/**
+ * @author Michael Kolling
+ * Interface between the editor and the rest of BlueJ
+ * The editor uses this class
+ */
+public interface EditorWatcher
+{
+    //key for storing the value of the expand/collapse of the naviview
+    public final static String NAVIVIEW_EXPANDED_PROPERTY="naviviewExpandedProperty";
+    /**
+     * Called by Editor when a file is changed
+     */
+    void modificationEvent(Editor editor);
+
+    /**
+     * Called by Editor when a file is saved
+     */
+    void saveEvent(Editor editor);
+
+    /**
+     * Called by Editor when it is closed
+     */
+    void closeEvent(Editor editor);
+
+    /**
+     * Called by Editor to set/clear a breakpoint
+     * @param lineNo the line number of the breakpoint
+     * @param set    whether the breakpoint is set (true) or cleared
+     * @return             An error message or null if okay.
+     */
+    String breakpointToggleEvent(Editor editor, int lineNo, 
+                                 boolean set);
+
+    /**
+     * Called by Editor when a file is to be compiled
+     */
+    void compile(Editor editor);
+    
+    /**
+     * Called by Editor when documentation is to be compiled
+     */
+    void generateDoc();  
+    
+    /**
+     * Sets a property
+     */
+    void setProperty(String key, String value);
+    
+    /**
+     * Gets a property
+     */
+    String getProperty(String key);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/AdvancedHighlightPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/AdvancedHighlightPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce7216a67f2afad0afd44b00dacee124e92871f2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/AdvancedHighlightPainter.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Graphics;
+import java.awt.Shape;
+
+import javax.swing.text.JTextComponent;
+import javax.swing.text.View;
+
+/**
+ * An "advanced" highlight painter, usable with {@link MoeHighlighter}
+ * 
+ * @author Davin McCall
+ */
+public interface AdvancedHighlightPainter
+{
+    /**
+     * Paint the highlight
+     * 
+     * @param g   The graphics context to paint to
+     * @param p0   The position where the highlight starts
+     * @param p1   The position where the highlight ends
+     * @param viewBounds  The view bounds of the root view within the component
+     * @param editor  The component on which the highlight is being painted
+     * @param view  The root view
+     */
+    public void paint(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor, View view);
+    
+    /**
+     * Issue a repaint for the area covered by the highlight.
+     * 
+     * @param p0  The position where the highlight starts
+     * @param p1  The position where the highlight ends
+     * @param viewBounds  The view bounds of the root view within the component
+     * @param editor      The component to repaint
+     * @param rootViwe  The root view
+     */
+    public void issueRepaint(int p0, int p1, Shape viewBounds, JTextComponent editor, View rootView);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/BlueJSyntaxView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/BlueJSyntaxView.java
new file mode 100644
index 0000000000000000000000000000000000000000..3264f52f2d2c0fd0d911e9e41ecbd8a1081e6627
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/BlueJSyntaxView.java
@@ -0,0 +1,1593 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.Toolkit;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Stack;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentEvent.ElementChange;
+import javax.swing.event.DocumentEvent.EventType;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.Position;
+import javax.swing.text.Segment;
+import javax.swing.text.TabExpander;
+import javax.swing.text.Utilities;
+import javax.swing.text.ViewFactory;
+
+import bluej.editor.moe.MoeSyntaxEvent.NodeChangeRecord;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+import bluej.parser.nodes.ParsedCUNode;
+import bluej.parser.nodes.ParsedNode;
+import bluej.prefmgr.PrefMgr;
+
+/**
+ * A Swing view implementation that does syntax colouring and adds some utility.
+ *
+ * <p>A BlueJSyntaxView (or subclass) instance is normally created by an implementation of
+ * the EditorKit interface.
+ * 
+ * <p>The original version of this class was based on SyntaxView from JEdit. Little of
+ * that code remains.
+ *
+ * @author Slava Pestov
+ * @author Bruce Quig
+ * @author Michael Kolling
+ * @author Davin McCall
+ */
+public abstract class BlueJSyntaxView extends MoePlainView
+{
+    /** (NaviView) Paint method inner scope? if false, whole method will be highlighted as a single block */
+    private static final boolean PAINT_METHOD_INNER = false;
+
+    private static final int LEFT_INNER_SCOPE_MARGIN = 5;
+    private static final int LEFT_OUTER_SCOPE_MARGIN = 2;
+    private static final int RIGHT_SCOPE_MARGIN = 4;
+    private static int strength = PrefMgr.getScopeHighlightStrength();
+    
+    {
+        MoeSyntaxDocument.getColors(); // initialize colors
+        resetColors();
+    }
+
+    /* Scope painting colours */
+    public static final Color GREEN_BASE = new Color(225, 248, 225);
+    public static final Color BLUE_BASE = new Color(233, 233, 248);
+    public static final Color YELLOW_BASE = new Color(250, 250, 180);
+    public static final Color PINK_BASE = new Color(248, 233, 248);
+    public static final Color GREEN_OUTER_BASE = new Color(188, 218, 188);
+    public static final Color BLUE_OUTER_BASE = new Color(188, 188, 210);
+    public static final Color YELLOW_OUTER_BASE = new Color(215, 215, 205);
+    public static final Color PINK_OUTER_BASE = new Color(210, 177, 210);
+    public static final Color GREEN_INNER_BASE = new Color(210, 230, 210);
+    
+    /* The following are initialized by resetColors() */
+    private static Color C1; // green border (container)
+    private static Color C2; // green wash
+    private static Color C3; // green border (inner).
+
+    private static Color M1; // yellow border (methods)
+    private static Color M2; // yellow wash
+
+    private static Color S1; // blue border (selection)
+    private static Color S2; // blue wash
+
+    private static Color I1; // pink border (iteration)
+    private static Color I2; // pink wash
+
+
+    /** System settings for graphics rendering (inc. font antialiasing etc.) */
+    private static Map<?,?> desktopHints = null;
+
+    // private members
+    private Segment line;
+
+    protected Font defaultFont;
+    private boolean initialised = false;
+
+    private Map<ParsedNode,Integer> nodeIndents = new HashMap<ParsedNode,Integer>();
+
+
+    /**
+     * Creates a new BlueJSyntaxView.
+     * @param elem The element
+     */
+    public BlueJSyntaxView(Element elem, int leftMargin)
+    {
+        super(elem, leftMargin);
+        line = new Segment();
+    }
+
+    @Override
+    public void paint(Graphics g, Shape a)
+    {
+        if (desktopHints != null && g instanceof Graphics2D) {
+            Graphics2D g2d = (Graphics2D) g;
+            g2d.addRenderingHints(desktopHints); 
+        }
+
+        super.paint(g, a);
+    }
+
+    /*
+     * Paints the specified line. This is called by the paint() method from PlainView.
+     *
+     * @param lineIndex The line number (0 based).
+     * @param g The graphics context
+     * @param x The x co-ordinate where the line should be painted
+     * @param y The y co-ordinate (baseline) where the line should be painted
+     */
+    @Override
+    protected void drawLine(int lineIndex, Graphics g, int x, int y)
+    {
+        if(!initialised) {
+            initialise(g);
+        }
+
+        MoeSyntaxDocument document = (MoeSyntaxDocument)getDocument();
+
+        Color def = MoeSyntaxDocument.getDefaultColor();
+        TabExpander tx = new MoeTabExpander(tabSize, x);
+
+        try {
+            Element lineElement = getElement().getElement(lineIndex);
+            int start = lineElement.getStartOffset();
+            int end = lineElement.getEndOffset();
+
+            document.getText(start, end - (start + 1), line);
+            g.setColor(def);
+
+            paintTaggedLine(line, lineIndex, g, x, y, document, def, lineElement, tx);
+        }
+        catch (BadLocationException bl) {
+            // shouldn't happen
+            throw new RuntimeException(bl);
+        }
+    }
+
+    /**
+     * Paint a line of text, without syntax colouring. This is provided as a convenience for subclasses.
+     */
+    protected void paintPlainLine(int lineIndex, Graphics g, int x, int y)
+    {
+        super.drawLine(lineIndex, g, x, y);
+    }
+
+    /**
+     * Draw a line for this view. Default implementation defers to paintSyntaxLine().
+     * @param x  The x co-ordinate of the line, where the text is to begin (i.e. the margin area is
+     *           to the left of this point)
+     */
+    protected void paintTaggedLine(Segment line, int lineIndex, Graphics g, int x, int y, 
+            MoeSyntaxDocument document, Color def, Element lineElement, TabExpander tx)
+    {
+        paintSyntaxLine(line, lineIndex, x, y, g, document, def, tx);
+    }
+
+    /**
+     * Paints a line with syntax highlighting,
+     * @param x  The x co-ordinate of the line, where the text is to begin (i.e. the margin area is
+     *           to the left of this point)
+     */
+    protected final void paintSyntaxLine(Segment line, int lineIndex, int x, int y,
+            Graphics g, MoeSyntaxDocument document, 
+            Color def, TabExpander tx)
+    {
+        Color[] colors = MoeSyntaxDocument.getColors();
+        Token tokens = document.getTokensForLine(lineIndex);
+        int offset = 0;
+        for(;;) {
+            byte id = tokens.id;
+            if(id == Token.END)
+                break;
+
+            int length = tokens.length;
+            Color color;
+            if (id == Token.NULL || id >= colors.length) {
+                color = def;
+            }
+            else {
+                color = colors[id];
+            }
+            g.setColor(color);
+            line.count = length;
+            
+            x = Utilities.drawTabbedText(line,x,y,g,tx,offset);
+            line.offset += length;
+            offset += length;
+
+            tokens = tokens.next;
+        }
+    }
+
+    protected final void paintScopeMarkers(Graphics g, MoeSyntaxDocument document, Shape a,
+            int firstLine, int lastLine, boolean onlyMethods)
+    {
+        paintScopeMarkers(g, document, a, firstLine, lastLine, onlyMethods, false);
+    }
+
+    /**
+     * A container for three line segments and elements: the previous (or above) line, the
+     * current line, and the next (or below) line.
+     */
+    private class ThreeLines
+    {
+        Segment aboveLineSeg;
+        Segment thisLineSeg;
+        Segment belowLineSeg;
+
+        Element aboveLineEl;
+        Element thisLineEl;
+        Element belowLineEl;
+    }
+
+    protected void paintScopeMarkers(Graphics g, MoeSyntaxDocument document, Shape a,
+            int firstLine, int lastLine, boolean onlyMethods, boolean small)
+    {
+        if (strength == 0) {
+            return;
+        }
+        
+        Element map = document.getDefaultRootElement();
+        ParsedNode rootNode = document.getParsedNode();
+        Rectangle clipBounds = g.getClipBounds();
+        if (clipBounds == null) {
+            clipBounds = a.getBounds();
+        }
+        int char_width = metrics.charWidth('m');
+
+        int aboveLine = firstLine - 1;
+        List<NodeAndPosition<ParsedNode>> prevScopeStack = new LinkedList<NodeAndPosition<ParsedNode>>();
+        int curLine = firstLine;
+
+        try {
+            ThreeLines lines = new ThreeLines();
+            lines.aboveLineSeg = new Segment();
+            lines.thisLineSeg = new Segment();
+            lines.belowLineSeg = new Segment();
+
+            lines.aboveLineEl = null;
+            lines.thisLineEl = map.getElement(firstLine);
+            if (aboveLine >= 0) {
+                lines.aboveLineEl = map.getElement(aboveLine);
+                document.getText(lines.aboveLineEl.getStartOffset(),
+                        lines.aboveLineEl.getEndOffset() - lines.aboveLineEl.getStartOffset(),
+                        lines.aboveLineSeg);
+            }
+            lines.belowLineEl = null;
+            if (firstLine + 1 < map.getElementCount()) {
+                lines.belowLineEl = map.getElement(firstLine + 1);
+                document.getText(lines.belowLineEl.getStartOffset(),
+                        lines.belowLineEl.getEndOffset() - lines.belowLineEl.getStartOffset(),
+                        lines.belowLineSeg);
+            }
+
+            document.getText(lines.thisLineEl.getStartOffset(),
+                    lines.thisLineEl.getEndOffset() - lines.thisLineEl.getStartOffset(),
+                    lines.thisLineSeg);
+
+            getScopeStackAfter(rootNode, 0, lines.thisLineEl.getStartOffset(), prevScopeStack);
+
+            while (curLine <= lastLine) {
+
+                if (prevScopeStack.size() == 0) {
+                    break;
+                }
+
+                drawScopes(a, g, document, lines, char_width, prevScopeStack, small, onlyMethods, 0);
+
+                // Next line
+                curLine++;
+                if (curLine <= lastLine) {
+                    lines.aboveLineEl = lines.thisLineEl;
+                    lines.thisLineEl = lines.belowLineEl; 
+                    if (curLine + 1 < map.getElementCount()) {
+                        lines.belowLineEl = map.getElement(curLine + 1);
+                    }
+                    else {
+                        lines.belowLineEl = null;
+                    }
+                    Segment oldAbove = lines.aboveLineSeg;
+                    lines.aboveLineSeg = lines.thisLineSeg;
+                    lines.thisLineSeg = lines.belowLineSeg;
+                    lines.belowLineSeg = oldAbove; // recycle the object
+
+                    if (lines.belowLineEl != null) {
+                        document.getText(lines.belowLineEl.getStartOffset(),
+                                lines.belowLineEl.getEndOffset() - lines.belowLineEl.getStartOffset(),
+                                lines.belowLineSeg);
+                    }
+                }
+            }
+        }
+        catch (BadLocationException ble) {}
+    }
+
+    private class DrawInfo
+    {
+        Graphics g;
+        ThreeLines lines;
+        boolean small;
+
+        ParsedNode node;
+        int ypos;
+        int ypos2;
+        boolean starts;  // the node starts on the current line
+        boolean ends;    // the node ends on the current line
+        Color color1;    // Edge colour
+        Color color2;    // Fill colour
+    }
+
+    /**
+     * Draw the scope highlighting for one line of the document.
+     * 
+     * @param a              the shape to render into
+     * @param g              the graphics context to render to
+     * @param document       the document
+     * @param lines          the previous, current and next lines (segments and elements)
+     * @param prevScopeStack the stack of nodes (from outermost to innermost) at the beginning of the current line
+     */
+    private void drawScopes(Shape a, Graphics g, MoeSyntaxDocument document, ThreeLines lines,
+            int charWidth, List<NodeAndPosition<ParsedNode>> prevScopeStack, boolean small,
+            boolean onlyMethods, int nodeDepth)
+    throws BadLocationException
+    {
+        Rectangle clipBounds = g.getClipBounds();
+        if (clipBounds == null) {
+            clipBounds = a.getBounds();
+        }
+
+        Rectangle lbounds = modelToView(lines.thisLineEl.getStartOffset(), a,
+                Position.Bias.Forward).getBounds();
+        int ypos = lbounds.y;
+        int ypos2 = ypos + lbounds.height;
+
+        int rightMargin = small ? 0 : 20;
+        int fullWidth = a.getBounds().width + a.getBounds().x;
+
+        ListIterator<NodeAndPosition<ParsedNode>> li = prevScopeStack.listIterator();
+        //Color lastLineColor = C3;
+
+        NodeAndPosition<ParsedNode> parent = null;
+
+        DrawInfo drawInfo = new DrawInfo();
+        drawInfo.g = g;
+        drawInfo.lines = lines;
+        drawInfo.small = small;
+        drawInfo.ypos = ypos;
+        drawInfo.ypos2 = ypos2;
+
+        while (li.hasNext()) {
+            NodeAndPosition<ParsedNode> nap = li.next();
+            int napPos = nap.getPosition();
+            int napEnd = nap.getEnd();
+
+            if (napPos >= lines.thisLineEl.getEndOffset()) {
+                // The node isn't even on this line, go to the next line
+                break;
+            }
+
+            if (nodeSkipsEnd(napPos, napEnd, lines.thisLineEl, lines.thisLineSeg)) {
+                break;
+            }
+
+            if (! drawNode(drawInfo, nap, parent, onlyMethods)) {
+                parent = nap;
+                continue;
+            }
+
+            // Draw the start node
+            int xpos = getNodeIndent(a, document, nap, lines.thisLineEl,
+                    lines.thisLineSeg);
+            boolean starts = nodeSkipsStart(nap, lines.aboveLineEl, lines.aboveLineSeg);
+            boolean ends = nodeSkipsEnd(napPos, napEnd, lines.belowLineEl, lines.belowLineSeg);
+            int rbound = getNodeRBound(a, nap, fullWidth - rightMargin, nodeDepth,
+                    lines.thisLineEl, lines.thisLineSeg);
+
+            drawInfo.node = nap.getNode();
+            drawInfo.starts = starts;
+            drawInfo.ends = ends;
+            Color [] colors = colorsForNode(drawInfo.node);
+            drawInfo.color1 = colors[0];
+            drawInfo.color2 = colors[1];
+
+            if (xpos != - 1 && xpos <= a.getBounds().x + a.getBounds().width) {
+                drawScopeLeft(drawInfo, xpos, rbound);
+                drawScopeRight(drawInfo, rbound);
+            }
+            nodeDepth++;
+
+            //lastNodePos = nap;
+        }
+
+        // Move along.
+        li = prevScopeStack.listIterator(prevScopeStack.size());
+        NodeAndPosition<ParsedNode> nap = li.previous(); // last node
+        int napPos = nap.getPosition();
+        int napEnd = napPos + nap.getSize();
+
+        // For nodes which end on this line:
+        while (napEnd <= lines.thisLineEl.getEndOffset()) {
+            // Node ends this line
+            li.remove(); nodeDepth--;
+
+            if (! li.hasPrevious()) return;
+            NodeAndPosition<ParsedNode> napParent = li.previous();
+            li.next();
+
+            NodeAndPosition<ParsedNode> nextNap = nap.nextSibling();
+            napPos = napParent.getPosition();
+            napEnd = napPos + napParent.getSize();
+            nap = napParent;
+
+            while (nextNap != null) {
+                li.add(nextNap);
+                li.previous(); li.next();  // so remove works
+                nodeDepth++;
+                napPos = nextNap.getPosition();
+                napEnd = napPos + nextNap.getSize();
+                if (! nodeSkipsStart(nextNap, lines.thisLineEl, lines.thisLineSeg)) {
+                    if (drawNode(drawInfo, nextNap, napParent, onlyMethods)) {
+                        // Draw it
+                        int xpos = getNodeIndent(a, document, nextNap, lines.thisLineEl,
+                                lines.thisLineSeg);
+                        int rbound = getNodeRBound(a, nextNap, fullWidth - rightMargin, nodeDepth,
+                                lines.thisLineEl, lines.thisLineSeg);
+                        drawInfo.node = nextNap.getNode();
+                        Color [] colors = colorsForNode(drawInfo.node);
+                        drawInfo.color1 = colors[0];
+                        drawInfo.color2 = colors[1];
+                        drawInfo.starts = nodeSkipsStart(nextNap, lines.aboveLineEl,
+                                lines.aboveLineSeg);
+                        drawInfo.ends = nodeSkipsEnd(napPos, napEnd, lines.belowLineEl,
+                                lines.belowLineSeg);
+
+                        if (xpos != -1 && xpos <= a.getBounds().x + a.getBounds().width) {
+                            drawScopeLeft(drawInfo, xpos, rbound);
+                            drawScopeRight(drawInfo, rbound);
+                        }
+                    }
+                }
+
+                nap = nextNap;
+                nextNap = nextNap.getNode().findNodeAtOrAfter(napPos, napPos);
+            }
+        }
+    }
+
+    /**
+     * Check whether a node needs to be drawn.
+     * @param info
+     * @param node
+     * @return
+     */
+    private boolean drawNode(DrawInfo info, NodeAndPosition<ParsedNode> nap, NodeAndPosition<ParsedNode> parent, boolean onlyMethods)
+    {
+        int napPos = nap.getPosition();
+        int napEnd = napPos + nap.getSize();
+
+        if (napPos >= info.lines.thisLineEl.getEndOffset()) {
+            // The node isn't even on this line, go to the next line
+            return false;
+        }
+
+        if (! nap.getNode().isContainer() && ! nap.getNode().isInner()) {
+            return false;
+        }
+
+        if (onlyMethods) {
+            if (nap.getNode().getNodeType() == ParsedNode.NODETYPE_METHODDEF) {
+                return true;
+            }
+            if (! PAINT_METHOD_INNER) {
+                return false;
+            }
+            /*
+            if (nap.getNode().isInner() && parent != null && parent.getNode().getNodeType()
+                    == ParsedNode.NODETYPE_METHODDEF) {
+                return true;
+            }
+            return false;
+             */
+        }
+
+        if (nodeSkipsStart(nap, info.lines.thisLineEl, info.lines.thisLineSeg)) {
+            return false; // just white space on this line
+        }
+
+        if (nodeSkipsEnd(napPos, napEnd, info.lines.thisLineEl, info.lines.thisLineSeg)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Get the scope highlighting colours for a given node.
+     */
+    private Color[] colorsForNode(ParsedNode node)
+    {
+        if (node.isInner()) {
+            return new Color[] { C3, MoeSyntaxDocument.getBackgroundColor() };
+        }
+        else {
+            if (node.getNodeType() == ParsedNode.NODETYPE_METHODDEF) {
+                return new Color[] { M1, M2 };
+            }
+            if (node.getNodeType() == ParsedNode.NODETYPE_ITERATION) {
+                return new Color[] { I1, I2 };
+            }
+            if (node.getNodeType() == ParsedNode.NODETYPE_SELECTION
+                    || node.getNodeType() == ParsedNode.NODETYPE_NONE) {
+                return new Color[] { S1, S2 };
+            }
+            return new Color[] { C1, C2 };
+        }
+    }
+
+    /**
+     * Draw the left edge of the scope, and the middle part up the given bound.
+     */
+    private void drawScopeLeft(DrawInfo info, int xpos, int rbound)
+    {
+        Graphics g = info.g;
+        if (! info.small) {
+            xpos -= info.node.isInner() ? LEFT_INNER_SCOPE_MARGIN : LEFT_OUTER_SCOPE_MARGIN;
+        }
+
+        // draw node start
+        int hoffs = info.small ? 0 : 4; // determines size of corner arcs
+        //g.setColor(info.color2);
+        // g.fillRect(xpos + hoffs, info.ypos, endX - xpos - hoffs, ypos2 - ypos);
+
+        int edgeTop = info.ypos + (info.starts ? hoffs : 0);
+        int edgeBtm = info.ypos2 - (info.ends ? hoffs : 0);
+
+        g.setColor(info.color2);
+        g.fillRect(xpos, edgeTop, hoffs, edgeBtm - edgeTop);
+        g.setColor(info.color1);
+        g.drawLine(xpos, edgeTop, xpos, edgeBtm);
+
+
+        if(info.starts) {
+            // Top left corner
+            g.setColor(info.color2);
+            g.fillArc(xpos, info.ypos, hoffs * 2, hoffs * 2, 180, -90);
+
+            // Top edge
+            g.setColor(info.color1);
+            g.drawArc(xpos, info.ypos, hoffs * 2, hoffs * 2, 180, -90);
+        }
+        if(info.ends) {
+            // Bottom left corner
+            g.setColor(info.color2);
+            g.fillArc(xpos, edgeBtm - hoffs, hoffs * 2, hoffs * 2, 180, 90);
+
+            // Bottom edge
+            g.setColor(info.color1);
+            g.drawArc(xpos, edgeBtm - hoffs, hoffs * 2, hoffs * 2, 180, 90);
+            //g.drawLine(xpos + hoffs, ypos2 - 1, rbounds, ypos2 - 1);
+        }
+
+        drawScope(info, xpos + hoffs, rbound);
+    }
+
+    /**
+     * Draw the right edge of a scope.
+     */
+    private void drawScopeRight(DrawInfo info, int xpos)
+    {
+        Graphics g = info.g;
+
+        int hoffs = info.small ? 0 : 4; // determines size of corner arcs        
+        int edgeTop = info.ypos + (info.starts ? hoffs : 0);
+        int edgeBtm = info.ypos2 - (info.ends ? hoffs + 1 : 0);
+
+        g.setColor(info.color2);
+        g.fillRect(xpos, edgeTop, hoffs, edgeBtm - edgeTop);
+
+        g.setColor(info.color1);
+        g.drawLine(xpos + hoffs, edgeTop, xpos + hoffs, edgeBtm);
+
+        if(info.starts) {
+            // Top right corner
+            g.setColor(info.color2);
+            g.fillArc(xpos - hoffs, info.ypos, hoffs * 2, hoffs * 2, 0, 90);
+
+            g.setColor(info.color1);
+            g.drawArc(xpos - hoffs, info.ypos, hoffs * 2, hoffs * 2, 0, 90);
+        }
+        if(info.ends) {
+            // Bottom right corner
+            g.setColor(info.color2);
+            g.fillArc(xpos - hoffs, edgeBtm - hoffs, hoffs * 2, hoffs * 2, 0, -90);
+
+            g.setColor(info.color1);
+            g.drawArc(xpos - hoffs, edgeBtm - hoffs, hoffs * 2, hoffs * 2, 0, -90);
+        }
+    }
+
+    /**
+     * Draw the center part of a scope (not the left or right edge, but the bit in between)
+     * @param info  general drawing information
+     * @param xpos  the leftmost x-coordinate to draw from
+     * @param rbounds the rightmost x-coordinate to draw to
+     */
+    private void drawScope(DrawInfo info, int xpos, int rbounds)
+    {
+        Graphics g = info.g;
+        Color color1 = info.color1;
+        Color color2 = info.color2;
+        boolean startsThisLine = info.starts;
+        boolean endsThisLine = info.ends;
+        int ypos = info.ypos;
+        int ypos2 = info.ypos2;
+
+        // draw node start
+        g.setColor(color2);
+        g.fillRect(xpos, ypos, rbounds - xpos, ypos2 - ypos);
+
+        if(startsThisLine) {
+            // Top edge
+            g.setColor(color1);
+            g.drawLine(xpos, ypos, rbounds, ypos);
+        }
+        if(endsThisLine) {
+            // Bottom edge
+            g.setColor(color1);
+            g.drawLine(xpos, ypos2 - 1, rbounds, ypos2 - 1);
+        }
+    }
+
+    /**
+     * Find the rightmost bound of a node on a particular line.
+     * 
+     * @param a       The view allocation
+     * @param napEnd  The end of the node (position in the document just beyond the node)
+     * @param fullWidth  The full width to draw to (for the outermost mode)
+     * @param nodeDepth  The node depth
+     * @param lineEl   line element of the line to find the bound for
+     * @param lineSeg  Segment containing text of the current line
+     */
+    private int getNodeRBound(Shape a, NodeAndPosition<ParsedNode> nap, int fullWidth, int nodeDepth,
+            Element lineEl, Segment lineSeg) throws BadLocationException
+    {
+        int napEnd = nap.getEnd();
+        int rbound = fullWidth - nodeDepth * RIGHT_SCOPE_MARGIN;
+        if (lineEl == null || napEnd >= lineEl.getEndOffset()) {
+            return rbound;
+        }
+        if (napEnd < lineEl.getStartOffset()) {
+            return rbound;
+        }
+        
+        // If there is some text between the node end and the end of the line, we want to clip the
+        // node short so that the text does not appear to be part of the node.
+        int nwsb = findNonWhitespaceComment(nap, lineEl, lineSeg, napEnd - lineEl.getStartOffset());
+        if (nwsb != -1) {
+            Rectangle ebounds = modelToView(napEnd, a, Position.Bias.Backward).getBounds();
+            return Math.min(rbound, ebounds.x);
+        }
+        return rbound;
+    }
+
+    /**
+     * Checks whether the given node should be skipped on the given line (because it
+     * starts later). This takes into account that the node may "officially" start on the
+     * line, but only have white space, in which case it can be moved down to the next line.
+     */
+    private boolean nodeSkipsStart(NodeAndPosition<ParsedNode> nap, Element lineEl, Segment segment)
+    {
+        int napPos = nap.getPosition();
+        int napEnd = nap.getEnd();
+        
+        if (lineEl == null) {
+            return true;
+        }
+        if (napPos > lineEl.getStartOffset() && napEnd > lineEl.getEndOffset()) {
+            // The node officially starts on this line, but might have no text on this
+            // line. In that case, we probably want to move its start down to the next line.
+            if (napPos >= lineEl.getEndOffset()) {
+                return true;
+            }
+            int nws = findNonWhitespaceComment(nap, lineEl, segment, napPos - lineEl.getStartOffset());
+            if (nws == -1) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check whether a node which overlaps a line of the document actually finishes on the
+     * previous line, by way of not having any actual text on this line. Return true if
+     * so.
+     */
+    private boolean nodeSkipsEnd(int napPos, int napEnd, Element lineEl, Segment segment)
+    {
+        if (lineEl == null) {
+            return true;
+        }
+        if (napEnd < lineEl.getEndOffset() && napPos < lineEl.getStartOffset()) {
+            // The node officially finishes on this line, but might have no text on
+            // this line.
+            if (napEnd <= lineEl.getStartOffset()) {
+                return true;
+            }
+            if (napEnd >= lineEl.getEndOffset()) {
+                return false;
+            }
+            int nws = findNonWhitespace(segment, 0);
+            if (nws == -1 || lineEl.getStartOffset() + nws >= napEnd) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get a node's indent amount (in component co-ordinate space) for a given line.
+     * If the node isn't present on the line, returns Integer.MAX_VALUE. A cached value
+     * is used if available.
+     */
+    private int getNodeIndent(Shape a, MoeSyntaxDocument doc, NodeAndPosition<ParsedNode> nap, Element lineEl,
+            Segment segment)
+        throws BadLocationException
+    {
+        int napPos = nap.getPosition();
+        int napEnd = nap.getEnd();
+
+        if (lineEl == null) {
+            return Integer.MAX_VALUE;
+        }
+
+        if (napPos >= lineEl.getEndOffset()) {
+            return Integer.MAX_VALUE;
+        }
+
+        if (napEnd <= lineEl.getStartOffset()) {
+            return Integer.MAX_VALUE;
+        }
+
+        if (nodeSkipsStart(nap, lineEl, segment)
+                || nodeSkipsEnd(napPos, napEnd, lineEl, segment)) {
+            return Integer.MAX_VALUE;
+        }
+
+        // int indent = nap.getNode().getLeftmostIndent(doc, 0, 0);
+        Integer indent = nodeIndents.get(nap.getNode());
+        if (indent == null) {
+            indent = getNodeIndent(a, doc, nap);
+            nodeIndents.put(nap.getNode(), indent);
+        }
+
+        int xpos = indent;
+
+        // Corner case: node start position is on this line, and is greater than the node indent?
+        if (napPos > lineEl.getStartOffset()) {
+            // In this case, we'll stretch the border to the regular indent only if
+            // we can do it without hitting non-whitespace (which must belong to another node).
+            int nws = findNonWhitespaceBwards(segment, napPos - lineEl.getStartOffset() - 1, 0);
+            if (nws != -1) {
+                Rectangle lbounds = modelToView(lineEl.getStartOffset() + nws + 1, a,
+                        Position.Bias.Forward).getBounds();
+                xpos = Math.max(xpos, lbounds.x);
+            }
+        }
+
+        return xpos;
+    }
+
+    /**
+     * Calculate the indent for a node.
+     */
+    private int getNodeIndent(Shape a, MoeSyntaxDocument doc, NodeAndPosition<ParsedNode> nap)
+    {
+        try {
+            int indent = Integer.MAX_VALUE;
+
+            int curpos = nap.getPosition();
+            int napEnd = nap.getEnd();
+
+            Element map = doc.getDefaultRootElement();
+            Stack<NodeAndPosition<ParsedNode>> scopeStack = new Stack<NodeAndPosition<ParsedNode>>();
+            scopeStack.add(nap);
+
+            outer:
+            while (curpos < napEnd) {
+                // Remove any nodes from the scope stack who we have now skipped over
+                NodeAndPosition<ParsedNode> top = scopeStack.get(scopeStack.size() - 1);
+                while (top.getEnd() <= curpos) {
+                    scopeStack.remove(scopeStack.size() - 1);
+                    top = scopeStack.get(scopeStack.size() - 1);
+                }
+                
+                // Re-build the scope stack and skip inner nodes.
+                // Note, we find nodes at curpos + 1 to avoid nodes which *end* here.
+                NodeAndPosition<ParsedNode> nextChild = top.getNode().findNodeAt(curpos + 1, top.getPosition());
+                while (nextChild != null) {
+                    if (nextChild.getNode().isInner()) {
+                        curpos = nextChild.getEnd();
+                        continue outer;
+                    }
+                    scopeStack.add(nextChild);
+                    top = nextChild;
+                    nextChild = top.getNode().findNodeAt(curpos + 1, top.getPosition());
+                }
+                
+                // Ok, we've skipped inner nodes
+                int line = map.getElementIndex(curpos);
+                Element lineEl = map.getElement(line);
+                Segment segment = new Segment();
+                doc.getText(lineEl.getStartOffset(), lineEl.getEndOffset() - lineEl.getStartOffset(), segment);
+
+                int lineOffset = curpos - lineEl.getStartOffset();
+
+                int nws;
+                if (lineEl.getStartOffset() < nap.getPosition() && nap.getNode().isInner()) {
+                    // The node is an inner node starting on this line
+                    nws = findNonWhitespaceComment(nap, lineEl, segment, lineOffset);
+                } else {
+                    nws = findNonWhitespace(segment, lineOffset);
+                }
+
+                if (nws == lineOffset) {
+                    // Ok, at this position we have non-white space and are not in an inner
+                    Rectangle cbounds = modelToView(curpos, a, Position.Bias.Forward).getBounds();
+                    indent = Math.min(indent, cbounds.x);
+                    curpos = lineEl.getEndOffset();
+                }
+                else if (nws == -1) {
+                    curpos = lineEl.getEndOffset();
+                }
+                else {
+                    // We need to check for inner nodes at the adjusted position
+                    curpos += nws - lineOffset;
+                }
+            }
+
+            return indent == Integer.MAX_VALUE ? -1 : indent;
+        }
+        catch (BadLocationException ble) {
+            return -1;
+        }
+    }
+    
+    private int[] reassessIndentsAdd(Shape a, int dmgStart, int dmgEnd)
+    {
+        MoeSyntaxDocument doc = (MoeSyntaxDocument) getDocument();
+        ParsedCUNode pcuNode = doc.getParsedNode();
+        if (pcuNode == null) {
+            return new int[] {dmgStart, dmgEnd};
+        }
+        
+        Element map = doc.getDefaultRootElement();
+        int ls = map.getElementIndex(dmgStart);
+        int le = map.getElementIndex(dmgEnd);
+        Segment segment = new Segment();
+        
+        try {
+            int [] dmgRange = new int[2];
+            dmgRange[0] = dmgStart;
+            dmgRange[1] = dmgEnd;
+
+            int i = ls;
+            List<NodeAndPosition<ParsedNode>> scopeStack = new LinkedList<NodeAndPosition<ParsedNode>>();
+            int lineEndPos = map.getElement(le).getEndOffset();
+            Element lineEl = map.getElement(ls);
+            NodeAndPosition<ParsedNode> top =
+                pcuNode.findNodeAtOrAfter(lineEl.getStartOffset(), 0);
+            while (top != null && top.getEnd() == lineEl.getStartOffset()) {
+                top = top.nextSibling();
+            }
+            
+            if (top == null) {
+                // No nodes at all.
+                return dmgRange;
+            }
+            if (top.getPosition() >= lineEl.getEndOffset()) {
+                // The first node we found begins on a line following the additions.
+                i = map.getElementIndex(top.getPosition());
+                if (i > le) {
+                    return dmgRange;
+                }
+            }
+            
+            scopeStack.add(top);
+            NodeAndPosition<ParsedNode> nap = top.getNode().findNodeAtOrAfter(lineEl.getStartOffset() + 1,
+                    top.getPosition());
+            while (nap != null) {
+                scopeStack.add(nap);
+                nap = nap.getNode().findNodeAtOrAfter(lineEl.getStartOffset() + 1, nap.getPosition());                
+            }
+            
+            outer:
+            while (true) {
+                // Skip to the next line which has text on it
+                doc.getText(lineEl.getStartOffset(), lineEl.getEndOffset() - lineEl.getStartOffset(), segment);
+                int nws = findNonWhitespace(segment, 0);
+                while (nws == -1) {
+                    if (++i > le) {
+                        break outer;
+                    }
+                    lineEl = map.getElement(i);
+                    doc.getText(lineEl.getStartOffset(),
+                            lineEl.getEndOffset() - lineEl.getStartOffset(), segment);
+                    nws = findNonWhitespace(segment, 0);
+                }
+
+                // Remove from the stack nodes which we've gone past
+                int curpos = lineEl.getStartOffset() + nws;
+                ListIterator<NodeAndPosition<ParsedNode>> j = scopeStack.listIterator(scopeStack.size());
+                NodeAndPosition<ParsedNode> topNap = null;
+                do {
+                    nap = j.previous();
+                    if (nap.getEnd() > curpos) {
+                        break;
+                    }
+                    topNap = nap;
+                    j.remove();
+                } while (j.hasPrevious());
+
+                if (topNap != null) {
+                    // Rebuild the scope stack
+                    do {
+                        topNap = topNap.nextSibling();
+                    } while (topNap != null && topNap.getEnd() <= curpos);
+                    while (topNap != null && topNap.getPosition() < lineEndPos) {
+                        scopeStack.add(topNap);
+                        topNap = topNap.getNode().findNodeAtOrAfter(curpos + 1, topNap.getPosition());
+                    }
+                }
+                
+                if (scopeStack.isEmpty()) {
+                    break;
+                }
+                
+                // At this point:
+                // - curpos is the position of the first non-whitespace on the current line (it may be
+                //   prior to damageStart, but in that case it will be on the same line)
+                // - i is the current line index
+                // - lineEl is the current line element
+                // - segment contains the text of the current line
+                // - scopeStack contains a stack of elements which overlap or follow curpos, and
+                //   which start on or before the current line.
+
+                // Calculate/store indent
+                Rectangle cbounds = modelToView(lineEl.getStartOffset() + nws, a, Position.Bias.Forward).getBounds();
+                int indent = cbounds.x;
+                for (j = scopeStack.listIterator(scopeStack.size()); j.hasPrevious(); ) {
+                    NodeAndPosition<ParsedNode> next = j.previous();
+                    if (next.getPosition() <= curpos) {
+                        // Node is present on this line (begins before curpos)
+                        updateNodeIndent(next, indent, nodeIndents.get(next.getNode()), dmgRange);
+                    }
+                    else if (next.getPosition() < lineEl.getEndOffset()) {
+                        // Node starts on this line, after curpos.
+                        nws = findNonWhitespace(segment, next.getPosition() - lineEl.getStartOffset());
+                        Integer oindent = nodeIndents.get(next.getNode());
+                        if (oindent != null && nws != -1) {
+                            cbounds = modelToView(lineEl.getStartOffset() + nws, a, Position.Bias.Forward).getBounds();
+                            indent = cbounds.x;
+                            updateNodeIndent(next, indent, oindent, dmgRange);
+                        }
+                    }
+                    else {
+                        // Node isn't on this line.
+                        continue;
+                    }
+                    
+                    // Inner nodes are skipped during indent calculation
+                    if (next.getNode().isInner()) {
+                        break;
+                    }
+                }
+
+                // Process subsequent nodes which are also on this line
+                j = scopeStack.listIterator(scopeStack.size());
+                while (j.hasPrevious()) {
+                    nap = j.previous();
+                    if (nap.getEnd() > lineEl.getEndOffset()) {
+                        break;
+                    }
+                    // Node ends this line and may have siblings
+                    nap = nap.nextSibling();
+                    j.remove();
+                    if (nap != null) {
+                        do {
+                            scopeStack.add(nap);
+                            if (nap.getPosition() < lineEl.getEndOffset()) {
+                                int spos = nap.getPosition() - lineEl.getStartOffset();
+                                nws = findNonWhitespace(segment, spos);
+                                Integer oindent = nodeIndents.get(nap.getNode());
+                                if (oindent != null && nws != -1) {
+                                    cbounds = modelToView(lineEl.getStartOffset() + nws, a, Position.Bias.Forward).getBounds();
+                                    indent = cbounds.x;
+                                    updateNodeIndent(nap, indent, oindent, dmgRange);
+                                }
+                            }
+                            nap = nap.getNode().findNodeAtOrAfter(nap.getPosition(), nap.getPosition());
+                        }
+                        while (nap != null);
+                        j = scopeStack.listIterator(scopeStack.size());
+                    }
+                }
+
+                // Move on to the next line
+                if (++i > le) {
+                    break;
+                }
+                lineEl = map.getElement(i);
+            }
+            
+            return dmgRange;
+        }
+        catch (BadLocationException ble) {
+            throw new RuntimeException(ble);
+        }
+    }
+
+    private int[] reassessIndentsRemove(Shape a, int dmgPoint, boolean multiLine)
+    {
+        MoeSyntaxDocument doc = (MoeSyntaxDocument) getDocument();
+        ParsedCUNode pcuNode = doc.getParsedNode();
+        
+        int [] dmgRange = new int[2];
+        dmgRange[0] = dmgPoint;
+        dmgRange[1] = dmgPoint;
+        
+        if (pcuNode == null) {
+            return dmgRange;
+        }
+        
+        Element map = doc.getDefaultRootElement();
+        int ls = map.getElementIndex(dmgPoint);
+        Element lineEl = map.getElement(ls);
+
+        NodeAndPosition<ParsedNode> top =
+            pcuNode.findNodeAtOrAfter(lineEl.getStartOffset(), 0);
+        while (top != null && top.getEnd() == lineEl.getStartOffset()) {
+            top = top.nextSibling();
+        }
+        
+        if (top == null) {
+            // No nodes at all.
+            return dmgRange;
+        }
+
+        if (top.getPosition() >= lineEl.getEndOffset()) {
+            // The first node we found is on the next line.
+            return dmgRange;
+        }
+        
+        try {
+            // At this point lineEl/segment are the line containing the deletion point. Some lines beyond
+            // this point may have been removed (if multiLine true).
+            Segment segment = new Segment();
+            doc.getText(lineEl.getStartOffset(),
+                    lineEl.getEndOffset() - lineEl.getStartOffset(), segment);
+            
+            // All nodes for this line with a cached indent greater than or equal to the damage point
+            // indent should have their indents re-assessed: If the indent of the node on this line is
+            // lower than (or the same as) the cached indent, it becomes the new cached indent; otherwise
+            // the cached indent must be discarded.
+            // Except: if the node does not span the damage point, its cached indent need not be discarded,
+            //   since in that case the node indent cannot have increased.
+
+            List<NodeAndPosition<ParsedNode>> rscopeStack = new LinkedList<NodeAndPosition<ParsedNode>>();
+            getScopeStackAfter(doc.getParsedNode(), 0, dmgPoint, rscopeStack);
+            rscopeStack.remove(0); // remove the root node
+
+            boolean doContinue = true;
+
+            Rectangle cbounds = modelToView(dmgPoint, a, Position.Bias.Forward).getBounds();
+            int dpI = cbounds.x; // damage point indent
+
+            while (doContinue && ! rscopeStack.isEmpty()) {
+                NodeAndPosition<ParsedNode> rtop = rscopeStack.remove(rscopeStack.size() - 1);
+                while (rtop != null && rtop.getPosition() < lineEl.getEndOffset()) {
+                    if (rtop.getPosition() <= dmgPoint && rtop.getEnd() >= lineEl.getEndOffset()) {
+                        // Content of inner nodes can't affect containing nodes:
+                        doContinue &= ! rtop.getNode().isInner();
+                    }
+
+                    Integer cachedIndent = nodeIndents.get(rtop.getNode());
+                    if (cachedIndent == null) {
+                        rtop = rtop.nextSibling();
+                        continue;
+                    }
+
+                    // If the cached indent is smaller than the damage point indent, then it
+                    // is still valid - unless this is a multiple line remove.
+                    if (!multiLine && cachedIndent < dpI) {
+                        rtop = rtop.nextSibling();
+                        continue;
+                    }
+
+                    if (nodeSkipsStart(rtop, lineEl, segment)) {
+                        if (rtop.getPosition() <= dmgPoint) {
+                            // The remove may have made this line empty
+                            nodeIndents.remove(rtop.getNode());
+                            dmgRange[0] = Math.min(dmgRange[0], rtop.getPosition());
+                            dmgRange[1] = Math.max(dmgRange[1], rtop.getEnd());
+                        }
+                        break; // no more siblings can be on this line
+                    }
+
+                    int nwsP = Math.max(lineEl.getStartOffset(), rtop.getPosition());
+                    int nws = findNonWhitespace(segment, nwsP - lineEl.getStartOffset());
+                    if (nws == -1 || nws + lineEl.getStartOffset() >= rtop.getEnd()) {
+                        // Two separate cases which we can handle in the same manner.
+                        if (rtop.getPosition() <= dmgPoint) {
+                            // The remove may have made this line empty
+                            nodeIndents.remove(rtop.getNode());
+                            dmgRange[0] = Math.min(dmgRange[0], rtop.getPosition());
+                            dmgRange[1] = Math.max(dmgRange[1], rtop.getEnd());
+                        }
+
+                        rtop = rtop.nextSibling();
+                        continue;
+                    }
+
+                    cbounds = modelToView(nws + lineEl.getStartOffset(), a, Position.Bias.Forward).getBounds();
+                    int newIndent = cbounds.x;
+
+                    if (newIndent < cachedIndent) {
+                        nodeIndents.put(rtop.getNode(), newIndent);
+                        dmgRange[0] = Math.min(dmgRange[0], rtop.getPosition());
+                        dmgRange[1] = Math.max(dmgRange[1], rtop.getEnd());
+                    }
+                    else if (newIndent > cachedIndent) {
+                        if (rtop.getPosition() <= dmgPoint) {
+                            nodeIndents.remove(rtop.getNode());
+                            dmgRange[0] = Math.min(dmgRange[0], rtop.getPosition());
+                            dmgRange[1] = Math.max(dmgRange[1], rtop.getEnd());
+                        }
+                    }
+
+                    rtop = rtop.nextSibling();
+                }
+            }
+            
+            return dmgRange;
+        }
+        catch (BadLocationException ble) {
+            throw new RuntimeException(ble);
+        }
+    }
+    
+    /**
+     * Update an existing indent, in the case where we have found a line where the indent
+     * may now be smaller due to an edit.
+     * @param nap    The node whose cached indent value is to be updated
+     * @param indent   The indent, on some line
+     * @param oindent  The old indent value (may be null)
+     * @param dmgRange  The range of positions which must be repainted. This is updated by
+     *                  if necessary.
+     */
+    private void updateNodeIndent(NodeAndPosition<ParsedNode> nap, int indent, Integer oindent, int [] dmgRange)
+    {
+        int dmgStart = dmgRange[0];
+        int dmgEnd = dmgRange[1];
+        
+        if (oindent != null) {
+            int noindent = oindent;
+            if (indent < noindent) {
+                nodeIndents.put(nap.getNode(), indent);
+            }
+            else if (indent != noindent) {
+                nodeIndents.remove(nap.getNode());
+            }
+            if (indent != noindent) {
+                dmgStart = Math.min(dmgStart, nap.getPosition());
+                dmgEnd = Math.max(dmgEnd, nap.getEnd());
+                dmgRange[0] = dmgStart;
+                dmgRange[1] = dmgEnd;
+            }
+        }
+    }
+    
+    /**
+     * Get a stack of ParsedNodes which overlap or follow a particular document position. The stack shall
+     * contain the outermost node (at the bottom of the stack) through to the innermost node which overlaps
+     * (but does not end at) or which is the node first following the specified position.
+     * 
+     * @param root     The root node
+     * @param rootPos  The position of the root node
+     * @param position The position for which to build the scope stack
+     * @param list     The list into which to store the stack. Items are added to the end of the list.
+     */
+    private void getScopeStackAfter(ParsedNode root, int rootPos, int position, List<NodeAndPosition<ParsedNode>> list)
+    {
+        // Note we add 1 to the given position to skip nodes which actually end at the position,
+        // or which are zero size.
+        list.add(new NodeAndPosition<ParsedNode>(root, 0, root.getSize()));
+        int curpos = rootPos;
+        NodeAndPosition<ParsedNode> nap = root.findNodeAtOrAfter(position + 1, curpos);
+        while (nap != null) {
+            list.add(nap);
+            curpos = nap.getPosition();
+            nap = nap.getNode().findNodeAtOrAfter(position + 1, curpos);
+        }
+    }
+
+    /**
+     * Search for a non-whitespace character, starting from the given offset
+     * (0 = start of the segment). Returns -1 if no such character can be found.
+     */
+    private int findNonWhitespace(Segment segment, int startPos)
+    {
+        int endpos = segment.offset + segment.count;
+        for (int i = segment.offset + startPos; i < endpos; i++) {
+            char c = segment.array[i];
+            if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
+                return i - segment.offset;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Search for a non-whitespace character, starting from the given offset in the segment; treat
+     * single-line comments as whitespace. Returns -1 if the line consists only of whitespace.
+     */
+    private int findNonWhitespaceComment(NodeAndPosition<ParsedNode> nap, Element lineEl, Segment segment, int startPos)
+    {
+        int nws = findNonWhitespace(segment, startPos);
+        if (nws != -1) {
+            int pos = nws + lineEl.getStartOffset();
+            
+            if (nap.getEnd() > pos) {
+                NodeAndPosition<ParsedNode> inNap = nap.getNode().findNodeAt(pos, nap.getPosition());
+                if (inNap != null && inNap.getNode().getNodeType() == ParsedNode.NODETYPE_COMMENT
+                        && inNap.getPosition() == pos && inNap.getEnd() == lineEl.getEndOffset() - 1) {
+                    return -1;
+                }
+            }
+            else {
+                NodeAndPosition<ParsedNode> nnap = nap.nextSibling();
+                if (nnap != null && nnap.getNode().getNodeType() == ParsedNode.NODETYPE_COMMENT
+                        && nnap.getPosition() == pos && nnap.getEnd() == lineEl.getEndOffset() - 1) {
+                    return -1;
+                }
+            }
+        }
+        return nws;
+    }
+    
+    /**
+     * Search backwards for a non-whitespace character. If no such character
+     * is found, returns (endPos - 1).
+     */
+    private int findNonWhitespaceBwards(Segment segment, int startPos, int endPos)
+    {
+        int lastP = segment.offset + endPos;
+        int i;
+        for (i = segment.offset + startPos; i > lastP; i--) {
+            char c = segment.array[i];
+            if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
+                return i - segment.offset;
+            }
+        }
+        return endPos - 1;
+    }
+
+    /**
+     * Check whether a given line is tagged with a given tag.
+     * @param line The line to check
+     * @param tag  The name of the tag
+     * @return     True, if the tag is set
+     */
+    protected final boolean hasTag(Element line, String tag)
+    {
+        return Boolean.TRUE.equals(line.getAttributes().getAttribute(tag)); 
+    }
+
+
+    /**
+     * Initialise some fields after we get a graphics context for the first time
+     */
+    protected void initialise(Graphics g)
+    {
+        defaultFont = g.getFont();
+
+        // Use system settings for text rendering (Java 6 only)
+        if (desktopHints == null) {
+            Toolkit tk = Toolkit.getDefaultToolkit(); 
+            desktopHints = (Map<?,?>) (tk.getDesktopProperty("awt.font.desktophints"));
+        }
+        if (desktopHints != null && g instanceof Graphics2D) {
+            Graphics2D g2d = (Graphics2D) g;
+            g2d.addRenderingHints(desktopHints); 
+        }
+
+        initialised = true;
+    }
+
+    /*
+     * Need to override this method to handle node updates. If a node indentation changes,
+     * the whole node needs to be repainted.
+     */
+    @Override
+    protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f)
+    {
+        if (a == null) {
+            // We have no shape. One cause might be that the editor is not visible.
+            nodeIndents.clear();
+            return;
+        }
+        
+        MoeSyntaxDocument document = (MoeSyntaxDocument) getDocument();
+        
+        int damageStart = document.getLength();
+        int damageEnd = 0;
+
+        if (changes instanceof MoeSyntaxEvent) {
+            MoeSyntaxEvent mse = (MoeSyntaxEvent) changes;
+            for (NodeAndPosition<ParsedNode> node : mse.getRemovedNodes()) {
+                nodeRemoved(node.getNode());
+                damageStart = Math.min(damageStart, node.getPosition());
+                damageEnd = Math.max(damageEnd, node.getEnd());
+                NodeAndPosition<ParsedNode> nap = node;
+                
+                int [] r = clearNap(nap, document, damageStart, damageEnd);
+                damageStart = r[0];
+                damageEnd = r[1];
+            }
+            
+            for (NodeChangeRecord record : mse.getChangedNodes()) {
+                NodeAndPosition<ParsedNode> nap = record.nap;
+                nodeIndents.remove(nap.getNode());
+                damageStart = Math.min(damageStart, nap.getPosition());
+                damageStart = Math.min(damageStart, record.originalPos);
+                damageEnd = Math.max(damageEnd, nap.getEnd());
+                damageEnd = Math.max(damageEnd,record.originalPos + record.originalSize);
+                
+                int [] r = clearNap(nap, document, damageStart, damageEnd);
+                damageStart = r[0];
+                damageEnd = r[1];
+            }
+        }
+
+        Component host = getContainer();
+        if (host == null) {
+            return;
+        }
+        Element map = getElement();
+
+        if (changes.getType() == EventType.INSERT) {
+            damageStart = Math.min(damageStart, changes.getOffset());
+            damageEnd = Math.max(damageEnd, changes.getOffset() + changes.getLength());
+            int [] r = reassessIndentsAdd(a, damageStart, damageEnd);
+            damageStart = r[0];
+            damageEnd = r[1];
+        }
+        else if (changes.getType() == EventType.REMOVE) {
+            damageStart = Math.min(damageStart, changes.getOffset());
+            damageEnd = Math.max(damageEnd, changes.getOffset());
+            ElementChange ec = changes.getChange(document.getDefaultRootElement());
+            // Element [] childrenRemoved = changes.getChange(document.getDefaultRootElement()).getChildrenRemoved();
+            boolean multiLine = ec != null;
+            int [] r = reassessIndentsRemove(a, damageStart, multiLine);
+            damageStart = r[0];
+            damageEnd = r[1];
+        }
+        
+        if (damageStart < damageEnd) {
+            int line = map.getElementIndex(damageStart);
+            int lastline = map.getElementIndex(damageEnd - 1);
+            damageLineRange(line, lastline, a, host);
+        }
+
+        DocumentEvent.ElementChange ec = changes.getChange(map);
+        Element[] added = (ec != null) ? ec.getChildrenAdded() : null;
+        Element[] removed = (ec != null) ? ec.getChildrenRemoved() : null;
+        if (((added != null) && (added.length > 0)) || 
+                ((removed != null) && (removed.length > 0))) {
+            // This case is handled Ok by the superclass.
+            super.updateDamage(changes, a, f);
+        } else {
+            // This is the case we have to fix. The PlainView implementation only
+            // repaints a single line; we need to repaint the whole range.
+            super.updateDamage(changes, a, f);
+            int choffset = changes.getOffset();
+            int chlength = Math.max(changes.getLength(), 1);
+            int line = map.getElementIndex(choffset);
+            int lastline = map.getElementIndex(choffset + chlength - 1);
+            damageLineRange(line, lastline, a, host);
+        }
+    }
+
+    /**
+     * Clear a node's cached indent information. If the node is an inner node this
+     * also clears parent nodes as appropriate.
+     */
+    private int[] clearNap(NodeAndPosition<ParsedNode> nap, MoeSyntaxDocument document,
+            int damageStart, int damageEnd)
+    {
+        if (nap.getNode().isInner()) {
+
+            List<NodeAndPosition<ParsedNode>> list = new LinkedList<NodeAndPosition<ParsedNode>>();
+            NodeAndPosition<ParsedNode> top;
+            top = new NodeAndPosition<ParsedNode>(document.getParsedNode(), 0, document.getLength());
+            while (top != null && top.getNode() != nap.getNode()) {
+                if (top.getNode().isInner()) {
+                    list.clear();
+                }
+                list.add(top);
+                top = top.getNode().findNodeAt(nap.getEnd(), top.getPosition());
+            }
+
+            for (NodeAndPosition<ParsedNode> cnap : list)
+            {
+                damageStart = Math.min(damageStart, cnap.getPosition());
+                damageEnd = Math.max(damageEnd, cnap.getEnd());
+                nodeIndents.remove(cnap.getNode());
+            }
+        }
+        
+        return new int[] {damageStart, damageEnd};
+    }
+    
+    private void nodeRemoved(ParsedNode node)
+    {
+        nodeIndents.remove(node);
+    }
+
+    public static void setHighlightStrength(int strength)
+    {
+        BlueJSyntaxView.strength = strength;
+        resetColors();
+    }
+
+    /**
+     * Sets up the colors based on the strength value 
+     * (from strongest (20) to white (0)
+     */
+    private static void resetColors()
+    {       
+        C1 = getGreenContainerBorder();
+        C2 = getGreenWash(); 
+        C3 = getGreenBorder();
+        M1 = getYellowBorder();
+        M2 = getYellowWash();
+        S1 = getBlueBorder();
+        S2 = getBlueWash();
+        I1 = getPinkBorder();
+        I2 = getPinkWash();             
+    }
+
+    private static Color getReducedColor(Color c)
+    {
+        return getReducedColor(c.getRed(), c.getGreen(), c.getBlue(), strength);
+    }
+    
+    /**
+     * Get a colour which has been faded toward the background according to the
+     * given strength value. The higher the strength value, the less the color
+     * is faded.
+     */
+    public static Color getReducedColor(int r, int g, int b, int strength)
+    {
+        Color bg = MoeSyntaxDocument.getBackgroundColor();
+        double factor = strength / (float) ScopeHighlightingPrefDisplay.MAX;
+        double other = 1 - factor;
+        int nr = Math.min((int)(r * factor + bg.getRed() * other), 255);
+        int ng = Math.min((int)(g * factor + bg.getGreen() * other), 255);
+        int nb = Math.min((int)(b * factor + bg.getBlue() * other), 255);
+        return new Color(nr, ng, nb);
+    }
+    
+    /** 
+     * Return the green wash color
+     * modified to become less strong based on the 'strength' value
+     */
+    private static Color getGreenWash()
+    {
+        return getReducedColor(GREEN_BASE);
+    }
+
+    /** 
+     * Return the green container border color
+     * modified to become less strong based on the 'strength' value
+     */
+    private static Color getGreenContainerBorder()
+    {
+        return getReducedColor(GREEN_OUTER_BASE);
+    }
+
+    /** 
+     * Return the green border color
+     * modified to become less strong based on the 'strength' value
+     */
+    private static Color getGreenBorder()
+    {
+        return getReducedColor(GREEN_INNER_BASE);
+    }
+
+    /**
+     * Return the yellow border color
+     * modified to become less strong (until white) based on the 'strength' value
+     */
+    private static Color getYellowBorder()
+    {
+        return getReducedColor(YELLOW_OUTER_BASE);
+    }
+    
+    /**
+     * Return the yellow wash color
+     * modified to become less strong (until white) based on the 'strength' value
+     */
+    private static Color getYellowWash()
+    {
+        return getReducedColor(YELLOW_BASE);
+    }
+
+    /**
+     * Return the blue border (selection) color
+     * modified to become less strong (until white) based on the 'strength' value
+     */
+    private static Color getBlueBorder()
+    {
+        return getReducedColor(BLUE_OUTER_BASE);
+    }
+
+    /**
+     * Return the blue wash color
+     * modified to become less strong (until white) based on the 'strength' value
+     */
+    private static Color getBlueWash()
+    {
+        return getReducedColor(BLUE_BASE);
+    }
+
+    /**
+     *  Return the pink border (iteration) color
+     *  modified to become less strong (until white) based on the 'strength' value
+     */
+    private static Color getPinkBorder()
+    {
+        return getReducedColor(PINK_OUTER_BASE);
+    }
+
+    /**
+     *  Return the pink wash color
+     *  modified to become less strong (until white) based on the 'strength' value
+     */
+    private static Color getPinkWash()
+    {
+        return getReducedColor(PINK_BASE);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/BracketMatchPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/BracketMatchPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..a68030f2c6a63537e6ffc1afc534a3e056926c81
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/BracketMatchPainter.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.*;
+
+import javax.swing.text.*;
+
+import bluej.utility.Debug;
+
+/**
+ * Specialised highlight painter for painting matching bracket in text component as
+ * a rectangle.
+ */
+public class BracketMatchPainter extends DefaultHighlighter.DefaultHighlightPainter
+{
+     
+    public BracketMatchPainter(Color colour)
+    {
+        super(colour);
+    }
+        
+    /**
+     * Paints a rectangle around a matching bracket
+     * This seems to be the only method we need to over-ride.
+     *
+     * @return area highlighted 
+     */
+    public Shape paintLayer(Graphics g, int begin, int end, Shape bounds, JTextComponent comp, View view) 
+    {
+        g.setColor(getColor());
+        Rectangle rect = null;
+        try {
+            Shape shape = view.modelToView(begin, Position.Bias.Forward,
+                                           end,Position.Bias.Backward,
+                                           bounds);
+            rect = shape.getBounds();                
+            g.fillRect(rect.x, rect.y, rect.width -1, rect.height - 1);
+        } catch (BadLocationException ble) {
+            Debug.reportError("bad location exception thrown");
+            ble.printStackTrace();
+        }    
+        return rect;
+    }
+    
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/CodeCompleteCellRenderer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/CodeCompleteCellRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f31d8c8a3574018a0ab5b551626f0b01d690d80
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/CodeCompleteCellRenderer.java
@@ -0,0 +1,109 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+
+import javax.swing.Box;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.ListCellRenderer;
+
+import bluej.Config;
+import bluej.parser.AssistContent;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.DBoxLayout;
+import java.awt.Color;
+
+/**
+ * A cell renderer for the code completion popup list.
+ * 
+ * @author Davin McCall
+ */
+public class CodeCompleteCellRenderer extends JPanel implements ListCellRenderer
+{
+    /** label showing the return type */
+    private JLabel typeLabel = new JLabel();
+    /** label showing method name and parameters */
+    private JLabel descriptionLabel = new JLabel();
+    
+    private Dimension rtypeSize;
+    private String immediateType;
+    private Font cfont;
+    private Font cfontBold;
+    
+    CodeCompleteCellRenderer(String immediateType)
+    {
+        setBorder(null);
+        setLayout(new DBoxLayout(DBoxLayout.X_AXIS));
+        int fontSize = PrefMgr.getStandardEditorFont().getSize();
+        cfont = Config.getFont("bluej.codecompletion.font", "Monospaced", fontSize);
+        cfontBold = cfont.deriveFont(Font.BOLD);
+        typeLabel.setFont(cfont);
+        typeLabel.setText("String123456"); // for assigning width
+        rtypeSize = typeLabel.getPreferredSize();
+        typeLabel.setMaximumSize(rtypeSize);
+        typeLabel.setMinimumSize(rtypeSize);
+        typeLabel.setPreferredSize(rtypeSize);
+        typeLabel.setForeground(new Color(90, 80, 45));
+        add(typeLabel);
+        
+        add(descriptionLabel);
+        add(Box.createHorizontalGlue());
+        setBorder(new javax.swing.border.EmptyBorder(2, 2, 2, 2));
+
+        this.immediateType = immediateType;
+    }
+    
+    public Component getListCellRendererComponent(JList list, Object value,
+            int index, boolean isSelected, boolean cellHasFocus)
+    {
+        if (value != null) {
+            AssistContent content = (AssistContent) value;
+            typeLabel.setText(content.getReturnType().toString());
+            descriptionLabel.setText(content.getDisplayName());
+            
+            if (content.getDeclaringClass().equals(immediateType)) {
+                descriptionLabel.setFont(cfontBold);
+            }
+            else {
+                descriptionLabel.setFont(cfont);
+            }
+        }
+        
+        if (isSelected) {
+            setBackground(list.getSelectionBackground());
+            setForeground(list.getSelectionForeground());
+            setOpaque(true);
+        }
+        else {
+            setBackground(list.getBackground());
+            setForeground(list.getForeground());
+            setOpaque(false);
+        }
+        
+        return this;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/CodeCompletionDisplay.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/CodeCompletionDisplay.java
new file mode 100644
index 0000000000000000000000000000000000000000..4147af6bc2b66792a4cce98056a4dff46f5f2bf2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/CodeCompletionDisplay.java
@@ -0,0 +1,518 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2012  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GridLayout;
+import java.awt.Paint;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowFocusListener;
+import java.awt.event.WindowListener;
+import java.util.Vector;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
+import javax.swing.InputMap;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JFrame;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.border.Border;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.text.html.HTMLEditorKit;
+
+import bluej.Config;
+import bluej.parser.AssistContent;
+import bluej.parser.SourceLocation;
+import bluej.parser.lexer.LocatableToken;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.JavaUtils;
+
+
+/**
+ * Code completion panel for the Moe editor.
+ * 
+ * @author Marion Zalk
+ */
+public class CodeCompletionDisplay extends JFrame 
+    implements ListSelectionListener, MouseListener
+{
+    private static final Color msgTextColor = new Color(200,170,100);
+
+    private MoeEditor editor;
+    private WindowListener editorListener;
+    private AssistContent[] values;
+    private String prefix;
+    private String suggestionType;
+    private SourceLocation prefixBegin;
+    private SourceLocation prefixEnd;
+
+    private JList methodList;
+    private JEditorPane methodDescription; 
+
+    private JComponent pane;
+
+    /**
+     * Construct a code completion display panel, for the given editor and with the given
+     * suggestions. The location specifies the partial identifier entered by the user before
+     * requesting suggestions (if any - it may be null).
+     */
+    public CodeCompletionDisplay(MoeEditor ed, String suggestionType, 
+            AssistContent[] values, LocatableToken location) 
+    {
+        this.values=values;
+        this.suggestionType = suggestionType;
+        makePanel();
+        editor=ed;
+        
+        if (location != null) {
+            prefixBegin = new SourceLocation(location.getLine(), location.getColumn());
+            prefixEnd = new SourceLocation(location.getEndLine(), location.getEndColumn());
+            prefix = location.getText();
+        }
+        else {
+            prefixBegin = editor.getCaretLocation();
+            prefixEnd = prefixBegin;
+            prefix = "";
+        }
+
+        populatePanel();
+
+        addWindowFocusListener(new WindowFocusListener() {
+            @Override
+            public void windowGainedFocus(WindowEvent e)
+            {
+                methodList.requestFocusInWindow();
+                editor.getSourcePane().getCaret().setVisible(true);
+            }
+
+            @Override
+            public void windowLostFocus(WindowEvent e)
+            {
+                doClose();
+            }
+        });
+        
+        editorListener = new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent e)
+            {
+                doClose();
+            }
+            
+            @Override
+            public void windowIconified(WindowEvent e)
+            {
+                doClose();
+            }
+        };
+        
+        ed.addWindowListener(editorListener);
+    }
+
+    /**
+     * Close the code completion display window.
+     */
+    private void doClose()
+    {
+        editor.removeWindowListener(editorListener);
+        dispose();
+    }
+    
+    /**
+     * Creates a component with a main panel (list of available methods & values)
+     * and a text area where the description of the chosen value is displayed
+     */
+    private void makePanel()
+    {
+        GridLayout gridL=new GridLayout(1, 2);
+        pane = (JComponent) getContentPane();
+
+        JPanel mainPanel = new JPanel();
+        mainPanel.setLayout(gridL);
+
+        // create area for method names
+        JPanel methodPanel = new JPanel();
+
+        // create function description area     
+        methodDescription = new JEditorPane();
+        Border mdBorder = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.BLACK),
+                BorderFactory.createEmptyBorder(0, 10, 5, 10));
+        methodDescription.setBorder(mdBorder);
+        methodDescription.setEditable(false);
+        methodDescription.setOpaque(false);
+        
+        methodDescription.setEditorKit(new HTMLEditorKit());
+        methodDescription.setEditable(false);
+        InputMap inputMap = new InputMap() {
+            @Override
+            public Object get(KeyStroke keyStroke)
+            {
+                // Define no action for up/down, which allows the parent scroll
+                // pane to process the keys instead. This means the view will scroll,
+                // rather than just moving an invisible cursor.
+                Object action = super.get(keyStroke);
+                if ("caret-up".equals(action) || "caret-down".equals(action)) {
+                    return null;
+                }
+                return action;
+            }
+        };
+        inputMap.setParent(methodDescription.getInputMap(JComponent.WHEN_FOCUSED));
+        methodDescription.setInputMap(JComponent.WHEN_FOCUSED, inputMap);
+        // To make the gradient fill show up on the Nimbus look and feel,
+        // we set the background with an alpha component of zero to get transparency
+        // (see http://forums.java.net/jive/thread.jspa?messageID=267839)
+        methodDescription.setBackground(new Color(0,0,0,0));
+        methodDescription.setFont(methodDescription.getFont().deriveFont((float)PrefMgr.getEditorFontSize()));
+        
+        methodList = new JList();
+        methodList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        methodList.addListSelectionListener(this);
+        methodList.addMouseListener(this);
+        methodList.requestFocusInWindow();
+        methodList.setCellRenderer(new CodeCompleteCellRenderer(suggestionType));
+        methodList.setOpaque(false);
+        
+        // To allow continued typing of method name prefix, we map keys to equivalent actions
+        // within the editor. I.e. typing a key inserts that key character.
+        inputMap = new InputMap() {
+            @Override
+            public Object get(final KeyStroke keyStroke)
+            {
+                if (keyStroke.getKeyCode() == KeyEvent.VK_ESCAPE) {
+                    return null;
+                }
+                if (keyStroke.getKeyChar() == 8 && keyStroke.getKeyEventType() == KeyEvent.KEY_TYPED) {
+                    // keyChar 8 = backspace
+                    return new AbstractAction() {
+                        public void actionPerformed(ActionEvent e)
+                        {
+                            if (prefix.length() > 0) {
+                                SourceLocation back = new SourceLocation(prefixEnd.getLine(), prefixEnd.getColumn() - 1);
+                                editor.setSelection(back, prefixEnd);
+                                editor.insertText("", false);
+                                prefix = prefix.substring(0, prefix.length() - 1);
+                                prefixEnd = editor.getCaretLocation();
+                                updatePrefix();
+                            }
+                        }
+                    };
+                }
+                Object actionName = super.get(keyStroke);
+                if (actionName == null && keyStroke.getKeyEventType() == KeyEvent.KEY_TYPED) {
+                    char keyChar = keyStroke.getKeyChar();
+                    // Ignore < 32, and range between 0x7F and 0x9F which are unicode
+                    // control characters. 0x7F is "delete".
+                    // 0xFFFF is returned on Mac JDK7 for non-character events.
+                    if (keyChar >= 32 && keyChar < 0x7F || keyChar > 0x9F && keyChar < 0xFFFF) {
+                        return new AbstractAction() {
+                            public void actionPerformed(ActionEvent e)
+                            {
+                                editor.insertText("" + keyStroke.getKeyChar(), false);
+                                prefix += keyStroke.getKeyChar();
+                                prefixEnd = editor.getCaretLocation();
+                                updatePrefix();
+                            }
+                        };
+                    }
+                }
+                return actionName;
+            }
+        };
+        inputMap.setParent(methodList.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
+        methodList.setInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
+
+        ActionMap actionMap = new ActionMap() {
+            @Override
+            public Action get(Object key)
+            {
+                if (key instanceof Action) {
+                    return (Action) key;
+                }
+                return super.get(key);
+            }
+        };
+        actionMap.setParent(methodList.getActionMap());
+        methodList.setActionMap(actionMap);
+        
+        // Set a standard height/width
+        Font mlFont = methodList.getFont();
+        mlFont = mlFont.deriveFont((float)PrefMgr.getEditorFontSize());
+        FontMetrics metrics = methodList.getFontMetrics(mlFont);
+        Dimension size = new Dimension(metrics.charWidth('m') * 30, metrics.getHeight() * 15);
+
+        JScrollPane scrollPane;
+        scrollPane = new GradientFillScrollPane(methodList, new Color(250,246,229), new Color(233,210,132));
+        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+        scrollPane.setPreferredSize(size);
+        methodPanel.add(scrollPane);
+        methodPanel.setFont(mlFont);
+        
+        scrollPane = new GradientFillScrollPane(methodDescription, new Color(250,246,229), new Color(240,220,140));
+        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+        scrollPane.setPreferredSize(size);
+
+        mainPanel.add(methodPanel);
+        mainPanel.add(scrollPane);
+        
+        pane.add(mainPanel); 
+
+        inputMap = new InputMap();
+        inputMap.setParent(pane.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
+
+        KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0);
+        inputMap.put(keyStroke, "escapeAction");
+        keyStroke=KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
+        inputMap.put(keyStroke, "completeAction");
+        
+        pane.getRootPane().setInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
+        
+        actionMap = new ActionMap() {
+            @Override
+            public Action get(Object key)
+            {
+                if (key instanceof Action) {
+                    return (Action) key;
+                }
+                return super.get(key);
+            }
+        };
+        actionMap.put("escapeAction", new AbstractAction() {
+            public void actionPerformed(ActionEvent e)
+            {
+                doClose();
+            }
+        });
+        actionMap.put("completeAction", new AbstractAction(){ 
+            public void actionPerformed(ActionEvent e)
+            {
+                codeComplete();
+            }
+        });
+        pane.getRootPane().setActionMap(actionMap);
+
+        this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+        this.setUndecorated(true);
+        setGlassPane(getCodeCompleteGlassPane());
+        pack();
+    }
+
+    private void updatePrefix()
+    {
+        Vector<AssistContent> listData = new Vector<AssistContent>();
+        for (int i=0; i<values.length; i++ ) {
+            if (values[i].getDisplayName().startsWith(prefix)) {
+                listData.add(values[i]);
+            }
+        }
+        methodList.setListData(listData);
+        methodList.setSelectedIndex(0);
+
+        getGlassPane().setVisible(listData.size() == 0);
+    }
+    
+    /**
+     * Populate the completion list.
+     */
+    private void populatePanel()
+    {  
+        updatePrefix();
+    }
+
+    /**
+     * codeComplete prints the selected text in the editor
+     */
+    private void codeComplete()
+    {
+        AssistContent selected = (AssistContent) methodList.getSelectedValue();
+        if (selected != null) {
+            String completion = selected.getCompletionText();
+            String completionSel = selected.getCompletionTextSel();
+            String completionPost = selected.getCompletionTextPost();
+            boolean hasParameters = selected.hasParameters();
+
+            editor.setSelection(prefixBegin, prefixEnd);
+
+            editor.insertText(completion, false);
+            SourceLocation selLoc = editor.getCaretLocation();
+            editor.insertText(completionSel, false);
+            editor.insertText(completionPost, hasParameters);
+            if (hasParameters) {
+                editor.setSelection(selLoc.getLine(), selLoc.getColumn(), completionSel.length());
+            }
+        }
+        
+        setVisible(false);
+    }
+
+    // ---------------- MouseListener -------------------
+    
+    /*
+     * A double click results in a completion.
+     */
+    public void mouseClicked(MouseEvent e)
+    {
+        int count=e.getClickCount();
+        if (count==2){
+            codeComplete();
+        }
+    }
+
+    public void mouseEntered(MouseEvent e) { }
+
+    public void mouseExited(MouseEvent e) { }
+
+    public void mousePressed(MouseEvent e) { }
+
+    public void mouseReleased(MouseEvent e) { }
+
+    // ---------------- ListSelectionListener -------------------
+    
+    /* (non-Javadoc)
+     * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
+     */
+    public void valueChanged(ListSelectionEvent e) 
+    {
+        AssistContent selected = (AssistContent) methodList.getSelectedValue();
+        if (selected != null) {
+            String jdHtml = selected.getJavadoc();
+            if (jdHtml != null) {
+                jdHtml = JavaUtils.javadocToHtml(jdHtml);
+            }
+            else {
+                jdHtml = "";
+            }
+            
+            String sig = escapeAngleBrackets(selected.getReturnType())
+                       + " <b>" + escapeAngleBrackets(selected.getDisplayMethodName()) + "</b>"
+                       + escapeAngleBrackets(selected.getDisplayMethodParams());
+            
+            jdHtml = "<h3>" + selected.getDeclaringClass() + "</h3>" + 
+                "<blockquote><tt>" + sig + "</tt></blockquote><br>" +
+                jdHtml;
+
+            methodDescription.setText(jdHtml);
+            methodDescription.setCaretPosition(0); // scroll to top
+        }
+        else {
+            methodDescription.setText("");
+        }
+    }
+
+    private static String escapeAngleBrackets(String sig)
+    {
+        return sig.replace("<", "&lt;").replace(">", "&gt;");
+    }
+
+    /**
+     * A JScrollPane variant that paints a gradient fill as the background.
+     * 
+     * Don't forget to setOpaque(false) on whatever is inside this pane.
+     */
+    private static class GradientFillScrollPane extends JScrollPane
+    {
+        private Color topColor;
+        private Color bottomColor;
+        
+        private GradientFillScrollPane(Component view, Color topColor, Color bottomColor)
+        {
+            super(view);
+            getViewport().setOpaque(false);
+            this.topColor = topColor;
+            this.bottomColor = bottomColor;
+        }
+
+        @Override
+        protected void paintComponent(Graphics g)
+        {
+            super.paintComponent(g);
+         
+            if (g instanceof Graphics2D) {
+                Graphics2D g2d = (Graphics2D)g;
+                
+                int w = getWidth();
+                int h = getHeight();
+                 
+                // Paint a gradient from top to bottom:
+                GradientPaint gp = new GradientPaint(
+                    0, 0, topColor,
+                    0, h, bottomColor);
+   
+                Paint origPaint = g2d.getPaint();
+                g2d.setPaint(gp);
+                g2d.fillRect(0, 0, w, h);
+                g2d.setPaint(origPaint);
+            }
+        }
+    }    
+
+    // ===== the glass pane for messages on this component =====
+
+    private CodeCompleteGlassPane myGlassPane;
+
+    private CodeCompleteGlassPane getCodeCompleteGlassPane()
+    {
+        if(myGlassPane == null) {
+            myGlassPane = new CodeCompleteGlassPane();
+        }
+        return myGlassPane;
+    }
+
+    /**
+     * A glass pane which displays a "no matching completions" message. 
+     */
+    class CodeCompleteGlassPane extends JComponent
+    {
+        @Override
+        protected void paintComponent(Graphics g)
+        {
+            Color origColor = g.getColor();
+            Font origFont = g.getFont();
+            g.setColor(msgTextColor);
+            g.setFont(origFont.deriveFont(20f));
+            g.drawString(Config.getString("editor.completion.noMatch"), 30, 60);
+            g.setColor(origColor);
+            g.setFont(origFont);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/EditorDividerPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/EditorDividerPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..548ab3dc2b372d6ce19669046398d59f4dd3cd14
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/EditorDividerPanel.java
@@ -0,0 +1,164 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.DBox;
+import bluej.utility.DBoxLayout;
+
+/**
+ * Simple divider between the editor and the naviview to provide expand/collapse functionality
+ * 
+ * @author Marion Zalk  
+ */
+public class EditorDividerPanel extends JPanel implements MouseListener {
+
+    boolean expanded=true;
+    protected JLabel expandCollapseButton;
+    private final static String EXPAND_COLLAPSE_NAVIVIEW= "expandCollapseNaviview";
+    private NaviView nav;
+    private ImageIcon openNavArrow;
+    private ImageIcon closeNavArrow;
+    private boolean currentlyHidden = false;
+
+    public EditorDividerPanel(NaviView naviview, boolean expanded) 
+    {
+        super();
+        //display consists of a label with an image
+        nav=naviview;
+        this.expanded=expanded;
+        openNavArrow=Config.getImageAsIcon("image.editordivider.open");
+        closeNavArrow=Config.getImageAsIcon("image.editordivider.close");
+
+        setPreferredSize(new Dimension(closeNavArrow.getIconWidth()+2, 0));
+        setMaximumSize(new Dimension(closeNavArrow.getIconWidth()+2, Integer.MAX_VALUE));
+
+        setLayout(new DBoxLayout(DBox.X_AXIS, 0, 0));
+        expandCollapseButton=new JLabel();
+        expandCollapseButton.setName(EXPAND_COLLAPSE_NAVIVIEW);
+        addMouseListener(this); 
+        add(expandCollapseButton, BorderLayout.CENTER);
+        if (isExpanded())
+            expandCollapseButton.setIcon(closeNavArrow);
+        else{
+            nav.setVisible(false);
+            expandCollapseButton.setIcon(openNavArrow);
+        }
+    }
+
+    protected boolean isExpanded() 
+    {
+        return expanded;
+    }
+
+    /**
+     * Sets the value of expanded/collapsed to the current view and to the prefmgr 
+     * @param expanded
+     */
+    protected void setExpanded(boolean expanded) 
+    {
+        //saving the value of the naviview (expanded/collapsed) to the prefmgr
+        //so it is there when the next editor may be opened
+        PrefMgr.setNaviviewExpanded(expanded);
+        this.expanded = expanded;
+    }
+
+    /**
+     * Causes either the naviview to expand/collapse
+     */
+    public void mouseClicked(MouseEvent e) 
+    {
+        // If they're viewing the documentation,
+        // don't allow the toggle to act:
+        if (currentlyHidden)
+            return;
+        //if expanded/collapse set the necessary images and flags 
+        if (isExpanded()){
+            nav.setVisible(false);
+            setExpanded(false);
+            expandCollapseButton.setIcon(openNavArrow);
+            mouseExited(e);
+        }           
+        else{
+            nav.setVisible(true);
+            setExpanded(true);
+            expandCollapseButton.setIcon(closeNavArrow);
+            mouseExited(e);
+        }     
+    }
+
+    public void mouseEntered(MouseEvent e) 
+    {
+        setOpaque(true);
+        setBackground(MoeEditor.lightGrey);
+        repaint();
+    }
+
+    public void mouseExited(MouseEvent e) {
+        setOpaque(false);
+        repaint();
+    }
+
+    public void mousePressed(MouseEvent e) { }
+
+    public void mouseReleased(MouseEvent e) { }
+
+
+    /**
+     * Temporarily hides the naviview (when switching to documentation view)
+     * Also temporarily hides this panel
+     */
+    public void beginTemporaryHide()
+    {
+        currentlyHidden = true;
+        nav.setVisible(false);
+        expandCollapseButton.setIcon(openNavArrow);
+        setVisible(false);
+    }
+    
+    /**
+     * Stops the effects of a temporary hide (switch back to editor view)
+     * and redisplays itself
+     * 
+     * Can be called without a previous call to beginTemporaryHide, e.g.
+     * in the case where the editor is opened in documentation view
+     */
+    public void endTemporaryHide()
+    {
+        currentlyHidden = false;
+        if (isExpanded()) {
+            nav.setVisible(true);
+            expandCollapseButton.setIcon(closeNavArrow);
+        }
+        setVisible(true);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/EditorPrefPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/EditorPrefPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..56112482807fa83f12f6d2e6564f1829e3cdc2d9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/EditorPrefPanel.java
@@ -0,0 +1,157 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.editor.EditorManager;
+import bluej.prefmgr.PrefMgr;
+import bluej.prefmgr.PrefPanelListener;
+import bluej.utility.DBox;
+import bluej.utility.DBoxLayout;
+
+/**
+ * A PrefPanel subclass to allow the user to interactively edit
+ * editor settings
+ *
+ * @author  Michael Kolling
+ */
+public class EditorPrefPanel extends JPanel implements PrefPanelListener
+{
+    private JTextField editorFontField;
+    private JCheckBox hilightingBox;
+    private JCheckBox autoIndentBox;
+    private JCheckBox lineNumbersBox;
+    private JCheckBox makeBackupBox;
+    private JCheckBox matchBracketsBox;
+    private ScopeHighlightingPrefDisplay scopeHighlightingPrefDisplay;
+
+    /**
+     * Setup the UI for the dialog and event handlers for the buttons.
+     */
+    public EditorPrefPanel()
+    {
+        scopeHighlightingPrefDisplay=new ScopeHighlightingPrefDisplay();
+        setBorder(BlueJTheme.generalBorder);
+
+        JComponent editorPanel = new DBox(DBoxLayout.Y_AXIS, 0, BlueJTheme.componentSpacingSmall, 0.5f);
+        {
+            String editorTitle = Config.getString("prefmgr.edit.editor.title");
+            editorPanel.setBorder(BorderFactory.createCompoundBorder(
+                    BorderFactory.createTitledBorder(editorTitle),
+                    BlueJTheme.generalBorder));
+            editorPanel.setAlignmentX(LEFT_ALIGNMENT);            
+            JPanel topPanel=new JPanel(new GridLayout(3,2,0,0));
+            
+            JPanel fontPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5));
+            {
+                fontPanel.add(new JLabel(Config.getString("prefmgr.edit.editorfontsize")+"  "));
+                editorFontField = new JTextField(4);
+                fontPanel.add(editorFontField);
+            }
+            topPanel.add(fontPanel);
+            autoIndentBox = new JCheckBox(Config.getString("prefmgr.edit.autoindent"));
+            topPanel.add(autoIndentBox);
+            
+            hilightingBox = new JCheckBox(Config.getString("prefmgr.edit.usesyntaxhilighting"));
+            topPanel.add(hilightingBox);
+            
+            makeBackupBox = new JCheckBox(Config.getString("prefmgr.edit.makeBackup"));
+            topPanel.add(makeBackupBox);
+
+            lineNumbersBox = new JCheckBox(Config.getString("prefmgr.edit.displaylinenumbers"));
+            topPanel.add(lineNumbersBox);
+            
+            matchBracketsBox= new JCheckBox(Config.getString("prefmgr.edit.matchBrackets"));
+            topPanel.add(matchBracketsBox);
+            
+            JPanel bottomPanel=new JPanel(new GridLayout(1,2,0,0));
+            bottomPanel.setBorder(BorderFactory.createCompoundBorder(
+                    BorderFactory.createTitledBorder(Config.getString("prefmgr.edit.colortransparency")),
+                    BlueJTheme.generalBorder));
+            //colour scope highlighter slider
+            JPanel sliderPanel=new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 20));
+            {               
+                sliderPanel.add(scopeHighlightingPrefDisplay.getHighlightStrengthSlider());
+            }
+              
+            bottomPanel.add(sliderPanel);            
+            bottomPanel.add(scopeHighlightingPrefDisplay.getColourPalette());
+                        
+            editorPanel.add(topPanel);
+            editorPanel.add(Box.createVerticalGlue());
+            editorPanel.add(bottomPanel);
+        }
+        add(editorPanel);
+
+        add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+
+        add(Box.createVerticalGlue());
+        add(Box.createVerticalGlue());
+        add(Box.createVerticalGlue());
+    }
+
+    public void beginEditing()
+    {
+        editorFontField.setText(String.valueOf(PrefMgr.getEditorFontSize()));
+        hilightingBox.setSelected(PrefMgr.getFlag(PrefMgr.HILIGHTING));
+        autoIndentBox.setSelected(PrefMgr.getFlag(PrefMgr.AUTO_INDENT));
+        lineNumbersBox.setSelected(PrefMgr.getFlag(PrefMgr.LINENUMBERS));
+        makeBackupBox.setSelected(PrefMgr.getFlag(PrefMgr.MAKE_BACKUP));
+        matchBracketsBox.setSelected(PrefMgr.getFlag(PrefMgr.MATCH_BRACKETS));
+    }
+
+    public void revertEditing()
+    {
+    }
+
+    public void commitEditing()
+    {
+        int newFontSize = 0;
+        try {
+            newFontSize = Integer.parseInt(editorFontField.getText());
+            PrefMgr.setEditorFontSize(newFontSize);
+        }
+        catch (NumberFormatException nfe) { }
+
+        PrefMgr.setFlag(PrefMgr.HILIGHTING, hilightingBox.isSelected());
+        MoeSyntaxView.resetSyntaxHighlighting();
+        PrefMgr.setFlag(PrefMgr.AUTO_INDENT, autoIndentBox.isSelected());
+        PrefMgr.setFlag(PrefMgr.LINENUMBERS, lineNumbersBox.isSelected());
+        PrefMgr.setFlag(PrefMgr.MAKE_BACKUP, makeBackupBox.isSelected());
+        PrefMgr.setFlag(PrefMgr.MATCH_BRACKETS, matchBracketsBox.isSelected());
+        PrefMgr.setScopeHighlightStrength(scopeHighlightingPrefDisplay.getStrengthValue());
+        EditorManager.getEditorManager().refreshAll();
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/FindPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/FindPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..2961499cdc95113935cfcae7e95be3314aa24a9d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/FindPanel.java
@@ -0,0 +1,687 @@
+/*
+This file is part of the BlueJ program. 
+Copyright (C) 1999-2010,2011  Michael Kolling and John Rosenberg 
+
+This program is free software; you can redistribute it and/or 
+modify it under the terms of the GNU General Public License 
+as published by the Free Software Foundation; either version 2 
+of the License, or (at your option) any later version. 
+
+This program is distributed in the hope that it will be useful, 
+but WITHOUT ANY WARRANTY; without even the implied warranty of 
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+GNU General Public License for more details. 
+
+You should have received a copy of the GNU General Public License 
+along with this program; if not, write to the Free Software 
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+This file is subject to the Classpath exception as provided in the  
+LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.DBox;
+import bluej.utility.DBoxLayout;
+
+/**
+ * The FindPanel class implements the find functionality of the MoeEditor.
+ * It provides both the user interface panel and the high level implementation
+ * of the find functionality.It also is a link to the replace panel.
+ *
+ * @author  Marion Zalk
+ * @author  Michael Kölling
+ */
+public class FindPanel extends JPanel implements ActionListener, DocumentListener, MouseListener
+{
+    private MoeEditor editor;
+    private JComponent findBody;
+    private DBox findTextBody;
+    private DBox optionsBody;
+    private JPanel mcBody;
+    private JPanel closeBody;
+    private DBox findLabelBox;
+    private JLabel replaceLabel;
+    private JTextField findTField;
+    private JButton previousButton;
+    private JButton nextButton;
+    private JCheckBox matchCaseCheckBox;
+    private JLabel replaceIconLabel;
+    private JLabel closeIconLabel;
+    private String searchString = "";
+    private static Font findFont;
+    private ImageIcon openIcon;
+    private ImageIcon closedIcon;
+    private int searchStart = -1;
+
+    /**
+     * Constructor that creates and displays the different elements of the Find Panel
+     */
+    public FindPanel(MoeEditor ed)
+    {
+        super(new BorderLayout());
+        setBorder(BorderFactory.createEmptyBorder(2, 0, 5, 0));
+        openIcon = Config.getFixedImageAsIcon("bluej_arrow_open.gif");
+        closedIcon = Config.getFixedImageAsIcon("bluej_arrow_close.gif");
+        findFont = PrefMgr.getStandardFont();
+
+        editor = ed;
+        initDisplay();
+
+        setFindDisplay();
+        setCaseCheckDisplay();
+        setCloseDisplay();
+        setPrevNextDisplay();
+        setReplaceDisplay();
+
+        addDisplayElements();
+
+        findTField.addFocusListener(new FocusListener()
+        {
+
+            public void focusGained(FocusEvent e)
+            {
+                if (searchStart == -1) {
+                    searchStart = editor.getCurrentTextPane().getCaretPosition();
+                }
+            }
+
+            public void focusLost(FocusEvent e)
+            {
+                searchStart = -1;
+            }
+        });
+
+    }
+
+    @Override
+    public void setVisible(boolean aFlag)
+    {
+        if (aFlag && !isVisible()) {
+            // Remember the current caret location so we can revert to it if
+            // the search term cannot be found.
+            searchStart = editor.getCurrentTextPane().getSelectionStart();
+        }
+        super.setVisible(aFlag);
+        if (aFlag) {
+            findTField.requestFocus();
+        }
+    }
+
+    /**
+     * Get the maximum and preferred width of the "find:" label.
+     */
+    public int getLabelBoxWidth()
+    {
+        return findLabelBox.getPreferredSize().width;
+    }
+
+    /**
+     * Initialise the structure for the display panel
+     */
+    private void initDisplay()
+    {
+        findBody = new DBox(DBoxLayout.X_AXIS, 0, BlueJTheme.componentSpacingLarge, 0.5f);
+        findTextBody = new DBox(DBoxLayout.X_AXIS, 0, BlueJTheme.commandButtonSpacing, 0.5f);
+        //prev, next
+        optionsBody = new DBox(DBoxLayout.X_AXIS, 0, BlueJTheme.commandButtonSpacing, 0.5f);
+        mcBody = new DBox(DBoxLayout.X_AXIS, 0, 0, 0.5f);
+
+        findBody.setOpaque(false);
+        findTextBody.setOpaque(false);
+        optionsBody.setOpaque(false);
+        mcBody.setOpaque(false);
+
+        closeBody = new JPanel(new BorderLayout());
+        closeBody.setOpaque(false);
+    }
+
+    /**
+     * Initialise find buttons and labels
+     */
+    private void setFindDisplay()
+    {
+        JLabel findLabel = new JLabel(Config.getString("editor.findpanel.findLabel"));
+        findLabel.setFont(findFont);
+
+        replaceLabel = new JLabel(Config.getString("editor.replacePanel.replaceLabel"));
+        replaceLabel.setFont(findFont);
+
+        Dimension lblSize = findLabel.getPreferredSize();
+        lblSize.width = Math.max(lblSize.width, replaceLabel.getPreferredSize().width);
+
+        findLabelBox = new DBox(DBox.X_AXIS, 0.5f);
+        findLabelBox.setMaximumSize(lblSize);
+        findLabelBox.setPreferredSize(lblSize);
+        findLabelBox.add(Box.createHorizontalGlue());
+        findLabelBox.add(findLabel);
+        findLabelBox.setOpaque(false);
+
+        findTField = new JTextField(11);
+        findTField.setMaximumSize(findTField.getPreferredSize());
+        findTField.setFont(findFont);
+        setSearchString("");
+        setfindTextField("");
+        findTField.getDocument().addDocumentListener(this);
+        findTField.addActionListener(this);
+    }
+
+    /**
+     * Initialise the previous and next buttons
+     */
+    private void setPrevNextDisplay()
+    {
+        previousButton = new JButton();
+        previousButton.addActionListener(this);
+        previousButton.setText(Config.getString("editor.findpanel.findPrevious") + " ");
+        previousButton.setEnabled(false);
+        previousButton.setFont(findFont);
+
+        nextButton = new JButton();
+        nextButton.addActionListener(this);
+        nextButton.setText(Config.getString("editor.findpanel.findNext"));
+        nextButton.setEnabled(false);
+        nextButton.setFont(findFont);
+
+        if (Config.isMacOS()) {
+            previousButton.putClientProperty("JButton.buttonType", "segmentedTextured");
+            previousButton.putClientProperty("JButton.segmentPosition", "first");
+            nextButton.putClientProperty("JButton.buttonType", "segmentedTextured");
+            nextButton.putClientProperty("JButton.segmentPosition", "last");
+        }
+    }
+
+    /**
+     * Initialise the check case check box
+     */
+    private void setCaseCheckDisplay()
+    {
+        matchCaseCheckBox = new JCheckBox();
+        matchCaseCheckBox.setText(Config.getString("editor.findpanel.matchCase"));
+        matchCaseCheckBox.setSelected(false);
+        matchCaseCheckBox.setFont(findFont);
+        matchCaseCheckBox.addActionListener(this);
+        matchCaseCheckBox.setOpaque(false);
+    }
+
+    /**
+     * Returns true if the case should be matched
+     */
+    public boolean getMatchCase()
+    {
+        return matchCaseCheckBox.isSelected();
+    }
+
+    /**
+     * Initialise the close button
+     */
+    private void setCloseDisplay()
+    {
+        closeIconLabel = new JLabel();
+        closeIconLabel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 10));
+        closeIconLabel.setIcon(Config.getFixedImageAsIcon("cross.png"));
+        closeIconLabel.addMouseListener(this);
+    }
+
+    /**
+     * Initialise the buttons and labels for replace functionality
+     */
+    private void setReplaceDisplay()
+    {
+        replaceIconLabel = new JLabel(Config.getString("editor.findpanel.replacePanel"));
+        replaceIconLabel.setFont(findFont);
+        replaceIconLabel.setIcon(closedIcon);
+        replaceIconLabel.addMouseListener(this);
+    }
+
+    /**
+     * Adds the different elements into the display
+     */
+    private void addDisplayElements()
+    {
+        findTextBody.add(findLabelBox);
+        findTextBody.add(findTField);
+
+        if (Config.isMacOS()) {
+            DBox buttonBox = new DBox(DBoxLayout.X_AXIS, 0.5f);
+            buttonBox.setOpaque(false);
+            buttonBox.add(previousButton);
+            buttonBox.add(nextButton);
+            optionsBody.add(buttonBox);
+        } else {
+            optionsBody.add(previousButton);
+            optionsBody.add(nextButton);
+        }
+
+        closeBody.add(closeIconLabel, BorderLayout.EAST);
+
+        mcBody.add(matchCaseCheckBox);
+        mcBody.add(Box.createHorizontalStrut(BlueJTheme.componentSpacingLarge * 2));
+        mcBody.add(replaceIconLabel);
+
+        findBody.add(findTextBody);
+        findBody.add(optionsBody);
+        findBody.add(mcBody);
+
+        add(findBody, BorderLayout.WEST);
+        add(closeBody, BorderLayout.EAST);
+
+        KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+        this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "escapeAction");
+        this.getActionMap().put("escapeAction", new AbstractAction()
+        { //$NON-NLS-1$
+
+            public void actionPerformed(ActionEvent e)
+            {
+                close();
+            }
+        });
+
+    }
+
+    /**
+     * Performs the required action dependent on source of action event 
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        JComponent src = (JComponent) e.getSource();
+
+        if (src == nextButton || src == findTField) {
+            getNext();
+        } else if (src == previousButton) {
+            getPrev();
+        } else if (src == matchCaseCheckBox) {
+            editor.getCurrentTextPane().setCaretPosition(editor.getCurrentTextPane().getSelectionStart());
+            find(true);
+        }
+    }
+
+    /**
+     * Search forwards
+     */
+    public void getNext()
+    {
+        editor.getCurrentTextPane().setCaretPosition((editor.getCurrentTextPane().getSelectionStart() + 1));
+        find(true);
+        editor.enableReplaceButtons();
+    }
+
+    /**
+     * Search backwards
+     */
+    public void getPrev()
+    {
+        find(false);
+        editor.enableReplaceButtons();
+    }
+
+    /**
+     * Finds a instance of the search string (forward, from the current selection beginning),
+     * writes a message and moves the caret as required.
+     */
+    private void findEvent()
+    {
+        int selBegin = editor.getCurrentTextPane().getSelectionStart();
+
+        //check there has been a legitimate change in the search criteria            
+        if (getSearchString() != null) {
+            //previous search had a value and this search is empty
+            //need to remove highlighting and have no message
+            if (findTField.getText().length() == 0) {
+                //need to reset the search to the beginning of the last selected
+                editor.removeSearchHighlights();
+                setSearchString(null);
+                editor.getCurrentTextPane().setCaretPosition(selBegin);
+                writeMessage(false, 0);
+                return;
+            }
+        }
+
+        editor.getCurrentTextPane().setCaretPosition(selBegin);
+        boolean found = find(true);
+        if (!found && searchStart != -1) {
+            // If nothing found, caret should be moved back to position it was in before
+            // the search started.
+            editor.getCurrentTextPane().setCaretPosition(searchStart);
+        }
+        updateDisplay(found);
+    }
+
+    /**
+     * Display the find panel and initiate a search. If the selection is null the search
+     * the previous search String is used (if there is a previous search) 
+     */
+    public void displayFindPanel(String selection)
+    {
+        if (selection == null) {
+            selection = getSearchString();
+        }
+        setSearchString(selection);
+        this.setVisible(true);
+        populateFindTextfield(selection);
+    }
+
+    public String getSearchString()
+    {
+        return searchString;
+    }
+
+    /**
+     * Sets the text in the textfield and resets the searchString to the new text
+     * @param searchString
+     */
+    public void setSearchString(String searchString)
+    {
+        this.searchString = searchString;
+    }
+
+    /**
+     * Enable (previous and next) buttons if there is a valid search string.
+     * If not these buttons should be disabled
+     */
+    private void updateDisplay(boolean enable)
+    {
+        previousButton.setEnabled(enable);
+        nextButton.setEnabled(enable);
+        editor.enableReplaceButtons(enable);
+    }
+
+    /**
+     * When the editor finds a value it needs to reset the caret to before the search string
+     * This ensures that the find will continue to find including what has already 
+     * just been found. This is required as partial finds are done.
+     * @param src JTextField is the source and focus is reset there and searchQuery is reset
+     */
+    private void setFindValues()
+    {
+        setSearchString(findTField.getText());
+        findTField.requestFocus();
+    }
+
+    /**
+     *  HighlightAll instances of the search String with a replacement.
+     * -reset number of finds to 0
+     * -search forward or backward depending on choice
+     * -print out number of highlights 
+     */
+    public boolean highlightAll(boolean ignoreCase, boolean forwards)
+    {
+        int counter = search(ignoreCase, true, forwards);
+        //if there was nothing found, need to move the caret back to its original position
+        //also need to disable buttons accordingly
+        if (counter < 1) {
+            if (searchStart != -1) {
+                editor.getCurrentTextPane().setCaretPosition(searchStart);
+            }
+            previousButton.setEnabled(false);
+            nextButton.setEnabled(false);
+            editor.enableReplaceButtons(false);
+        }
+        writeMessage(true, counter);
+        return counter != 0;
+    }
+
+    /**
+     * Display either writes an empty message or a message reflecting the
+     * number of occurrences found
+     */
+    private void writeMessage(boolean emptyMessage, int counter)
+    {
+        if (!emptyMessage) {
+            editor.writeMessage(" ");
+            return;
+        }
+
+        if (counter > 0) {
+            if (editor.getCurrentTextPane().getSelectedText() != null) {
+                //move the caret to the beginning of the selected item
+                //editor.moveCaretPosition(editor.getCaretPosition()-getSearchString().length());
+            }
+            editor.writeMessage(Config.getString("editor.highlight.found").trim() + " "
+                    + counter + " " + Config.getString("editor.replaceAll.intancesOf").trim() + " "
+                    + getSearchString());
+        } else {
+            //only write msg if there was a search string
+            if (counter < 1 && getSearchString().length() > 0) {
+                editor.writeMessage(Config.getString("editor.replaceAll.string").trim() + " "
+                        + getSearchString() + " " + Config.getString("editor.highlight.notFound").trim());
+
+            }
+        }
+    }
+
+    /**
+     * Search either forwards or backwards for the search string, highlighting all occurrences.
+     * If no occurrences are found, the caret position is lost.
+     */
+    private int search(boolean ignoreCase, boolean wrap, boolean next)
+    {
+        String searchStr = getSearchString();
+        if (searchStr.length() == 0) {
+            return 0;
+        }
+
+        int found;
+        if (!next) {
+            editor.doFindBackward(searchStr, ignoreCase, wrap);
+        } else {
+            editor.doFind(searchStr, ignoreCase, wrap);
+        }
+
+        // position the caret so that following doFindSelect finds the correct occurrence
+        int caretPos = editor.getCurrentTextPane().getCaretPosition();
+        if (caretPos > getSearchString().length()) {
+            caretPos = editor.getCurrentTextPane().getCaretPosition() - searchStr.length();
+        }
+        editor.getCurrentTextPane().setCaretPosition(caretPos);
+        found = editor.doFindSelect(searchStr, ignoreCase, wrap);
+        return found;
+    }
+
+    /**
+     * Find the current search string in either the forwards or backwards direction, 
+     * highlighting all occurrences, and selecting the first found occurrence.
+     */
+    protected boolean find(boolean forward)
+    {
+        setFindValues();
+        editor.removeSearchHighlights();
+        return highlightAll(!matchCaseCheckBox.isSelected(), forward);
+    }
+
+    public String getSearchTextfield()
+    {
+        return findTField.getText();
+    }
+
+    public void changedUpdate(DocumentEvent e)
+    {
+    }
+
+    /**
+     * Initiates a find
+     */
+    public void insertUpdate(DocumentEvent e)
+    {
+        findEvent();
+    }
+
+    /**
+     * Initiates a find
+     */
+    public void removeUpdate(DocumentEvent e)
+    {
+        if (findTField.getText().length() == 0) {
+            //need to reset the search to the beginning of the last selected
+            editor.removeSearchHighlights();
+            editor.removeSelections();
+            setSearchString(null);
+            if (searchStart != -1) {
+                editor.getCurrentTextPane().setCaretPosition(searchStart);
+            }
+            writeMessage(false, 0);
+            updateDisplay(false);
+        } else {
+            findEvent();
+        }
+    }
+
+    public void setfindTextField(String selection)
+    {
+        findTField.setText(selection);
+    }
+
+    public void mouseClicked(MouseEvent e)
+    {
+        JComponent src = (JComponent) e.getSource();
+        if (src == closeIconLabel) {
+            close();
+            return;
+        }
+        if (src == replaceIconLabel) {
+            if (editor.isShowingInterface()) {
+                return;
+            }
+            editor.toggleReplacePanelVisible();
+            if (replaceIconLabel.getIcon() == openIcon) {
+                replaceIconLabel.setIcon(closedIcon);
+            } else if (replaceIconLabel.getIcon() == closedIcon) {
+                replaceIconLabel.setIcon(openIcon);
+            }
+        }
+    }
+
+    public void mouseEntered(MouseEvent e)
+    {
+    }
+
+    public void mouseExited(MouseEvent e)
+    {
+    }
+
+    public void mousePressed(MouseEvent e)
+    {
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+    }
+
+    public void setTextfieldSelected()
+    {
+        findTField.selectAll();
+    }
+
+    /**
+     * setFindReplaceIcon can set the icon for the replace as being open/closed
+     * @param open icon is open/closed
+     */
+    protected void setFindReplaceIcon(boolean open)
+    {
+        if (open) {
+            replaceIconLabel.setIcon(openIcon);
+        } else {
+            replaceIconLabel.setIcon(closedIcon);
+        }
+    }
+
+    /**
+     * Removes the highlights and sets the find and replace panel to invisible
+     * Also resets the replace icon to closed
+     */
+    public void close()
+    {
+        editor.removeSearchHighlights();
+        this.setVisible(false);
+        editor.setReplacePanelVisible(false);
+        editor.getCurrentTextPane().requestFocusInWindow();
+        replaceIconLabel.setIcon(closedIcon);
+    }
+
+    /**
+     * 
+     * @return text field for search text
+     */
+    protected JTextField getFindTField()
+    {
+        return findTField;
+    }
+
+    /**
+     * Puts the focus in the find field
+     */
+    protected void requestFindfieldFocus()
+    {
+        findTField.requestFocus();
+    }
+
+    /**
+     * Populates the field and puts the focus in the text field
+     */
+    protected void populateFindTextfield(String selection)
+    {
+        setfindTextField(selection);
+        findTField.selectAll();
+        findTField.requestFocus();
+    }
+
+    /**
+     * Allows the replace button to be en/disabled
+     * @param isEnable true for enable; false if not
+     */
+    protected void setReplaceEnabled(boolean isEnabled)
+    {
+        replaceIconLabel.setEnabled(isEnabled);
+        //if it is in documentation view (i.e disabled) the icon should be closed (even though it is disabled)
+        if (!isEnabled) {
+            setFindReplaceIcon(false);
+        }
+    }
+
+    /**
+     * Returns current search location
+     * @return current search location
+     */
+    protected int getSearchStart()
+    {
+        return searchStart;
+    }
+
+    /**
+     * Sets the search location to the specified value
+     * @param searchStart SourceLocation specifying the beginning of the search
+     */
+    protected void setSearchStart(int searchStart)
+    {
+        this.searchStart = searchStart;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/GoToLineDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/GoToLineDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc9e58384e401c772b027ffc3427fbe1b50d7a2c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/GoToLineDialog.java
@@ -0,0 +1,258 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.text.*;
+
+import bluej.*;
+import bluej.utility.EscapeDialog;
+
+
+/**
+ * Dialog for user to input a line number to traverse source file in editor
+ * 
+ * @author Bruce Quig
+ */
+public class GoToLineDialog extends EscapeDialog implements ActionListener
+{
+    static final String goToLineTitle = Config.getString("editor.gotoline.title");
+    static final String goToLineLabel = Config.getString("editor.gotoline.label");
+    static final String notNumericMessage = Config.getString("editor.gotoline.notNumericMessage");
+    static final String notInRangeMessage = Config.getString("editor.gotoline.notInRangeMessage");
+    static final int INVALID_NUMBER = -1;
+    
+    // -------- INSTANCE VARIABLES --------
+    private JButton okButton;
+    private JButton cancelButton;
+    private JTextField lineNumberField;
+    private JLabel instructionLabel;
+    private JLabel messageLabel;
+    private int lineNumber = INVALID_NUMBER;
+    private int sizeOfClass;
+    
+    
+    /**
+     * Creates a new GoToLineDialog object.
+     */
+    public GoToLineDialog(Frame owner)
+    {
+        super(owner, goToLineTitle, true);
+        makeDialog();
+    }
+
+    /**
+     * Make the dialod visible.
+     * @param range the number of lines of source code in source file
+     */
+    public void showDialog(int range)
+    {
+        //getRootPane().setDefaultButton(okButton);
+        sizeOfClass = range;
+        instructionLabel.setText(goToLineLabel + " ( 1 - " + range + " )"); 
+        lineNumberField.requestFocus();
+        setVisible(true);
+    }
+
+    // === Actionlistener interface ===
+
+    /**
+     * A button was pressed. Find out which one and do the appropriate thing.
+     */
+    public void actionPerformed(ActionEvent evt)
+    {
+        Object src = evt.getSource();
+
+        if (src == okButton) {
+            doOK();
+        } else if (src == cancelButton) {
+            doCancel();
+        }
+    }
+    
+    /**
+    * Setup the dialog
+    */
+    private void makeDialog()
+    {
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent E)
+            {
+                doCancel();
+            }
+        });
+       
+        
+        JPanel bodyPanel = new JPanel();
+        bodyPanel.setLayout(new BoxLayout(bodyPanel, BoxLayout.Y_AXIS));
+        bodyPanel.setBorder(BorderFactory.createEmptyBorder(10, 20, 20, 20));
+   
+        instructionLabel = new JLabel(goToLineLabel);
+        bodyPanel.add(instructionLabel);
+        bodyPanel.add(Box.createVerticalStrut(6));
+   
+        lineNumberField = new JTextField();
+        bodyPanel.add(lineNumberField);
+        bodyPanel.add(Box.createVerticalStrut(6));
+        
+        IntegerDocument integerDocument1 = new IntegerDocument();
+        lineNumberField.setDocument(integerDocument1);
+        
+        messageLabel = new JLabel(" ");
+        bodyPanel.add(messageLabel);
+        bodyPanel.add(Box.createVerticalStrut(6));
+        
+        // add buttons
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+        buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+        okButton = BlueJTheme.getOkButton();
+        okButton.addActionListener(this);
+
+        cancelButton = BlueJTheme.getCancelButton();
+        cancelButton.addActionListener(this);
+
+        buttonPanel.add(okButton);
+        buttonPanel.add(cancelButton);
+        getRootPane().setDefaultButton(okButton);
+        
+        bodyPanel.add(buttonPanel);
+        getContentPane().add(bodyPanel, BorderLayout.CENTER);
+        pack();
+      
+    }
+    
+    /**
+     * When ok button is selected
+     */
+    private void doOK()
+    {
+        lineNumber = validateInput();
+        clear();
+        setVisible(false);   
+    }
+    
+    /**
+     * When cancel button is selected
+     */
+    private void doCancel()
+    {
+        lineNumber = INVALID_NUMBER;
+        setVisible(false);   
+    }
+    /**
+    * Clear the line number text field
+    */
+    private void clear()
+    {
+        lineNumberField.setText("");   
+    }
+    
+    /**
+    * Returns the lineNumber.
+    * @return the line number entered, returns -1 if input is invalid
+    */
+    public int getLineNumber() 
+    {
+        return lineNumber;
+    }
+    
+    /**
+     * Convert input field contents to an int
+     * @return int the String input value as an int 
+     * representing line number
+     */
+    private int validateInput()
+    {
+        int validatedNumber = -1;
+        try {
+            validatedNumber = Integer.parseInt(lineNumberField.getText());
+        } catch (NumberFormatException nfe) {
+         	//shouldn't happen, verified at data model level
+        }
+        return validatedNumber;
+    }
+    
+    /**
+    * Inner class that provides the formatted (Integer only) data model
+    * for the line number text field
+    */
+    class IntegerDocument extends PlainDocument 
+    {
+        /**
+        * Inserts into Document model.  Checks for format and for range
+        */
+        public void insertString(int offset, String string, AttributeSet attributes)
+            throws BadLocationException 
+        {
+            if (string == null) {
+                return;
+            } else {
+                String newValue;
+                int length = getLength();
+                if (length == 0) {
+                    newValue = string;
+                } else {
+                    String currentContent = getText(0, length);
+                    StringBuffer currentBuffer = new StringBuffer(currentContent);
+                    currentBuffer.insert(offset, string);
+                    newValue = currentBuffer.toString();
+                }
+                try {
+                    int parsedNumber = checkInputIsInteger(newValue);
+                    if(checkInputRange(parsedNumber)) {
+                        super.insertString(offset, string, attributes);
+                        messageLabel.setText(" ");
+                    }
+                } catch (NumberFormatException exception) {
+                    Toolkit.getDefaultToolkit().beep();
+                    messageLabel.setText(notNumericMessage);
+                }
+            }
+        }
+      
+        /**
+        * Check that the String is an integer
+        */
+        private int checkInputIsInteger(String proposedValue) 
+           throws NumberFormatException 
+        {
+            int newValue = 0;
+            if (proposedValue.length() > 0) {
+                newValue = Integer.parseInt(proposedValue);
+            }
+            return newValue;
+        }
+       
+        /**
+        * Check that the int parameter is within range, meaning that it is 
+        * greater than 0 and not greater than the number of lines in the source file
+        */
+        private boolean checkInputRange(int parsedNumber)
+        {
+            return(parsedNumber > 0 && parsedNumber <= sizeOfClass);   
+        }
+    }
+} // end class GoToLineDialog
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/Info.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/Info.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf3938ca4d79a7d28e24a43688ee8de2ad38e9aa
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/Info.java
@@ -0,0 +1,303 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.DialogManager;
+import bluej.utility.BlueJFileReader;
+
+import bluej.utility.Utility;
+import java.awt.*;              // MenuBar, MenuItem, Menu, Button, etc.
+import java.awt.event.*;        // New Event model
+import javax.swing.*;           // all the GUI components
+import java.io.*;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * An information panel, displayed at the bottom of a MoeEditor window. The panel can
+ * display error messages / notices to the user, and has a "?" button which can be
+ * used to request additional help on compiler errors.
+ *
+ * @author Michael Kolling
+ */
+public final class Info extends JPanel
+    implements ActionListener
+{
+    static final ImageIcon helpImage = Config.getFixedImageAsIcon("help.png");
+
+    private static Font infoFont = new Font("SansSerif", Font.BOLD, PrefMgr.getEditorFontSize() - 1);
+
+    // -------- INSTANCE VARIABLES --------
+
+    private JLabel line1;
+    private JLabel line2;
+    String originalMsg;
+    boolean isClear;
+    JButton helpButton;
+    String helpGroup;
+
+    // ------------- METHODS --------------
+
+    /**
+     * Construct a new Info instance.
+     */
+    public Info()
+    {
+        super();
+        setLayout(new BorderLayout());
+        setBorder(BorderFactory.createLineBorder(Color.black));
+
+        JPanel body = new JPanel(new GridLayout(0, 1)); // one col, many rows
+        body.setBackground(MoeEditor.infoColor);
+        body.setBorder(new EmptyBorder(0,6,0,4));
+        line1 = new JLabel() {
+            public void setBounds(int x, int y, int width, int height)
+            {
+                super.setBounds(x,y,width,height);
+                if (originalMsg != null) {
+                    rebreakLine();
+                }
+            };
+        };
+        line2 = new JLabel();
+        body.add(line1);
+        body.add(line2);
+        body.setOpaque(false);
+        add(body, BorderLayout.CENTER);
+
+        helpButton = new JButton(helpImage);
+        if (!Config.isMacOS()) {
+            helpButton.setMargin(new Insets(0,0,0,0));
+        }
+        else {
+            Utility.changeToMacButton(helpButton);
+        }
+        helpButton.addActionListener(this);
+        helpButton.setRequestFocusEnabled(false);   // never get focus
+        add(helpButton, BorderLayout.EAST);
+        helpButton.setVisible(false);
+
+        isClear = true;
+        helpGroup = "";
+        refresh();
+    }
+    
+    /**
+     * Reset the font size for all Info instances - each instance must be
+     * individually refresh()ed after calling this.
+     */
+    public static void resetFont()
+    {
+        int fsize = Math.max(PrefMgr.getEditorFontSize() - 1, 1);
+        infoFont = new Font("SansSerif", Font.BOLD, fsize);
+    }
+
+    /**
+     * display a one- or two-line message (using '\n' to separate multiple lines)
+     */
+    public void message(String msg)
+    {
+        originalMsg = msg;
+        rebreakLine();
+        isClear = false;
+        hideHelp();
+    }
+    
+    /**
+     * Find a suitable place to split the original message over the two lines,
+     * and do so.
+     */
+    private void rebreakLine()
+    {
+        int newline = originalMsg.indexOf('\n');
+        
+        String firstLine, secondLine;
+        
+        if (newline == -1) {
+            int ipos = breakLine(originalMsg);
+            if(originalMsg.length() <= ipos) {
+                firstLine = originalMsg;
+                secondLine = "";
+            }
+            else {
+                // look for a suitable place to break to a new line
+                int lspace = originalMsg.lastIndexOf(' ', ipos);
+                int tspace = originalMsg.lastIndexOf('\t', ipos);
+                int space = Math.max(lspace, tspace);
+                if (space > ipos / 2) {
+                    // Roughly: if breaking at the space means breaking before the halfway point,
+                    // don't do it.
+                    ipos = space;
+                }
+                
+                firstLine = originalMsg.substring(0, ipos);
+                secondLine = originalMsg.substring(ipos);
+            }
+        }
+        else {
+            firstLine = originalMsg.substring(0, newline);
+            secondLine = originalMsg.substring(newline+1);
+        }
+        
+        secondLine = secondLine.replace("\n", ";  ");
+        line1.setText(firstLine);
+        line2.setText(secondLine);
+    }
+
+    /**
+     * Calculate at which character to break a line across the line1 label
+     */
+    private int breakLine(String msg)
+    {
+        if (msg.length() <= 2) {
+            return msg.length(); // don't even bother
+        }
+        
+        FontMetrics metrics = line1.getFontMetrics(line1.getFont());
+        Insets insets = line1.getInsets();
+        int hInsets = 0;
+        if (insets != null) {
+            hInsets = insets.left + insets.right;
+        }
+        int lineWidth = line1.getWidth() - hInsets;
+        
+        char [] charBuf = new char[msg.length()];
+        msg.getChars(0, msg.length(), charBuf, 0);
+        int curWidth = metrics.charsWidth(charBuf, 0, charBuf.length);
+        if (curWidth < lineWidth) {
+            return charBuf.length;
+        }
+        
+        int lowerBound = 1;
+        int upperBound = charBuf.length;
+        
+        while (lowerBound != upperBound) {
+            int mid = (lowerBound + upperBound + 1) / 2; // favour towards the upper bound
+            curWidth = metrics.charsWidth(charBuf, 0, mid);
+            if (curWidth < lineWidth) {
+                lowerBound = mid;
+            }
+            else {
+                upperBound = Math.min(mid, upperBound - 1);
+            }
+        }
+        
+        return lowerBound;
+    }
+    
+    /**
+     * display a two line message
+     */
+    public void message(String msg1, String msg2)
+    {
+        message(msg1 + '\n' + msg2);
+    }
+
+    /**
+     * display a one- or two-line warning (message with beep). Separate lines should
+     * be delimited with '\n'.
+     */
+    public void warning(String msg)
+    {
+        message (msg);
+        MoeEditorManager.editorManager.beep();
+    }
+
+    /**
+     * display a two line warning (message with beep)
+     */
+    public void warning(String msg1, String msg2)
+    {
+        message (msg1, msg2);
+        MoeEditorManager.editorManager.beep();
+    }
+
+    /**
+     * clear the display
+     */
+    public void clear()
+    {
+        if (!isClear) {
+            message (" ", " ");
+            isClear = true;
+        }
+    }
+
+    /**
+     * Refresh display parameters (font size).
+     */
+    public void refresh()
+    {
+        line1.setFont(infoFont);
+        line2.setFont(infoFont);
+    }
+    
+    /**
+     * Set the "help group" (the name of the compiler, used to locate the additional
+     * help text for error messages)
+     */
+    public void setHelp(String helpGroup)
+    {
+        this.helpGroup = helpGroup;
+        helpButton.setVisible(true);
+    }
+
+    /**
+     * Hide the "additional error message help" button.
+     */
+    private void hideHelp()
+    {
+        helpButton.setVisible(false);
+    }
+
+    // ---- ActionListener interface ----
+
+    public void actionPerformed(ActionEvent evt)
+    {
+        displayHelp(helpGroup);
+    }
+
+    private void displayHelp(String helpGroup)
+    {
+        File fileName = Config.getLanguageFile(helpGroup + ".help");
+        int i = originalMsg.indexOf('\n');
+        
+        String line;
+        if (i<0) {
+            line = originalMsg;
+        } else {
+            line = originalMsg.substring(0,i);   
+        }
+        
+        String helpText = BlueJFileReader.readHelpText(fileName, line.trim(),
+                                                       false);
+
+        if(helpText == null) {
+            DialogManager.showMessageWithText(null, "no-help",
+                                              "\n" + originalMsg);
+        }
+        else {
+            DialogManager.showText(null, originalMsg + "\n\n" + helpText);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/KeyBindingsPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/KeyBindingsPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..7374c9fdc3eb6a21837c861fc13e9b9facd5c46d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/KeyBindingsPanel.java
@@ -0,0 +1,475 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Event;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
+import java.util.Properties;
+
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.FocusManager;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import bluej.Config;
+import bluej.prefmgr.PrefPanelListener;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+
+/**
+ * KeyBindingsPanel panel for the key bindings in preferences
+ * @author Marion Zalk
+ *
+ */
+public class KeyBindingsPanel extends JPanel implements ActionListener, ListSelectionListener, ItemListener, PrefPanelListener
+{
+
+    // -------- CONSTANTS --------
+    static final String title = Config.getString("editor.functions.title");
+    static final String close = Config.getString("close");
+    static final String defaultsLabel = Config.getString("editor.functions.defaults");
+    static final String categoriesLabel = Config.getString("editor.functions.categories");
+    static final String keyLabel = Config.getString("editor.functions.keys");
+    static final String addKeyLabel = Config.getString("editor.functions.addkey");
+    static final String delKeyLabel = Config.getString("editor.functions.delkey");
+
+    // -------- INSTANCE VARIABLES --------
+
+    private FocusManager focusMgr;
+    private JButton defaultsButton;
+    private JButton addKeyButton;
+    private JButton delKeyButton;
+    private JComboBox categoryMenu;
+    private JList functionList;
+    private JList keyList;
+    private JTextArea helpLabel;
+
+    private MoeActions actions;     // The Moe action manager
+    private Action currentAction;       // the action currently selected
+    private KeyStroke[] currentKeys;    // key strokes currently displayed
+
+    private int firstDisplayedFunc; // index of first function in list
+    private Properties help;
+    private Action[] functions;     // all user functions
+    private String[] categories;
+    private int[] categoryIndex;   // an array of indexes into "functions"
+
+    public void actionPerformed(ActionEvent event) {
+        Object src = event.getSource();
+        if(src == defaultsButton)
+            handleDefaults();
+        else if(src == addKeyButton)
+            handleAddKey();
+        else if(src == delKeyButton)
+            handleDelKey();
+
+    }
+
+
+    public void valueChanged(ListSelectionEvent event) {
+        if(event.getValueIsAdjusting())  // ignore mouse down, dragging, etc.
+            return;
+
+        Object src = event.getSource();
+
+        if(src == functionList)
+            handleFuncListSelect();
+        else if(src == keyList)
+            handleKeyListSelect();
+
+    }
+
+    public void itemStateChanged(ItemEvent e) {
+        int selected = categoryMenu.getSelectedIndex();
+
+        firstDisplayedFunc = categoryIndex[selected];
+        int lastFunc = categoryIndex[selected + 1];
+
+        String[] names = new String[lastFunc - firstDisplayedFunc];
+
+        for(int i = firstDisplayedFunc; i < lastFunc; i++) {
+            names[i-firstDisplayedFunc] = 
+                (String)functions[i].getValue(Action.NAME);
+        }
+        functionList.setListData(names);
+        clearKeyList();
+        clearHelpText();
+        addKeyButton.setEnabled(false);
+        delKeyButton.setEnabled(false);
+        currentAction = null;
+        currentKeys = null;
+
+    }
+
+    public JPanel makePanel(){
+        GridLayout gridL=new GridLayout(1, 2);
+        JPanel mainPanel = new JPanel(gridL);  // has BorderLayout
+        mainPanel.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
+
+        // create function list area
+        JPanel funcPanel = new JPanel(new BorderLayout());
+        funcPanel.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
+        functionList = new JList();
+        functionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        functionList.addListSelectionListener(this);
+        functionList.setVisibleRowCount(12);
+        JScrollPane scrollPane = new JScrollPane(functionList);
+        funcPanel.add(scrollPane);
+
+        JPanel categoryPanel = new JPanel();
+        JLabel label = new JLabel(categoriesLabel);
+        categoryPanel.add(label);
+        categoryMenu = new JComboBox();
+        categoryPanel.add(categoryMenu);
+        funcPanel.add(categoryPanel, BorderLayout.NORTH);
+
+        // create control area on right (key bindings and buttons)
+        JPanel controlPanel = new JPanel(new BorderLayout());
+        controlPanel.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
+        // create area for key bindings
+        JPanel keyPanel = new JPanel(new BorderLayout());
+        JLabel kLabel=new JLabel(keyLabel);
+        kLabel.setPreferredSize(categoryMenu.getPreferredSize());
+        keyPanel.add(kLabel , BorderLayout.NORTH);
+        keyList = new JList();
+        keyList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        keyList.setPrototypeCellValue("shift-ctrl-delete"); 
+        keyList.setVisibleRowCount(4);
+        scrollPane = new JScrollPane(keyList);
+        keyPanel.add(scrollPane, BorderLayout.CENTER);
+
+        JPanel keyButtonPanel = new JPanel();
+        addKeyButton = new JButton(addKeyLabel);
+        addKeyButton.setMargin(new Insets(2,2,2,2));
+        keyButtonPanel.add(addKeyButton);
+
+        delKeyButton = new JButton(delKeyLabel);
+        delKeyButton.setMargin(new Insets(2,2,2,2));
+        keyButtonPanel.add(delKeyButton);
+
+        defaultsButton = new JButton(defaultsLabel);
+        keyButtonPanel.add(defaultsButton);
+        keyPanel.add(keyButtonPanel, BorderLayout.SOUTH);
+        controlPanel.add(keyPanel);
+
+        // create help text area at bottom
+        JPanel helpPanel = new JPanel(new GridLayout());
+        helpPanel.setBorder(BorderFactory.createCompoundBorder(
+                BorderFactory.createEmptyBorder(10,0,0,0),
+                BorderFactory.createLineBorder(Color.black)));
+        helpLabel=new JTextArea();
+        helpLabel.setRows(6);
+        helpLabel.setLineWrap(true);
+        helpLabel.setWrapStyleWord(true);
+        helpLabel.setBackground(MoeEditor.infoColor);
+        helpPanel.add(helpLabel);
+        controlPanel.add(helpPanel,BorderLayout.SOUTH);
+
+        mainPanel.add(funcPanel);
+        mainPanel.add(controlPanel);
+        updateDispay();
+
+        return mainPanel;
+    }
+
+    public void beginEditing() {
+       
+    }
+
+    public void commitEditing() {
+       handleClose();
+    }
+
+    public void revertEditing() {
+        
+    }
+
+    /**
+     * 
+     * @param actiontable
+     * @param categories
+     * @param categoryIndex
+     */
+    public void setActionValues(Action[] actiontable, 
+            String[] categories, int[] categoryIndex){
+        this.categories=categories;
+        functions = actiontable;
+        this.categoryIndex=categoryIndex;
+    }
+
+    /**
+     * 
+     */
+    public void updateDispay()
+    {
+        categoryMenu.addItemListener(this);
+        delKeyButton.addActionListener(this);
+        addKeyButton.addActionListener(this);
+        keyList.addListSelectionListener(this);
+        defaultsButton.addActionListener(this);
+        focusMgr = FocusManager.getCurrentManager();
+        openHelpFile();
+        for(int i=0; i<categories.length; i++)
+            categoryMenu.addItem(categories[i]);
+    }
+
+    class KeyCatcher extends FocusManager {
+
+        public void processKeyEvent(Component focusedComponent,
+                KeyEvent e) 
+        { 
+            if(e.getID() != KeyEvent.KEY_PRESSED)
+                return;
+
+            int keyCode = e.getKeyCode();
+
+            if(keyCode == KeyEvent.VK_CAPS_LOCK ||    // the keys we want to ignore...
+                    keyCode == KeyEvent.VK_SHIFT ||
+                    keyCode == KeyEvent.VK_CONTROL ||
+                    keyCode == KeyEvent.VK_META ||
+                    keyCode == KeyEvent.VK_ALT ||
+                    keyCode == KeyEvent.VK_ALT_GRAPH ||
+                    keyCode == KeyEvent.VK_COMPOSE ||
+                    keyCode == KeyEvent.VK_NUM_LOCK ||
+                    keyCode == KeyEvent.VK_SCROLL_LOCK ||
+                    keyCode == KeyEvent.VK_UNDEFINED
+            )
+                return;
+
+            if(currentAction == null)
+                Debug.message("FunctionDialog: currentAction is null...");
+            else {
+                KeyStroke key = KeyStroke.getKeyStrokeForEvent(e);
+                if(isPrintable(key, e))
+                    helpLabel.setText(getHelpText("cannot-redefine"));
+                else {
+                    actions.addActionForKeyStroke(key, currentAction);
+                    handleFuncListSelect();
+                }
+            }
+            e.consume();
+            removeKeyListener();
+        }
+
+        private boolean isPrintable(KeyStroke key, KeyEvent e)
+        {
+            // all control and alt keys are non-printable
+            int modifiers = key.getModifiers();
+            if(modifiers != 0 && modifiers != Event.SHIFT_MASK)
+                return false;
+
+            // action keys are non-printable
+            if(e.isActionKey())
+                return false;
+
+            // some action keys that the above function not recognises
+            int keyCode = e.getKeyCode();
+            if(keyCode == KeyEvent.VK_BACK_SPACE ||
+                    keyCode == KeyEvent.VK_DELETE ||
+                    keyCode == KeyEvent.VK_ENTER ||
+                    keyCode == KeyEvent.VK_TAB ||
+                    keyCode == KeyEvent.VK_ESCAPE)
+                return false;
+
+            // otherwise it's printable
+            return true;
+        }
+
+        public void focusNextComponent(Component c) {}
+        public void focusPreviousComponent(Component c) {}
+    }
+
+    /**
+     * Handle click on Defaults button.
+     */
+    private void handleDefaults()
+    {
+        int answer = DialogManager.askQuestion(this, "default-keys");
+        if(answer == 0) {
+            actions.setDefaultKeyBindings();
+            handleFuncListSelect();
+        }
+    }
+
+    /**
+     * Handle click in functions list.
+     */
+    private void handleFuncListSelect()
+    {
+        int index = functionList.getSelectedIndex();
+        if(index == -1)
+            return; // deselection event - ignore
+
+        // find selected action
+
+        currentAction = functions[firstDisplayedFunc + index];
+
+        // display keys and help text
+
+        updateKeyList(currentAction);
+        String helpText = 
+            getHelpText((String)currentAction.getValue(Action.NAME));
+        helpLabel.setText(helpText);
+    }
+
+    /**
+     * Handle click in key bindings list.
+     */
+    private void handleKeyListSelect()
+    {
+        delKeyButton.setEnabled(true);
+    }
+
+    /**
+     * Handle click on Close button.
+     */
+    private void handleClose()
+    {
+        removeKeyListener();
+        if(!actions.save())
+            DialogManager.showError(this, "cannot-save-keys");
+        setVisible(false);
+    }
+    /**
+     * Handle click on Add Key button.
+     */
+    private void handleAddKey()
+    {
+        helpLabel.setText(getHelpText("press-key"));
+        addKeyListener();
+    }
+
+    /**
+     * Handle click on Delete Key button.
+     */
+    private void handleDelKey()
+    {
+        if(currentKeys == null)
+            return;             // something went wrong here...
+
+        int index = keyList.getSelectedIndex();
+        if(index == -1)
+            return;             // deselection event - ignore
+
+        actions.removeKeyStrokeBinding(currentKeys[index]);
+        updateKeyList(currentAction);
+    }
+
+    /**
+     * Display key bindings in the key list
+     */
+    private void updateKeyList(Action action)
+    {
+        currentKeys = actions.getKeyStrokesForAction(action);
+        if(currentKeys == null)
+            clearKeyList();
+        else {
+            String[] keyStrings = getKeyStrings(currentKeys);
+            keyList.setListData(keyStrings);
+            delKeyButton.setEnabled(false);
+        }
+        addKeyButton.setEnabled(true);
+    }
+
+    /**
+     * Translate KeyStrokes into String representation.
+     */
+    private String[] getKeyStrings(KeyStroke[] keys)
+    {
+        String[] keyStrings = new String[keys.length];
+        for(int i = 0; i < keys.length; i++) {
+            int modifiers = keys[i].getModifiers();
+            keyStrings[i] = KeyEvent.getKeyModifiersText(modifiers);
+            if(keyStrings[i].length() > 0)
+                keyStrings[i] += "+";
+            keyStrings[i] += KeyEvent.getKeyText(keys[i].getKeyCode());
+        }
+        return keyStrings;
+    }
+
+    private void clearKeyList()
+    {
+        keyList.setListData(new String[0]);
+    }
+
+    private void clearHelpText()
+    {
+        helpLabel.setText(null);
+    }
+
+    private void openHelpFile()
+    {
+        help = Config.getMoeHelp();
+    }
+
+    private String getHelpText(String function)
+    {
+        if(help == null)
+            return null;
+        String helpText=help.getProperty(function);
+        //need to check if null first as some items do not have helpText/helpText is empty
+        if (helpText!=null && helpText.length()>0) {
+            //remove the /n from the text 
+            helpText=helpText.replaceAll("\n", "");
+            helpText=helpText.trim();
+        }
+        return helpText;
+    }
+
+    private void addKeyListener()
+    {
+        FocusManager.setCurrentManager(new KeyCatcher());
+    }
+
+    private void removeKeyListener()
+    {
+        FocusManager.setCurrentManager(focusMgr);
+    }
+
+
+    public KeyBindingsPanel() {
+        super();
+        actions = MoeActions.getActions(new JEditorPane());
+        setActionValues(actions.getActionTable(), actions.getCategories(), actions.getCategoryIndex());
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeActions.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeActions.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e2a5fc5be0af7a88f95c48ba2a795e1bab5b72e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeActions.java
@@ -0,0 +1,2578 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Container;
+import java.awt.Event;
+import java.awt.Font;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.swing.Action;
+import javax.swing.InputMap;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JOptionPane;
+import javax.swing.KeyStroke;
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Caret;
+import javax.swing.text.DefaultEditorKit;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.Keymap;
+import javax.swing.text.TextAction;
+import javax.swing.undo.CannotRedoException;
+import javax.swing.undo.CannotUndoException;
+
+import bluej.Config;
+import bluej.debugger.gentype.JavaType;
+import bluej.editor.moe.MoeIndent.AutoIndentInformation;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.nodes.CommentNode;
+import bluej.parser.nodes.MethodNode;
+import bluej.parser.nodes.ParsedNode;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+import bluej.prefmgr.PrefMgr;
+import bluej.prefmgr.PrefMgrDialog;
+import bluej.utility.Debug;
+
+/**
+ * A set of actions supported by the Moe editor. This is a singleton: the
+ * actions are shared between all editor instances.
+ * 
+ * Actions are stored both in a hash-map and in an array. The hash-map is used
+ * for fast lookup by name, whereas the array is needed to support complete,
+ * ordered access.
+ * 
+ * @author Michael Kolling
+ * @author Bruce Quig
+ */
+
+public final class MoeActions
+{
+    // -------- CONSTANTS --------
+
+    private static final String KEYS_FILE = "editor.keys";
+
+    private static int SHORTCUT_MASK;
+    private static int ALT_SHORTCUT_MASK;
+    private static int SHIFT_SHORTCUT_MASK;
+    private static int SHIFT_ALT_SHORTCUT_MASK;
+    private static int DOUBLE_SHORTCUT_MASK; // two masks (ie. CTRL + META)
+
+    private static final int tabSize = Config.getPropInteger("bluej.editor.tabsize", 4);
+    private static final String spaces = "                                        ";
+    private static final char TAB_CHAR = '\t';
+
+    // -------- INSTANCE VARIABLES --------
+
+    private Action[] actionTable; // table of all known actions
+    private HashMap<Object, Action> actions; // the same actions in a hash-map
+    private String[] categories;
+    public Action[] getActionTable() {
+        return actionTable;
+    }
+
+    public void setActionTable(Action[] actionTable) {
+        this.actionTable = actionTable;
+    }
+
+    public String[] getCategories() {
+        return categories;
+    }
+
+    public void setCategories(String[] categories) {
+        this.categories = categories;
+    }
+
+    public int[] getCategoryIndex() {
+        return categoryIndex;
+    }
+
+    public void setCategoryIndex(int[] categoryIndex) {
+        this.categoryIndex = categoryIndex;
+    }
+
+    private int[] categoryIndex;
+
+    private Keymap keymap; // the editor's keymap
+    private KeyCatcher keyCatcher;
+
+    private boolean lastActionWasCut; // true if last action was a cut action
+    // undo helpers
+    public UndoAction undoAction;
+    public RedoAction redoAction;
+
+    public FindNextAction findNextAction;
+    public FindNextBackwardAction findNextBackwardAction;
+
+    // frequently needed actions
+    public Action compileAction;
+    public Action contentAssistAction;
+
+    // for bug workaround:
+    private InputMap componentInputMap;
+
+    // =========================== STATIC METHODS ===========================
+
+    private static MoeActions moeActions;
+
+    private Action[] overrideActions;
+
+    /**
+     * Get the actions object (a singleton) and, at the same time, install the
+     * action keymap as the main keymap for the given textComponent..
+     */
+    public static MoeActions getActions(JTextComponent textComponent)
+    {
+        if (moeActions == null)
+            moeActions = new MoeActions(textComponent);
+
+        if (textComponent != null) {
+            textComponent.setKeymap(moeActions.keymap);
+            moeActions.overrideActions(textComponent);
+        }
+       
+        return moeActions;
+    }
+
+    // ========================== INSTANCE METHODS ==========================
+
+    private void overrideActions(JTextComponent textComponent)
+    {       
+        for (Action action : overrideActions) {
+            textComponent.getActionMap().put(action.getValue(Action.NAME), action);
+        }
+    }
+
+    /**
+     * Constructor. Singleton, thus private.
+     */
+    private MoeActions(JTextComponent textComponent)
+    {
+        // sort out modifier keys...
+        SHORTCUT_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+        if (SHORTCUT_MASK == Event.CTRL_MASK)
+            ALT_SHORTCUT_MASK = Event.META_MASK; // alternate (second) modifier
+        else
+            ALT_SHORTCUT_MASK = Event.CTRL_MASK;
+
+        SHIFT_SHORTCUT_MASK = SHORTCUT_MASK + Event.SHIFT_MASK;
+        SHIFT_ALT_SHORTCUT_MASK = Event.SHIFT_MASK + ALT_SHORTCUT_MASK;
+        DOUBLE_SHORTCUT_MASK = SHORTCUT_MASK + ALT_SHORTCUT_MASK;
+
+        // install our own keymap, with the existing one as parent
+        Keymap origKeymap = textComponent.getKeymap();
+        keymap = JTextComponent.addKeymap("BlueJ map", origKeymap);
+
+        createActionTable(textComponent);
+        keyCatcher = new KeyCatcher();
+        if (!load())
+            setDefaultKeyBindings();
+        lastActionWasCut = false;
+
+        // for bug workaround (below)
+        componentInputMap = textComponent.getInputMap();
+    }
+
+    public void setUndoEnabled(boolean enabled)
+    {
+        undoAction.setEnabled(enabled);
+    }
+
+    public void setRedoEnabled(boolean enabled)
+    {
+        redoAction.setEnabled(enabled);
+    }
+
+    public void setPasteEnabled(boolean enabled)
+    {
+        actions.get(DefaultEditorKit.pasteAction).setEnabled(enabled);
+    }
+
+    public FindNextAction getFindNextAction()
+    {
+        return findNextAction;
+    }
+
+    public FindNextBackwardAction getFindNextBackwardAction()
+    {
+        return findNextBackwardAction;
+    }
+
+    /**
+     * Allow the enabling/disabling of an action. 
+     * @param action  String representing name of action
+     * @param flag  true to enable action from menu.
+     */
+
+    public void enableAction(String action, boolean flag)
+    {
+        Action moeAction = getActionByName(action);
+        if (moeAction != null) {
+            moeAction.setEnabled(flag);
+        }
+    }
+
+
+    /**
+     * Return an action with a given name.
+     */
+    public Action getActionByName(String name)
+    {
+        return (Action) (actions.get(name));
+    }
+
+    /**
+     * Get a keystroke for an action. Return null is there is none.
+     */
+    public KeyStroke[] getKeyStrokesForAction(Action action)
+    {
+        KeyStroke[] keys = keymap.getKeyStrokesForAction(action);
+        keys = addComponentKeyStrokes(action, keys); // BUG workaround
+        if (keys != null && keys.length > 0)
+            return keys;
+        else
+            return null;
+    }
+
+    /**
+     * BUG WORKAROUND: currently, keymap.getKeyStrokesForAction() misses
+     * keystrokes that come from JComponents inputMap. Here, we add those
+     * ourselves...
+     */
+    public KeyStroke[] addComponentKeyStrokes(Action action, KeyStroke[] keys)
+    {
+        ArrayList<KeyStroke> keyStrokes = null;
+        KeyStroke[] componentKeys = componentInputMap.allKeys();
+
+        // find all component keys that bind to this action
+        for (int i = 0; i < componentKeys.length; i++) {
+            if (componentInputMap.get(componentKeys[i]).equals(action.getValue(Action.NAME))) {
+                if (keyStrokes == null)
+                    keyStrokes = new ArrayList<KeyStroke>();
+                keyStrokes.add(componentKeys[i]);
+            }
+        }
+
+        // test whether this keyStroke was redefined in keymap
+        if (keyStrokes != null) {
+            for (Iterator<KeyStroke> i = keyStrokes.iterator(); i.hasNext();) {
+                if (keymap.getAction((KeyStroke) i.next()) != null) {
+                    i.remove();
+                }
+            }
+        }
+
+        // merge found keystrokes into key array
+        if ((keyStrokes == null) || (keyStrokes.isEmpty()))
+            return keys;
+
+        KeyStroke[] allKeys;
+        if (keys == null) {
+            allKeys = new KeyStroke[keyStrokes.size()];
+            keyStrokes.toArray(allKeys);
+        }
+        else { // merge new keystrokes into keys
+            allKeys = new KeyStroke[keyStrokes.size() + keys.length];
+            keyStrokes.toArray(allKeys);
+            System.arraycopy(allKeys, 0, allKeys, keys.length, keyStrokes.size());
+            System.arraycopy(keys, 0, allKeys, 0, keys.length);
+        }
+        return allKeys;
+    }
+
+    /**
+     * Add a new key binding into the action table.
+     */
+    public void addActionForKeyStroke(KeyStroke key, Action a)
+    {
+        keymap.addActionForKeyStroke(key, a);
+    }
+
+    /**
+     * Remove a key binding from the action table.
+     */
+    public void removeKeyStrokeBinding(KeyStroke key)
+    {
+        keymap.removeKeyStrokeBinding(key);
+    }
+
+    /**
+     * Save the key bindings. Return true if successful.
+     */
+    public boolean save()
+    {
+        try {
+            File file = Config.getUserConfigFile(KEYS_FILE);
+            FileOutputStream ostream = new FileOutputStream(file);
+            ObjectOutputStream stream = new ObjectOutputStream(ostream);
+            KeyStroke[] keys = keymap.getBoundKeyStrokes();
+            stream.writeInt(MoeEditor.version);
+            stream.writeInt(keys.length);
+            for (int i = 0; i < keys.length; i++) {
+                stream.writeObject(keys[i]);
+                stream.writeObject(keymap.getAction(keys[i]).getValue(Action.NAME));
+            }
+            stream.flush();
+            ostream.close();
+            return true;
+        }
+        catch (Exception exc) {
+            Debug.message("Cannot save key bindings: " + exc);
+            return false;
+        }
+    }
+
+    /**
+     * Load the key bindings. Return true if successful.
+     */
+    public boolean load()
+    {
+        try {
+            File file = Config.getUserConfigFile(KEYS_FILE);
+            FileInputStream istream = new FileInputStream(file);
+            ObjectInputStream stream = new ObjectInputStream(istream);
+            //KeyStroke[] keys = keymap.getBoundKeyStrokes();
+            int version = 0;
+            int count = stream.readInt();
+            if (count > 100) { // it was new format: version number stored first
+                version = count;
+                count = stream.readInt();
+            }
+            if (Config.isMacOS() && (version < 140)) {
+                // do not attempt to load old bindings on MacOS when switching
+                // to jdk 1.4.1
+                return false;
+            }
+
+            for (int i = 0; i < count; i++) {
+                KeyStroke key = (KeyStroke) stream.readObject();
+                String actionName = (String) stream.readObject();
+                Action action = (Action) (actions.get(actionName));
+                if (action != null) {
+                    keymap.addActionForKeyStroke(key, action);
+                }
+            }
+            istream.close();
+
+            // set up bindings for new actions in recent releases
+
+            if (version < 252) {
+                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, SHORTCUT_MASK),
+                        (Action) (actions.get("increase-font")));
+                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, SHORTCUT_MASK),
+                        (Action) (actions.get("decrease-font")));
+            }
+            if (version < 300) {
+                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, Event.CTRL_MASK), (Action) (actions
+                        .get("code-completion")));
+                keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_I, SHIFT_SHORTCUT_MASK ), (Action) (actions
+                        .get("autoindent")));
+            }
+            return true;
+        }
+        catch (Exception exc) {
+            // ignore - file probably didn't exist (yet)
+            return false;
+        }
+    }
+
+    /**
+     * Called to inform that any one of the user actions (text edit or caret
+     * move) was executed.
+     */
+    public void userAction()
+    {
+        lastActionWasCut = false;
+    }
+
+    /**
+     * Called at every insertion of text into the document.
+     */
+    public void textInsertAction(DocumentEvent evt, JTextComponent textPane)
+    {
+        try {
+            if (evt.getLength() == 1) { // single character inserted
+                Document doc = evt.getDocument();
+                int offset = evt.getOffset();
+                char ch = doc.getText(offset, 1).charAt(0);
+
+                // 'ch' is the character that was just typed
+                // currently, the only character upon which we act is the
+                // closing brace ('}')
+
+                if (ch == '}' && PrefMgr.getFlag(PrefMgr.AUTO_INDENT)) {
+                    closingBrace(textPane, doc, offset);
+                }
+            }
+        }
+        catch (BadLocationException e) {}
+    }
+
+    /**
+     * We just typed a closing brace character - indent appropriately.
+     */
+    private void closingBrace(JTextComponent textPane, Document doc, int offset)
+    throws BadLocationException
+    {
+        int lineIndex = getCurrentLineIndex(textPane);
+        Element line = getLine(textPane, lineIndex);
+        int lineStart = line.getStartOffset();
+        String prefix = doc.getText(lineStart, offset - lineStart);
+
+        if(prefix.trim().length() == 0) {  // only if there is no other text before '}'
+            // Determine where the cursor appears horizontally (before insertion)
+            Rectangle r = textPane.modelToView(textPane.getCaretPosition() - 1);
+            Point p = r.getLocation();
+
+            // Indent the line
+            textPane.setCaretPosition(lineStart);
+            doIndent(textPane, true);
+            textPane.setCaretPosition(textPane.getCaretPosition() + 1);
+
+            // Set the magic position to the original position. This means that
+            // cursor up will go to the beginning of the previous line, which is much
+            // nicer behaviour.
+            textPane.getCaret().setMagicCaretPosition(p);
+        }
+    }
+
+    // ============================ USER ACTIONS =============================
+
+    abstract class MoeAbstractAction extends TextAction
+    {
+
+        public MoeAbstractAction(String name)
+        {
+            super(name);
+        }
+
+        /* side effect: clears message in editor! */
+        protected final MoeEditor getEditor(ActionEvent e)
+        {
+            MoeEditor ed = null;
+
+            // the source of the event is the first place to look
+            Object source = e.getSource();
+            if (source instanceof JComponent) {
+                Container c = ((JComponent) source).getTopLevelAncestor(); 
+                if (c instanceof MoeEditor)
+                    ed = (MoeEditor) c;
+            }
+
+            // otherwise use 'getTextComponent'
+            if (ed == null) {
+                JTextComponent textComponent = getTextComponent(e);               
+                if (textComponent != null) {
+                    Container c = textComponent.getTopLevelAncestor();
+                    if (c instanceof MoeEditor)
+                        ed = (MoeEditor) c;
+                }
+            }
+            if (ed != null)
+                ed.clearMessage();
+            return ed;
+        }
+    }
+
+    // === File: ===
+    // --------------------------------------------------------------------
+
+    class SaveAction extends MoeAbstractAction
+    {
+
+        public SaveAction()
+        {
+            super("save");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getEditor(e).userSave();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Reload has been chosen. Ask "Really?" and call "doReload" if the answer
+     * is yes.
+     */
+    class ReloadAction extends MoeAbstractAction
+    {
+
+        public ReloadAction()
+        {
+            super("reload");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getEditor(e).reload();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class PrintAction extends MoeAbstractAction
+    {
+
+        public PrintAction()
+        {
+            super("print");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getEditor(e).print();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class PageSetupAction extends MoeAbstractAction
+    {
+
+        public PageSetupAction()
+        {
+            super("page-setup");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getEditor(e).pageSetup();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class CloseAction extends MoeAbstractAction
+    {
+
+        public CloseAction()
+        {
+            super("close");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getEditor(e).close();
+        }
+    }
+
+    // === Edit: ===
+    // --------------------------------------------------------------------
+
+    public class UndoAction extends MoeAbstractAction
+    {
+
+        public UndoAction()
+        {
+            super("undo");
+            this.setEnabled(false);
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            MoeEditor editor = getEditor(e);
+            try {
+                editor.undoManager.undo();
+            }
+            catch (CannotUndoException ex) {
+                Debug.message("moe: cannot undo...");
+            }
+            editor.updateUndoControls();
+            editor.updateRedoControls();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    public class RedoAction extends MoeAbstractAction
+    {
+
+        public RedoAction()
+        {
+            super("redo");
+            this.setEnabled(false);
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            MoeEditor editor = getEditor(e);
+            try {
+                editor.undoManager.redo();
+            }
+            catch (CannotRedoException ex) {
+                Debug.message("moe: cannot redo...");
+            }
+            editor.updateUndoControls();
+            editor.updateRedoControls();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class CommentBlockAction extends MoeAbstractAction
+    {
+
+        public CommentBlockAction()
+        {
+            super("comment-block");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            MoeEditor editor = getEditor(e);
+            editor.undoManager.beginCompoundEdit();
+            blockAction(editor, new CommentLineAction());
+            editor.undoManager.endCompoundEdit();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class UncommentBlockAction extends MoeAbstractAction
+    {
+
+        public UncommentBlockAction()
+        {
+            super("uncomment-block");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            MoeEditor editor = getEditor(e);
+            editor.undoManager.beginCompoundEdit();
+            blockAction(editor, new UncommentLineAction());
+            editor.undoManager.endCompoundEdit();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class IndentBlockAction extends MoeAbstractAction
+    {
+
+        public IndentBlockAction()
+        {
+            super("indent-block");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            doBlockIndent(getEditor(e));
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class DeindentBlockAction extends MoeAbstractAction
+    {
+
+        public DeindentBlockAction()
+        {
+            super("deindent-block");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            doBlockDeIndent(getEditor(e));
+        }
+    }
+
+    // --------------------------------------------------------------------
+    
+    class AutoIndentAction extends MoeAbstractAction
+    {
+        public AutoIndentAction()
+        {
+            super("autoindent");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            MoeEditor editor = getEditor(e);
+            MoeSyntaxDocument doc = editor.getSourceDocument();
+            if (doc.getParsedNode() == null) {
+                // The Readme, or some other file which isn't parsed
+                return;
+            }
+
+            int prevCaretPos = editor.getSourcePane().getCaretPosition();
+            editor.setCaretActive(false);
+            editor.undoManager.beginCompoundEdit();
+            AutoIndentInformation info = MoeIndent.calculateIndentsAndApply(doc, prevCaretPos);
+            editor.undoManager.endCompoundEdit();
+            editor.setCaretPositionForward(info.getNewCaretPosition() - prevCaretPos);
+            editor.setCaretActive(true);
+            
+            if (info.isPerfect()) {
+                editor.writeMessage(Config.getString("editor.info.perfectIndent"));
+            }
+        }
+    }
+    
+    // --------------------------------------------------------------------
+    
+    
+    class InsertMethodAction extends MoeAbstractAction
+    {
+
+        public InsertMethodAction()
+        {
+            super("insert-method");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            MoeEditor editor = getEditor(e);
+            //this method should not be actioned if the editor is not displaying source code
+            if (!editor.containsSourceCode()){
+                return;
+            }
+            editor.undoManager.beginCompoundEdit();
+            insertTemplate(getTextComponent(e), editor, "method");
+            editor.undoManager.endCompoundEdit();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class AddJavadocAction extends MoeAbstractAction
+    {
+        public AddJavadocAction()
+        {
+            super ("add-javadoc");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            MoeEditor editor = getEditor(e);
+            //this method should not be actioned if the editor is not displaying source code
+            if (!editor.containsSourceCode()){
+                return;
+            }
+            int caretPos = editor.getCurrentTextPane().getCaretPosition();
+            NodeAndPosition<ParsedNode> node = editor.getParsedNode().findNodeAt(caretPos, 0);
+            while (node != null && node.getNode().getNodeType() != ParsedNode.NODETYPE_METHODDEF) {
+                node = node.getNode().findNodeAt(caretPos, node.getPosition());
+            }
+            if (node == null || !(node.getNode() instanceof MethodNode)) {
+                editor.writeMessage(Config.getString("editor.addjavadoc.notAMethod"));
+            } else {
+                MethodNode methodNode = ((MethodNode)node.getNode());
+                
+                boolean hasJavadocComment = false;
+                Iterator<NodeAndPosition<ParsedNode>> it = methodNode.getChildren(node.getPosition());
+                while (it.hasNext()) {
+                    ParsedNode subNode = it.next().getNode();
+                    if (subNode instanceof CommentNode) {
+                        hasJavadocComment = hasJavadocComment || ((CommentNode)subNode).isJavadocComment();
+                    }
+                }
+                
+                if (hasJavadocComment) {
+                    editor.writeMessage(Config.getString("editor.addjavadoc.hasJavadoc"));
+                } else {
+                    StringBuilder indent = new StringBuilder();
+                    int column = editor.getLineColumnFromOffset(node.getPosition()).getColumn();
+                    for (int i = 0;i < column-1;i++)
+                        indent.append(' ');
+                    StringBuilder newComment = new StringBuilder();
+                    newComment.append("/**\n");
+                    
+                    JavaEntity retTypeEntity = methodNode.getReturnType();
+                    
+                    if (retTypeEntity == null) {
+                        // It's a constructor:
+                        newComment.append(indent).append(" * ").append(methodNode.getName()).append(" ");
+                        newComment.append(Config.getString("editor.addjavadoc.constructor")).append("\n");
+                    } else {
+                        // It's a method:
+                        newComment.append(indent).append(" * ").append(Config.getString("editor.addjavadoc.method"));
+                        newComment.append(" ").append(methodNode.getName()).append("\n");
+                    }
+                    newComment.append(indent).append(" *\n");
+
+                    for (String s: methodNode.getParamNames()) {
+                        newComment.append(indent).append(" * @param ").append(s).append(" ");
+                        newComment.append(Config.getString("editor.addjavadoc.parameter")).append("\n");
+                    }
+                    
+                    if (retTypeEntity != null) {
+                        JavaType retType = retTypeEntity.resolveAsType().getType();
+                        if (retType != null && !retType.isVoid()) {
+                            newComment.append(indent).append(" * @return ");
+                            newComment.append(Config.getString("editor.addjavadoc.returnValue")).append("\n");
+                        }
+                    }
+                    
+                    newComment.append(indent).append(" */\n").append(indent);
+                    
+                    editor.undoManager.beginCompoundEdit();
+                    editor.getCurrentTextPane().setCaretPosition(node.getPosition());
+                    editor.getCurrentTextPane().replaceSelection(newComment.toString());
+                    editor.getCurrentTextPane().setCaretPosition((caretPos + newComment.length()));
+                    editor.undoManager.endCompoundEdit();
+                }
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class IndentAction extends MoeAbstractAction
+    {
+
+        public IndentAction()
+        {
+            super("indent");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            JTextComponent textPane = getTextComponent(e);
+            MoeEditor ed = getEditor(e);
+
+            if(haveSelection(textPane)) {
+                doBlockIndent(ed);
+            }
+            else {
+                // if necessary, convert all TABs in the current editor to spaces
+                int converted = 0;
+                if (ed.checkExpandTabs()) {
+                    // do TABs need expanding?
+                    ed.setCaretActive(false);
+                    converted = convertTabsToSpaces(textPane);
+                    ed.setCaretActive(true);
+                }
+
+                if (PrefMgr.getFlag(PrefMgr.AUTO_INDENT))
+                    doIndent(textPane, false);
+                else
+                    insertSpacedTab(textPane);
+
+                if (converted > 0)
+                    ed.writeMessage(Config.getString("editor.info.tabsExpanded"));
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class DeIndentAction extends MoeAbstractAction
+    {
+
+        public DeIndentAction()
+        {
+            super("de-indent");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            JTextComponent textPane = getTextComponent(e);
+            MoeEditor ed = getEditor(e);
+
+            if(haveSelection(textPane)) {
+                doBlockDeIndent(ed);
+            }
+            else {
+                // if necessary, convert all TABs in the current editor to spaces
+                if (ed.checkExpandTabs()) { // do TABs need expanding?
+                    ed.setCaretActive(false);
+                    int converted = convertTabsToSpaces(textPane);
+                    ed.setCaretActive(true);
+
+                    if (converted > 0)
+                        ed.writeMessage(Config.getString("editor.info.tabsExpanded"));
+                }
+                doDeIndent(textPane);
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class NewLineAction extends MoeAbstractAction
+    {
+
+        public NewLineAction()
+        {
+            super("new-line");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+
+            Action action = (Action) (actions.get(DefaultEditorKit.insertBreakAction));
+            action.actionPerformed(e);
+
+            if (PrefMgr.getFlag(PrefMgr.AUTO_INDENT)) {
+                JTextComponent textPane = getTextComponent(e);
+                doIndent(textPane, true);
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class CopyLineAction extends MoeAbstractAction
+    {
+
+        public CopyLineAction()
+        {
+            super("copy-line");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            boolean addToClipboard = lastActionWasCut;
+            getActionByName("caret-begin-line").actionPerformed(e);
+            getActionByName("selection-down").actionPerformed(e);
+            if (addToClipboard)
+                addSelectionToClipboard(getTextComponent(e));
+            else
+                getActionByName("copy-to-clipboard").actionPerformed(e);
+            lastActionWasCut = true;
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class CutLineAction extends MoeAbstractAction
+    {
+
+        public CutLineAction()
+        {
+            super("cut-line");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            boolean addToClipboard = lastActionWasCut;
+            getActionByName("caret-begin-line").actionPerformed(e);
+            getActionByName("selection-down").actionPerformed(e);
+            if (addToClipboard) {
+                addSelectionToClipboard(getTextComponent(e));
+                getActionByName("delete-previous").actionPerformed(e);
+            }
+            else
+                getActionByName("cut-to-clipboard").actionPerformed(e);
+            lastActionWasCut = true;
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class IncreaseFontAction extends MoeAbstractAction
+    {
+
+        public IncreaseFontAction()
+        {
+            super("increase-font");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {           
+            JTextComponent textPane = getTextComponent(e);
+            Font textPFont= textPane.getFont();           
+            int newFont=textPFont.getSize()+1;
+            PrefMgr.setEditorFontSize(newFont);
+            getTextComponent(e).setFont(textPane.getFont().deriveFont((float)newFont));            
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class DecreaseFontAction extends MoeAbstractAction
+    {
+
+        public DecreaseFontAction()
+        {
+            super("decrease-font");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {     
+            JTextComponent textPane = getTextComponent(e);
+            Font textPFont= textPane.getFont();            
+            int newFont=textPFont.getSize()-1;
+            PrefMgr.setEditorFontSize(newFont);
+            getTextComponent(e).setFont(textPFont.deriveFont((float)newFont));
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class CutEndOfLineAction extends MoeAbstractAction
+    {
+
+        public CutEndOfLineAction()
+        {
+            super("cut-end-of-line");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            boolean addToClipboard = lastActionWasCut;
+
+            getActionByName("selection-end-line").actionPerformed(e);
+            JTextComponent textComponent = getTextComponent(e);
+            String selection = textComponent.getSelectedText();
+            if (selection == null)
+                getActionByName("selection-forward").actionPerformed(e);
+
+            if (addToClipboard) {
+                addSelectionToClipboard(textComponent);
+                getActionByName("delete-previous").actionPerformed(e);
+            }
+            else
+                getActionByName("cut-to-clipboard").actionPerformed(e);
+            lastActionWasCut = true;
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class CutWordAction extends MoeAbstractAction
+    {
+
+        public CutWordAction()
+        {
+            super("cut-word");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            boolean addToClipboard = lastActionWasCut;
+            getActionByName("caret-previous-word").actionPerformed(e);
+            getActionByName("selection-next-word").actionPerformed(e);
+            if (addToClipboard) {
+                addSelectionToClipboard(getTextComponent(e));
+                getActionByName("delete-previous").actionPerformed(e);
+            }
+            else
+                getActionByName("cut-to-clipboard").actionPerformed(e);
+            lastActionWasCut = true;
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class ContentAssistAction extends MoeAbstractAction
+    {
+
+        public ContentAssistAction()
+        {
+            super("code-completion");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        { 
+            MoeEditor editor = getEditor(e);
+            if (Config.getPropBoolean("bluej.editor.codecompletion", true)){
+                editor.createContentAssist();
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class CutEndOfWordAction extends MoeAbstractAction
+    {
+
+        public CutEndOfWordAction()
+        {
+            super("cut-end-of-word");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            boolean addToClipboard = lastActionWasCut;
+            getActionByName("selection-next-word").actionPerformed(e);
+            if (addToClipboard) {
+                addSelectionToClipboard(getTextComponent(e));
+                getActionByName("delete-previous").actionPerformed(e);
+            }
+            else
+                getActionByName("cut-to-clipboard").actionPerformed(e);
+            lastActionWasCut = true;
+        }
+    }
+    
+    // --------------------------------------------------------------------
+    
+    private abstract class MoeActionWithOrWithoutSelection extends MoeAbstractAction
+    {
+        private boolean withSelection;
+        
+        protected MoeActionWithOrWithoutSelection(String actionName, boolean withSelection)
+        {
+            super(actionName);
+            this.withSelection = withSelection;
+        }
+
+        protected void moveCaret(JTextComponent c, int pos)
+        {
+            if (withSelection) {
+                c.getCaret().moveDot(pos);
+            } else {
+                c.setCaretPosition(pos);
+            }
+        }       
+    }
+    
+    // --------------------------------------------------------------------
+    
+    class NextWordAction extends MoeActionWithOrWithoutSelection
+    {
+        public NextWordAction(boolean withSelection)
+        {
+            super(withSelection ? DefaultEditorKit.selectionNextWordAction : DefaultEditorKit.nextWordAction, withSelection);
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            JTextComponent c = getTextComponent(e);
+            int origPos = c.getCaret().getDot();
+            int end = findWordLimit(c, origPos, true);
+            try {
+                if (Character.isWhitespace(c.getText(end, 1).charAt(0))) {
+                    // Whitespace region follows, find the end of it:
+                    int endOfWS = findWordLimit(c, end, true);
+                    moveCaret(c, endOfWS);
+                } else {
+                    // A different "word" follows immediately, stay where we are:
+                    moveCaret(c, end);
+                }
+            } catch (BadLocationException ex) {
+                // End of file already, just set the caret there:
+                moveCaret(c, end);
+            }
+        }
+        
+
+    }
+    
+    private static int findWordLimit(JTextComponent c, int pos, boolean forwards)
+    {
+        try {
+            char curChar = c.getText(pos, 1).charAt(0);
+            if (Character.isWhitespace(curChar)) { 
+                while (Character.isWhitespace(curChar)) {
+                    if (forwards) pos++; else pos--;
+                    curChar = c.getText(pos, 1).charAt(0);
+                }
+                // If we are going back, we'll have gone one character too far
+                // so adjust for that; but if going forwards, the limit is exclusive
+                return forwards ? pos : pos + 1;
+            } else if (Character.isJavaIdentifierPart(curChar)) {
+                while (Character.isJavaIdentifierPart(curChar)) {
+                    if (forwards) pos++; else pos--;
+                    curChar = c.getText(pos, 1).charAt(0);
+                }
+                // If we are going back, we'll have gone one character too far
+                // so adjust for that; but if going forwards, the limit is exclusive
+                return forwards ? pos : pos + 1;
+            } else {
+                // Can't form an identifier, isn't a space, therefore
+                // this char is a word by itself.  If we're looking for the start,
+                // this is it, and the end is one character on 
+                return forwards ? pos + 1 : pos;
+            }
+        } catch (BadLocationException e) {
+            return forwards ? c.getText().length() : 0;
+        }
+    }
+
+    // --------------------------------------------------------------------    
+    
+    class PrevWordAction extends MoeActionWithOrWithoutSelection
+    {       
+        public PrevWordAction(boolean withSelection)
+        {
+            super(withSelection ? DefaultEditorKit.selectionPreviousWordAction : DefaultEditorKit.previousWordAction, withSelection);
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            JTextComponent c = getTextComponent(e);
+            int origPos = c.getCaret().getDot();
+            try {
+                if (Character.isWhitespace(c.getText(origPos - 1, 1).charAt(0))) {
+                    // Whitespace region precedes, find the beginning of it:
+                    int startOfWS = findWordLimit(c, origPos - 1, false);
+                    int startOfPrevWord = findWordLimit(c, startOfWS - 1, false);
+                    moveCaret(c, startOfPrevWord);
+                } else {
+                    // We're in the middle of a word already, find the start:
+                    int startOfWord = findWordLimit(c, origPos - 1, false);
+                    moveCaret(c, startOfWord);
+                }
+            } catch (BadLocationException ex) {
+                // Start of file already, just set the caret there:
+                moveCaret(c, 0);
+            }            
+        }
+    }
+    
+    // --------------------------------------------------------------------
+    
+    class EndWordAction extends MoeActionWithOrWithoutSelection
+    {
+        public EndWordAction(boolean withSelection)
+        {
+            super(withSelection ? DefaultEditorKit.selectionEndWordAction : DefaultEditorKit.endWordAction, withSelection);
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            JTextComponent c = getTextComponent(e);
+            int origPos = c.getCaret().getDot();
+            int end = findWordLimit(c, origPos, true);
+            moveCaret(c, end);
+        }
+    }
+
+    // --------------------------------------------------------------------    
+    
+    class BeginWordAction extends MoeActionWithOrWithoutSelection
+    {
+        public BeginWordAction(boolean withSelection)
+        {
+            super(withSelection ? DefaultEditorKit.selectionBeginWordAction : DefaultEditorKit.beginWordAction, withSelection);
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            JTextComponent c = getTextComponent(e);
+            int origPos = c.getCaret().getDot();
+            int start = findWordLimit(c, origPos, false);
+            moveCaret(c, start);
+        }
+    }
+    
+    // --------------------------------------------------------------------
+    class DeleteWordAction extends MoeAbstractAction
+    {
+        public DeleteWordAction()
+        {
+            super("delete-previous-word");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            JTextComponent c = getTextComponent(e);
+            Action prevWordAct = actions.get(DefaultEditorKit.previousWordAction);
+            int end = c.getCaret().getDot();
+            prevWordAct.actionPerformed(e);
+            int begin = c.getCaret().getDot();
+            try {
+                c.getDocument().remove(begin, end - begin);
+            } catch (BadLocationException ex) {
+            }
+        }
+        
+    }
+    
+    // --------------------------------------------------------------------    
+    
+    class SelectWordAction extends MoeAbstractAction
+    {
+        public SelectWordAction()
+        {
+            super(DefaultEditorKit.selectWordAction);
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            JTextComponent c = getTextComponent(e);
+            int origPos = c.getCaret().getDot();
+            int newStart = findWordLimit(c, origPos, false);
+            int newEnd = findWordLimit(c, origPos, true);
+            c.getCaret().setDot(newStart);
+            c.getCaret().moveDot(newEnd);
+        }
+    }
+
+    // === Tools: ===
+    // --------------------------------------------------------------------
+
+    class FindAction extends MoeAbstractAction
+    {
+
+        public FindAction()
+        {
+            super("find");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            //getEditor(e).find();
+            MoeEditor editor=getEditor(e);
+            if (editor!=null)
+                editor.initFindPanel();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    public class FindNextAction extends MoeAbstractAction
+    {
+
+        public FindNextAction()
+        {
+            super("find-next");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getEditor(e).findNext(false);
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    public class FindNextBackwardAction extends MoeAbstractAction
+    {
+
+        public FindNextBackwardAction()
+        {
+            super("find-next-backward");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getEditor(e).findNext(true);
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class ReplaceAction extends MoeAbstractAction
+    {
+
+        public ReplaceAction()
+        {
+            super("replace");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            MoeEditor editor=getEditor(e);
+            if (editor != null) {
+                editor.setFindPanelVisible();
+                editor.setReplacePanelVisible(true);
+                if (editor.getSourcePane().getSelectedText()!=null){
+                    editor.setFindTextfield(editor.getSourcePane().getSelectedText());
+                }
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class CompileAction extends MoeAbstractAction
+    {
+
+        public CompileAction()
+        {
+            super("compile");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getEditor(e).compile();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class ToggleInterfaceAction extends MoeAbstractAction
+    {
+
+        public ToggleInterfaceAction()
+        {
+            super("toggle-interface-view");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            Object source = e.getSource();
+            if (source instanceof JComboBox)
+                getEditor(e).toggleInterface();
+            else
+                getEditor(e).toggleInterfaceMenu();
+        }
+    }
+
+    // === Debug: ===
+    // --------------------------------------------------------------------
+
+    class ToggleBreakPointAction extends MoeAbstractAction
+    {
+
+        public ToggleBreakPointAction()
+        {
+            super("toggle-breakpoint");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getEditor(e).toggleBreakpoint();
+        }
+    }
+
+    // === Options: ===
+    // --------------------------------------------------------------------
+
+    class KeyBindingsAction extends MoeAbstractAction
+    {
+
+        public KeyBindingsAction()
+        {
+            super("key-bindings");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            PrefMgrDialog.showDialog(1); // 1 is the index of the key bindings pane in the pref dialog
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class PreferencesAction extends MoeAbstractAction
+    {
+
+        public PreferencesAction()
+        {
+            super("preferences");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            PrefMgrDialog.showDialog(0); // 0 is the index of the editor pane in
+            // the pref dialog
+        }
+    }
+
+    // === Help: ===
+    // --------------------------------------------------------------------
+
+    class AboutAction extends MoeAbstractAction
+    {
+
+        public AboutAction()
+        {
+            super("about-editor");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            JOptionPane.showMessageDialog(getEditor(e), new String[]{"Moe", "Version " + MoeEditor.versionString, " ",
+                "Moe is the editor of the BlueJ programming environment.",
+            "Written by Michael K\u00F6lling (mik@bluej.org)."}, "About Moe", JOptionPane.INFORMATION_MESSAGE);
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class DescribeKeyAction extends MoeAbstractAction
+    {
+
+        public DescribeKeyAction()
+        {
+            super("describe-key");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            JTextComponent textComponent = getTextComponent(e);
+            textComponent.addKeyListener(keyCatcher);
+            MoeEditor ed = getEditor(e);
+            keyCatcher.setEditor(ed);
+            ed.writeMessage("Describe key: ");
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class HelpMouseAction extends MoeAbstractAction
+    {
+
+        public HelpMouseAction()
+        {
+            super("help-mouse");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            JOptionPane.showMessageDialog(getEditor(e), new String[]{"Moe Mouse Buttons:", " ", "left button:",
+                "   click: place cursor", "   double-click: select word", "   triple-click: select line",
+                "   drag: make selection", " ", "right button:", "   (currently unused)",}, "Moe Mouse Buttons",
+                JOptionPane.INFORMATION_MESSAGE);
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    class GoToLineAction extends MoeAbstractAction
+    {
+
+        public GoToLineAction()
+        {
+            super("go-to-line");
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getEditor(e).goToLine();
+        }
+    }
+
+    // --------------------------------------------------------------------
+    //     class Action extends MoeAbstractAction {
+    //
+    //       public Action() {
+    //       super("");
+    //       }
+    //
+    //       public void actionPerformed(ActionEvent e) {
+    //       DialogManager.NYI(editor);
+    //       }
+    //     }
+
+    // ========================= SUPPORT ROUTINES ==========================
+
+    /**
+     * Check whether any text is currently selected.
+     * @return True, if a selection is active.
+     */
+    private boolean haveSelection(JTextComponent textPane)
+    {
+        Caret caret = textPane.getCaret();
+        return caret.getMark() != caret.getDot();
+    }
+
+    /**
+     * Add the current selection of the text component to the clipboard.
+     */
+    public void addSelectionToClipboard(JTextComponent textComponent)
+    {
+        Clipboard clipboard = textComponent.getToolkit().getSystemClipboard();
+
+        // get text from clipboard
+        Transferable content = clipboard.getContents(this);
+        String clipContent = "";
+        if (content != null) {
+            try {
+                clipContent = (String) (content.getTransferData(DataFlavor.stringFlavor));
+            }
+            catch (Exception exc) {} // content was not string
+        }
+
+        // add current selection and store back in clipboard
+        StringSelection contents = new StringSelection(clipContent + textComponent.getSelectedText());
+        clipboard.setContents(contents, contents);
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Return the current column number.
+     */
+    private int getCurrentColumn(JTextComponent textPane)
+    {
+        Caret caret = textPane.getCaret();
+        int pos = Math.min(caret.getMark(), caret.getDot());
+        AbstractDocument doc = (AbstractDocument) textPane.getDocument();
+        int lineStart = doc.getParagraphElement(pos).getStartOffset();
+        return (pos - lineStart);
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Find and return a line by line number
+     */
+    private Element getLine(JTextComponent text, int lineNo)
+    {
+        return text.getDocument().getDefaultRootElement().getElement(lineNo);
+    }
+
+    // -------------------------------------------------------------------
+    /**
+     * Return the number of the current line.
+     */
+    private int getCurrentLineIndex(JTextComponent text)
+    {
+        MoeSyntaxDocument document = (MoeSyntaxDocument) text.getDocument();
+        return document.getDefaultRootElement().getElementIndex(text.getCaretPosition());
+    }
+
+    // ===================== ACTION IMPLEMENTATION ======================
+
+    /**
+     * Do some semi-intelligent indentation. That is: indent the current line to
+     * the same depth, using the same characters (TABs or spaces) as the line
+     * immediately above.
+     * 
+     * @param isNewLine   true if the action was to insert a line or closing brace;
+     *                     false if the action was to tab/indent
+     */
+    private void doIndent(JTextComponent textPane, boolean isNewLine)
+    {
+        int lineIndex = getCurrentLineIndex(textPane);
+        if (lineIndex == 0) { // first line
+            if(!isNewLine)
+                insertSpacedTab(textPane);
+            return;
+        }
+
+        MoeSyntaxDocument doc = (MoeSyntaxDocument) textPane.getDocument();
+
+        Element line = getLine(textPane, lineIndex);
+        int lineStart = line.getStartOffset();
+        int pos = textPane.getCaretPosition();
+
+        try {
+            boolean isOpenBrace = false;
+            boolean isCommentEnd = false, isCommentEndOnly = false;
+
+            // if there is any text before the cursor, just insert a tab
+
+            String prefix = doc.getText(lineStart, pos - lineStart);
+            if (prefix.trim().length() > 0) {
+                insertSpacedTab(textPane);
+                return;
+            }
+
+            // get indentation string from previous line
+
+            boolean foundLine = false;
+            int lineOffset = 1;
+            String prevLineText = null;
+            while ((lineIndex - lineOffset >= 0) && !foundLine) {
+                Element prevline = getLine(textPane, lineIndex - lineOffset);
+                int prevLineStart = prevline.getStartOffset();
+                int prevLineEnd = prevline.getEndOffset();
+                prevLineText = doc.getText(prevLineStart, prevLineEnd - prevLineStart);
+                if(!MoeIndent.isWhiteSpaceOnly(prevLineText)) {
+                    foundLine = true;
+                }
+                else {
+                    lineOffset++; 
+                }
+            }
+            if(!foundLine) {
+                if(!isNewLine)
+                    insertSpacedTab(textPane);
+                return;
+            }
+
+            if (isOpenBrace(prevLineText))
+                isOpenBrace = true;
+            else {
+                isCommentEnd = prevLineText.trim().endsWith("*/");
+                isCommentEndOnly = prevLineText.trim().equals("*/");
+            }
+
+            int indentPos = MoeIndent.findFirstNonIndentChar(prevLineText, isCommentEnd);
+            String indent = prevLineText.substring(0, indentPos);
+            
+            if (isOpenBrace) {
+                indentPos += tabSize;
+            }
+
+            // if the cursor is already past the indentation point, insert tab
+            // (unless we just did a line break, then we just stop)
+
+            int caretColumn = getCurrentColumn(textPane);
+            if (caretColumn >= indentPos) {
+                if (!isNewLine)
+                    insertSpacedTab(textPane);
+                return;
+            }
+
+            if (isNewLine && isNewCommentStart(indent, doc, lineStart)) {
+                completeNewCommentBlock(textPane, indent);
+                return;
+            }
+
+            // find and replace indentation of current line
+
+            int lineEnd = line.getEndOffset();
+            String lineText = doc.getText(lineStart, lineEnd - lineStart);
+            indentPos = MoeIndent.findFirstNonIndentChar(lineText, true);
+            char firstChar = lineText.charAt(indentPos);
+            doc.remove(lineStart, indentPos);
+            String newIndent = nextIndent(indent, isOpenBrace, isCommentEndOnly);
+            if (firstChar == '*')
+                newIndent = newIndent.replace('*', ' ');
+            doc.insertString(lineStart, newIndent, null);
+            if(firstChar == '}')
+                removeTab(textPane, doc);
+        }
+        catch (BadLocationException exc) {}
+    }
+
+    /**
+     * Do some semi-intelligent de-indentation. That is: indent the current line
+     * one indentation level less that the line above, or less than it currently
+     * is.
+     */
+    private void doDeIndent(JTextComponent textPane)
+    {
+        // set cursor to first non-blank character (or eol if none)
+        // if indentation is more than line above: indent as line above
+        // if indentation is same or less than line above: indent one level back
+
+        int lineIndex = getCurrentLineIndex(textPane);
+        MoeSyntaxDocument doc = (MoeSyntaxDocument) textPane.getDocument();
+
+        try {
+            Element line = getLine(textPane, lineIndex);
+            int lineStart = line.getStartOffset();
+            int lineEnd = line.getEndOffset();
+            String lineText = doc.getText(lineStart, lineEnd - lineStart);
+
+            int currentIndentPos = MoeIndent.findFirstNonIndentChar(lineText, true);
+            char firstChar = lineText.charAt(currentIndentPos);
+
+            textPane.setCaretPosition(lineStart + currentIndentPos);
+
+            if (lineIndex == 0) { // first line
+                removeTab(textPane, doc);
+                return;
+            }
+
+            // get indentation details from previous line
+
+            Element prevline = getLine(textPane, lineIndex - 1);
+            int prevLineStart = prevline.getStartOffset();
+            int prevLineEnd = prevline.getEndOffset();
+            String prevLineText = doc.getText(prevLineStart, prevLineEnd - prevLineStart);
+
+            int targetIndentPos = MoeIndent.findFirstNonIndentChar(prevLineText, true);
+
+            if (currentIndentPos > targetIndentPos) {
+                // indent same as line above
+                String indent = prevLineText.substring(0, targetIndentPos);
+                doc.remove(lineStart, currentIndentPos);
+                doc.insertString(lineStart, indent, null);
+                if(firstChar == '}')
+                    removeTab(textPane, doc);
+            }
+            else {
+                // we are at same level as line above or less - go one indentation
+                // level back
+                removeTab(textPane, doc);
+            }
+        }
+        catch (BadLocationException exc) {}
+    }
+
+    /**
+     * Indent a block of lines (defined by the current selection) by one
+     * additional level.
+     */
+    private void doBlockIndent(MoeEditor editor)
+    {
+        editor.undoManager.beginCompoundEdit();
+        blockAction(editor, new IndentLineAction());
+        editor.undoManager.endCompoundEdit();
+    }
+
+    /**
+     * De-indent a block of lines (defined by the current selection) by one
+     * level.
+     */
+    private void doBlockDeIndent(MoeEditor editor)
+    {
+        editor.undoManager.beginCompoundEdit();
+        blockAction(editor, new DeindentLineAction());
+        editor.undoManager.endCompoundEdit();
+    }
+
+    /**
+     * Check whether the indentation s opens a new multi-line comment
+     * @param lineStart The position in the document of the (newly-added) line start
+     */
+    private boolean isNewCommentStart(String s, MoeSyntaxDocument doc, int lineStart)
+    {
+        s = s.trim();
+        if (s.endsWith("/**") || s.endsWith("/*"))
+        {
+            // The user has just pressed enter after the beginning of a comment
+            // We must now decide if their comment was already fine
+            // (and thus we shouldn't add the ending), or if they had, in fact,
+            // begun a new comment (and do need the ending)
+            
+            // Find the comment node that corresponds to our position:
+            NodeAndPosition<ParsedNode> curNode = doc.getParser().findNodeAt(lineStart, 0);
+            while (curNode != null && !(curNode.getNode() instanceof CommentNode))
+            {
+                curNode = curNode.getNode().findNodeAt(lineStart, curNode.getPosition());
+            }
+            
+            if (curNode == null)
+                //Can't work it out; it's probably a new comment that is unterminated:
+                return true;
+            
+            String comment = getNodeContents(doc, curNode);
+            
+            // If the comment has a comment begin inside it (after the first two characters)
+            // it is likely a new comment that has over-run and matched an ending further
+            // down.  If it has no comment begin inside it, it's probably a pre-existing
+            // valid comment.
+            comment = comment.substring(2);
+            boolean commentHasBeginning = comment.contains("/*");
+            
+            return commentHasBeginning;
+        }
+        else
+            return false;
+    }
+
+    /**
+     * Insert text to complete a new, started block comment and place the cursor
+     * appropriately.
+     * 
+     * The indentString passed in always ends with "/*".
+     */
+    private void completeNewCommentBlock(JTextComponent textPane, String indentString)
+    {
+        String nextIndent = indentString.substring(0, indentString.length() - 2);
+        textPane.replaceSelection(nextIndent + " * ");
+        int pos = textPane.getCaretPosition();
+        textPane.replaceSelection("\n");
+        textPane.replaceSelection(nextIndent + " */");
+        textPane.setCaretPosition(pos);
+    }
+
+    /**
+     * Check whether the given line ends with an opening brace.
+     */
+    private boolean isOpenBrace(String s)
+    {
+        int index = s.lastIndexOf('{');
+        if (index == -1)
+            return false;
+
+        return s.indexOf('}', index + 1) == -1;
+    }
+
+    /**
+     * Transform indentation string to ensure:
+     * <ul>
+     * <li>after " / *" follows " *"
+     * <li>after " / * *" follows " *"
+     * <li>after " * /" follows ""
+     * </ul>
+     */
+    private String nextIndent(String s, boolean openBrace, boolean commentEndOnly)
+    {
+        // after an opening brace, add some spaces to the indentation
+        if (openBrace)
+            return s + spaces.substring(0, tabSize);
+
+        if (commentEndOnly)
+            return s.substring(0, s.length() - 1);
+
+        if (s.endsWith("/*"))
+            return s.substring(0, s.length() - 2) + " * ";
+
+        return s;
+    }
+
+    /**
+     * Insert a spaced tab at the current caret position in to the textPane.
+     */
+    private void insertSpacedTab(JTextComponent textPane)
+    {
+        int numSpaces = tabSize - (getCurrentColumn(textPane) % tabSize);
+        textPane.replaceSelection(spaces.substring(0, numSpaces));
+    }
+
+    /**
+     * Remove characters before the current caret position to take the 
+     * caret back to the previous TAB position. No check is made what kind
+     * of characters those are - the caller should make sure they can be 
+     * removed (usually they should be whitespace).
+     */
+    private void removeTab(JTextComponent textPane, Document doc)
+    throws BadLocationException
+    {
+        int col = getCurrentColumn(textPane);
+        if(col > 0) {
+            int remove = col % tabSize;
+            if(remove == 0)
+                remove = tabSize;
+            int pos = textPane.getCaretPosition();
+            doc.remove(pos-remove, remove);
+        }
+    }
+
+    /**
+     * Convert all tabs in this text to spaces, maintaining the current
+     * indentation.
+     * 
+     * @param textPane The text pane to convert
+     * @return  The number of tab characters converted
+     */
+    private int convertTabsToSpaces(JTextComponent textPane)
+    {
+        int count = 0;
+        int lineNo = 0;
+        AbstractDocument doc = (AbstractDocument) textPane.getDocument();
+        Element root = doc.getDefaultRootElement();
+        Element line = root.getElement(lineNo);
+        try {
+            while (line != null) {
+                int start = line.getStartOffset();
+                int length = line.getEndOffset() - start;
+                String text = doc.getText(start, length);
+                int startCount = count;
+                int tabIndex = text.indexOf('\t');
+                while (tabIndex != -1) {
+                    text = expandTab(text, tabIndex);
+                    count++;
+                    tabIndex = text.indexOf('\t');
+                }
+                if (count != startCount) { // there was a TAB in this line...
+                    doc.remove(start, length);
+                    doc.insertString(start, text, null);
+                }
+                lineNo++;
+                line = root.getElement(lineNo);
+            }
+        }
+        catch (BadLocationException exc) {
+            Debug.reportError("stuffed up in 'convertTabsToSpaces'");
+        }
+        return count;
+    }
+
+    private String expandTab(String s, int idx)
+    {
+        int numSpaces = tabSize - (idx % tabSize);
+        return s.substring(0, idx) + spaces.substring(0, numSpaces) + s.substring(idx + 1);
+    }
+
+    /**
+     * Insert text from a named template into the editor at the current cursor
+     * position. Every line in the template will be indented to the current
+     * cursor position (in addition to possible indentation in the template
+     * itself), and TAB characters at beginnings of lines in the template will
+     * be converted to a spaced tab according to the current tabsize.
+     * 
+     * @param textPane
+     *            The editor pane to enter the text into
+     * @param editor 
+     * @param templateName
+     *            The name of the template (without path or suffix)
+     */
+    private void insertTemplate(JTextComponent textPane, MoeEditor editor, String templateName)
+    {
+        try {
+            File template = Config.getTemplateFile(templateName);
+            BufferedReader in = new BufferedReader(new FileReader(template));
+            int addedTextLength = 0;
+            String line = in.readLine();
+            while (line != null) {
+                while ((line.length() > 0) && (line.charAt(0) == '\t')) {
+                    line = line.substring(1);
+                }
+                addedTextLength += line.length() + 1;
+                textPane.replaceSelection(line);
+                textPane.replaceSelection("\n");
+                line = in.readLine();
+            }
+            // The position of the caret should be in the right place now.
+            // Previously it was set to the position it was at before adding the
+            // template, but that resulted in errors when selecting the entire
+            // contents of the class before inserting the template.
+            int caretPos = editor.getSourcePane().getCaretPosition();
+            AutoIndentInformation info = MoeIndent.calculateIndentsAndApply(editor.getSourceDocument(),caretPos - addedTextLength,caretPos+2,caretPos);
+            editor.setCaretPositionForward(info.getNewCaretPosition() - editor.getSourcePane().getCaretPosition());
+        }
+        catch (IOException exc) {
+            Debug.reportError("Could not read method template.");
+            Debug.reportError("Exception: " + exc);
+        }
+    }
+
+    /**
+     * Perform an action on all selected lines in the source document.
+     */
+    private void blockAction(MoeEditor editor, LineAction lineAction)
+    {
+        editor.setCaretActive(false);
+        
+        Caret caret = editor.getSourcePane().getCaret();
+        int selectionStart = caret.getMark();
+        int selectionEnd = caret.getDot();
+        if (selectionStart > selectionEnd) {
+            int tmp = selectionStart;
+            selectionStart = selectionEnd;
+            selectionEnd = tmp;
+        }
+        if (selectionStart != selectionEnd)
+            selectionEnd = selectionEnd - 1; // skip last position
+
+        MoeSyntaxDocument doc = (MoeSyntaxDocument) editor.getSourceDocument();
+        Element text = doc.getDefaultRootElement();
+
+        int firstLineIndex = text.getElementIndex(selectionStart);
+        int lastLineIndex = text.getElementIndex(selectionEnd);
+        for (int i = firstLineIndex; i <= lastLineIndex; i++) {
+            Element line = text.getElement(i);
+            lineAction.apply(line, doc);
+        }
+
+        editor.setSelection(firstLineIndex + 1, 1,
+                text.getElement(lastLineIndex).getEndOffset()
+                - text.getElement(firstLineIndex).getStartOffset());
+        
+        editor.setCaretActive(true);
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Create the table of action supported by this editor
+     */
+    private void createActionTable(JTextComponent textComponent)
+    {
+        undoAction = new UndoAction();
+        redoAction = new RedoAction();
+        compileAction = new CompileAction();
+
+        // get all actions into arrays
+        Action[] textActions = textComponent.getActions();
+        
+        overrideActions = new Action[] {
+                //With and without selection for each:
+                new NextWordAction(false),
+                new NextWordAction(true),
+                new PrevWordAction(false),                
+                new PrevWordAction(true),
+                
+              //With and without selection for each:
+                new EndWordAction(false),
+                new EndWordAction(true),
+                new BeginWordAction(false),                
+                new BeginWordAction(true),
+                
+                new DeleteWordAction(),
+                
+                new SelectWordAction()
+        };
+        
+        Action[] myActions = {
+                new SaveAction(), 
+                new ReloadAction(), 
+                new PageSetupAction(), 
+                new PrintAction(),
+                new CloseAction(),
+
+                undoAction, 
+                redoAction, 
+                new CommentBlockAction(), 
+                new UncommentBlockAction(), 
+                new AutoIndentAction(),
+                new IndentBlockAction(),
+                new DeindentBlockAction(), 
+                new InsertMethodAction(), 
+                new AddJavadocAction(),
+                new IndentAction(),
+                new DeIndentAction(),
+                new NewLineAction(),
+                new CopyLineAction(), 
+                new CutLineAction(), 
+                new CutEndOfLineAction(), 
+                new CutWordAction(),
+                new CutEndOfWordAction(),
+
+                new FindAction(), 
+                findNextAction=new FindNextAction(),
+                findNextBackwardAction=new FindNextBackwardAction(),
+                new ReplaceAction(),
+                compileAction, 
+                new GoToLineAction(), 
+                new ToggleInterfaceAction(), 
+                new ToggleBreakPointAction(),
+
+                new KeyBindingsAction(), 
+                new PreferencesAction(),
+
+                new AboutAction(), 
+                new DescribeKeyAction(), 
+                new HelpMouseAction(), 
+
+                new IncreaseFontAction(),
+                new DecreaseFontAction(),
+
+                new ContentAssistAction()
+        };
+
+        // insert all actions into a hash map
+
+        actions = new HashMap<Object, Action>();
+
+        for (Action action : textActions) {
+            actions.put(action.getValue(Action.NAME), action);
+        }
+
+        for (Action action : overrideActions) {
+            actions.put(action.getValue(Action.NAME), action);
+        }
+       
+        for (Action action : myActions) {
+            actions.put(action.getValue(Action.NAME), action);
+        }
+
+        // sort all actions into a big, ordered table
+
+        actionTable = new Action[] {
+
+                // edit functions
+                (Action) (actions.get(DefaultEditorKit.deletePrevCharAction)), // 0
+                (Action) (actions.get(DefaultEditorKit.deleteNextCharAction)),
+                (Action) (actions.get("delete-previous-word")),
+                (Action) (actions.get(DefaultEditorKit.copyAction)),
+                (Action) (actions.get(DefaultEditorKit.cutAction)), 
+                (Action) (actions.get("copy-line")),
+                (Action) (actions.get("cut-line")), 
+                (Action) (actions.get("cut-end-of-line")),
+                (Action) (actions.get("cut-word")), 
+                (Action) (actions.get("cut-end-of-word")),
+                (Action) (actions.get(DefaultEditorKit.pasteAction)), 
+                (Action) (actions.get("indent")),
+                (Action) (actions.get("de-indent")),
+                (Action) (actions.get(DefaultEditorKit.insertTabAction)), 
+                (Action) (actions.get("new-line")),
+                (Action) (actions.get(DefaultEditorKit.insertBreakAction)), 
+                (Action) (actions.get("insert-method")),
+                (Action) (actions.get("comment-block")), 
+                (Action) (actions.get("uncomment-block")),
+                (Action) (actions.get("autoindent")), 
+                (Action) (actions.get("indent-block")), 
+                (Action) (actions.get("deindent-block")),
+
+                (Action) (actions.get(DefaultEditorKit.selectWordAction)), // 22
+                (Action) (actions.get(DefaultEditorKit.selectLineAction)),
+                (Action) (actions.get(DefaultEditorKit.selectParagraphAction)),
+                (Action) (actions.get(DefaultEditorKit.selectAllAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionBackwardAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionForwardAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionUpAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionDownAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionBeginWordAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionEndWordAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionPreviousWordAction)), // 32
+                (Action) (actions.get(DefaultEditorKit.selectionNextWordAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionBeginLineAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionEndLineAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionBeginParagraphAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionEndParagraphAction)),
+                (Action) (actions.get("selection-page-up")), 
+                (Action) (actions.get("selection-page-down")),
+                (Action) (actions.get(DefaultEditorKit.selectionBeginAction)),
+                (Action) (actions.get(DefaultEditorKit.selectionEndAction)), 
+                (Action) (actions.get("unselect")),
+
+                // move and scroll functions
+                (Action) (actions.get(DefaultEditorKit.backwardAction)), // 43
+                (Action) (actions.get(DefaultEditorKit.forwardAction)),
+                (Action) (actions.get(DefaultEditorKit.upAction)), 
+                (Action) (actions.get(DefaultEditorKit.downAction)),
+                (Action) (actions.get(DefaultEditorKit.beginWordAction)),
+                (Action) (actions.get(DefaultEditorKit.endWordAction)),
+                (Action) (actions.get(DefaultEditorKit.previousWordAction)),
+                (Action) (actions.get(DefaultEditorKit.nextWordAction)),
+                (Action) (actions.get(DefaultEditorKit.beginLineAction)),
+                (Action) (actions.get(DefaultEditorKit.endLineAction)),    // 52
+                (Action) (actions.get(DefaultEditorKit.beginParagraphAction)),
+                (Action) (actions.get(DefaultEditorKit.endParagraphAction)),
+                (Action) (actions.get(DefaultEditorKit.pageUpAction)),
+                (Action) (actions.get(DefaultEditorKit.pageDownAction)),
+                (Action) (actions.get(DefaultEditorKit.beginAction)),
+                (Action) (actions.get(DefaultEditorKit.endAction)),
+
+                // class functions
+                (Action) (actions.get("save")), // 59
+                (Action) (actions.get("reload")), 
+                (Action) (actions.get("close")), 
+                (Action) (actions.get("print")),
+                (Action) (actions.get("page-setup")),
+
+                // customisation functions
+                (Action) (actions.get("key-bindings")), // 64
+                (Action) (actions.get("preferences")),
+
+                // help functions
+                (Action) (actions.get("describe-key")), // 66
+                (Action) (actions.get("help-mouse")), 
+                (Action) (actions.get("show-manual")),
+                (Action) (actions.get("about-editor")),
+
+                // misc functions
+                undoAction, // 70
+                redoAction, 
+                (Action) (actions.get("find")), 
+                (Action) (actions.get("find-next")),
+                (Action) (actions.get("find-next-backward")), 
+                (Action) (actions.get("replace")),
+                (Action) (actions.get("compile")), 
+                (Action) (actions.get("toggle-interface-view")),
+                (Action) (actions.get("toggle-breakpoint")), 
+                (Action) (actions.get("go-to-line")),
+                (Action) (actions.get("increase-font")),
+                (Action) (actions.get("decrease-font")),
+                (Action) (actions.get("code-completion")),
+
+        }; // 83
+
+        categories = new String[] { 
+                Config.getString("editor.functions.editFunctions"),
+                Config.getString("editor.functions.moveScroll"), 
+                Config.getString("editor.functions.classFunctions"),
+                Config.getString("editor.functions.customisation"), 
+                Config.getString("editor.functions.help"),
+                Config.getString("editor.functions.misc")
+        };
+
+        categoryIndex = new int[] { 0, 43, 59, 64, 66, 70, 83 };
+    }
+
+    /**
+     * Set up the default key bindings. Used for initial setup, or restoring the
+     * default later on.
+     */
+    public void setDefaultKeyBindings()
+    {
+        keymap.removeBindings();
+
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_S, SHORTCUT_MASK), 
+                (Action) (actions.get("save")));
+        // "reload" not bound
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_P, SHORTCUT_MASK), 
+                (Action) (actions.get("print")));
+        // "page-setup" not bound
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_W, SHORTCUT_MASK), (Action) (actions
+                .get("close")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_Z, SHORTCUT_MASK), (Action) (actions
+                .get("undo")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_Y, SHORTCUT_MASK), (Action) (actions
+                .get("redo")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0), (Action) (actions
+                .get("comment-block")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_F7, 0), (Action) (actions
+                .get("uncomment-block")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0), (Action) (actions.get("indent-block")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0),
+                (Action) (actions.get("deindent-block")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_M, SHORTCUT_MASK), 
+                (Action) (actions.get("insert-method")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), 
+                (Action) (actions.get("indent")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, Event.SHIFT_MASK), 
+                (Action) (actions.get("de-indent")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_I, SHORTCUT_MASK), 
+                (Action) (actions.get("insert-tab")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), 
+                (Action) (actions.get("new-line")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Event.SHIFT_MASK), 
+                (Action) (actions.get("insert-break")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_F, SHORTCUT_MASK), 
+                (Action) (actions.get("find")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_G, SHORTCUT_MASK), 
+                (Action) (actions.get("find-next")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_G, SHIFT_SHORTCUT_MASK), (Action) (actions
+                .get("find-next-backward")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_R, SHORTCUT_MASK), (Action) (actions
+                .get("replace")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_L, SHORTCUT_MASK), (Action) (actions
+                .get("go-to-line")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_K, SHORTCUT_MASK), (Action) (actions
+                .get("compile")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_J, SHORTCUT_MASK), (Action) (actions
+                .get("toggle-interface-view")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_B, SHORTCUT_MASK), (Action) (actions
+                .get("toggle-breakpoint")));
+        // "key-bindings" not bound
+        // "preferences" not bound
+        // "about-editor" not bound
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_D, SHORTCUT_MASK), (Action) (actions
+                .get("describe-key")));
+        // "help-mouse" not bound
+        // "show-manual" not bound
+
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_C, SHORTCUT_MASK), (Action) (actions
+                .get(DefaultEditorKit.copyAction)));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_X, SHORTCUT_MASK), (Action) (actions
+                .get(DefaultEditorKit.cutAction)));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_V, SHORTCUT_MASK), (Action) (actions
+                .get(DefaultEditorKit.pasteAction)));
+
+        // F2, F3, F4
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), (Action) (actions.get("copy-line")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0), (Action) (actions
+                .get(DefaultEditorKit.pasteAction)));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0), (Action) (actions.get("cut-line")));
+
+        // cursor block
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_UP, ALT_SHORTCUT_MASK), (Action) (actions
+                .get(DefaultEditorKit.pasteAction)));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, ALT_SHORTCUT_MASK), (Action) (actions
+                .get(DefaultEditorKit.deletePrevCharAction)));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, ALT_SHORTCUT_MASK), (Action) (actions
+                .get(DefaultEditorKit.deleteNextCharAction)));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, SHIFT_ALT_SHORTCUT_MASK),
+                (Action) (actions.get("cut-line")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, SHIFT_ALT_SHORTCUT_MASK),
+                (Action) (actions.get("cut-end-of-line")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, DOUBLE_SHORTCUT_MASK), (Action) (actions
+                .get("cut-word")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, DOUBLE_SHORTCUT_MASK), (Action) (actions
+                .get("cut-end-of-word")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, SHORTCUT_MASK), (Action) (actions
+                .get("increase-font")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, SHORTCUT_MASK), (Action) (actions
+                .get("decrease-font")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, Event.CTRL_MASK), (Action) (actions
+                .get("code-completion")));
+        keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_I, SHIFT_SHORTCUT_MASK ), (Action) (actions
+                .get("autoindent")));
+
+    }
+
+    /**
+     * Interface LineAction - a superclass for all line actions. Line actions
+     * manipulate a single line of text and are used by the blockAction method.
+     * The blockAction applies a LineAction to each line in a block of text.
+     */
+    interface LineAction
+    {
+        /**
+         * Apply some action to a line in the document.
+         */
+        public void apply(Element line, MoeSyntaxDocument doc);
+    }
+
+
+
+    /**
+     * Class CommentLineAction - add a comment symbol to the given line.
+     */
+    class CommentLineAction
+    implements LineAction
+    {
+        /**
+         * Comment the given line
+         */
+        public void apply(Element line, MoeSyntaxDocument doc)
+        {
+            int lineStart = line.getStartOffset();
+            try {
+                doc.insertString(lineStart, "// ", null);
+            }
+            catch (Exception exc) {}
+        }
+    }
+
+
+    /**
+     * Class UncommentLineAction - remove the comment symbol (if any) from the
+     * given line.
+     */
+    class UncommentLineAction
+    implements LineAction
+    {
+        public void apply(Element line, MoeSyntaxDocument doc)
+        {
+            int lineStart = line.getStartOffset();
+            int lineEnd = line.getEndOffset();
+            try {
+                String lineText = doc.getText(lineStart, lineEnd - lineStart);
+                if (lineText.trim().startsWith("//")) {
+                    int cnt = 0;
+                    while (lineText.charAt(cnt) != '/')
+                        // whitespace chars
+                        cnt++;
+                    if (lineText.charAt(cnt + 2) == ' ')
+                        doc.remove(lineStart, cnt + 3);
+                    else
+                        doc.remove(lineStart, cnt + 2);
+                }
+            }
+            catch (Exception exc) {}
+        }
+    }
+
+    /**
+     * Class IndentLineAction - add one level of indentation to the given line.
+     */
+    class IndentLineAction
+    implements LineAction
+    {
+        public void apply(Element line, MoeSyntaxDocument doc)
+        {
+            int lineStart = line.getStartOffset();
+            try {
+                doc.insertString(lineStart, spaces.substring(0, tabSize), null);
+            }
+            catch (Exception exc) {}
+        }
+    }
+
+    /**
+     * Class DeindentLineAction - remove one indentation level from the given
+     * line.
+     */
+    class DeindentLineAction
+    implements LineAction
+    {
+        public void apply(Element line, MoeSyntaxDocument doc)
+        {
+            int lineStart = line.getStartOffset();
+            int lineEnd = line.getEndOffset();
+            try {
+                String lineText = doc.getText(lineStart, lineEnd - lineStart);
+                String spacedTab = spaces.substring(0, tabSize);
+                if (lineText.startsWith(spacedTab))
+                    doc.remove(lineStart, tabSize); // remove spaced tab
+                else if (lineText.charAt(0) == TAB_CHAR)
+                    doc.remove(lineStart, 1); // remove hard tab
+                else {
+                    int cnt = 0;
+                    while (lineText.charAt(cnt) == ' ')
+                        // remove spaces
+                        cnt++;
+                    doc.remove(lineStart, cnt);
+                }
+            }
+            catch (Exception exc) {}
+        }
+    }
+
+    /**
+     * Class KeyCatcher - used for implementation of "describe-key" command to
+     * catch the next key press so that we can see what it does.
+     */
+    class KeyCatcher extends KeyAdapter
+    {
+        MoeEditor editor;
+
+        @Override
+        public void keyPressed(KeyEvent e)
+        {
+            int keyCode = e.getKeyCode();
+
+            if (keyCode == KeyEvent.VK_CAPS_LOCK || // the keys we want to
+                    // ignore...
+                    keyCode == KeyEvent.VK_SHIFT || keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_META
+                    || keyCode == KeyEvent.VK_ALT || keyCode == KeyEvent.VK_ALT_GRAPH || keyCode == KeyEvent.VK_COMPOSE
+                    || keyCode == KeyEvent.VK_NUM_LOCK || keyCode == KeyEvent.VK_SCROLL_LOCK
+                    || keyCode == KeyEvent.VK_UNDEFINED)
+                return;
+
+            KeyStroke key = KeyStroke.getKeyStrokeForEvent(e);
+            String modifierName = KeyEvent.getKeyModifiersText(key.getModifiers());
+            String keyName = KeyEvent.getKeyText(keyCode);
+            if (modifierName.length() > 0)
+                keyName = modifierName + "+" + keyName;
+
+            Keymap map = keymap;
+            Action action = null;
+
+            while (map != null && action == null) {
+                action = map.getAction(key);
+                map = map.getResolveParent();
+            }
+
+            if (action == null) {
+                // BUG workaround: bindings inhertited from component are not
+                // found
+                // through the keymap. we search for them explicitly here...
+                Object binding = componentInputMap.get(key);
+                if (binding == null){
+                    editor.writeMessage(keyName + " " + Config.getString("editor.keypressed.keyIsNotBound").trim());
+                }
+                else {
+                    editor.writeMessage(keyName + " " +Config.getString("editor.keypressed.callsTheFunction").trim() + binding + "\"");
+                }
+            }
+            else {
+                String name = (String) action.getValue(Action.NAME);
+                editor.writeMessage(keyName + Config.getString("editor.keypressed.callsTheFunction") + name + "\"");
+            }
+            e.getComponent().removeKeyListener(keyCatcher);
+            e.consume();
+        }
+
+        public void setEditor(MoeEditor ed)
+        {
+            editor = ed;
+        }
+
+    }
+   
+    private static String getNodeContents(MoeSyntaxDocument doc, NodeAndPosition<ParsedNode> nap)
+    {
+        try {
+            return doc.getText(nap.getPosition(), nap.getSize());
+        }
+        catch (BadLocationException e) {
+            Debug.reportError("Error getting node contents in document", e);
+            return "";
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeBorderHighlighterPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeBorderHighlighterPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..24a3f047d8f78b9b613641861f5b366d1eeb604b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeBorderHighlighterPainter.java
@@ -0,0 +1,161 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.Position;
+import javax.swing.text.View;
+
+/**
+ * Highlighter for the border and fill of the found search instances.<p>
+ * 
+ * This highlighter also paints in a different colour where it coincides with the
+ * selection.
+ * 
+ * @author Marion Zalk
+ */
+public class MoeBorderHighlighterPainter implements AdvancedHighlightPainter
+{
+    Color borderColor=Color.BLACK;
+    Color innerColor1;
+    Color innerColor2;
+    Color selectionColor1;
+    Color selectionColor2;
+    
+    public MoeBorderHighlighterPainter(Color bColor, Color fillColor1, Color fillColor2,
+            Color selectionColor1, Color selectionColor2)
+    {
+        //super(fillColor1);
+        borderColor=bColor;
+        innerColor1=fillColor1;
+        innerColor2=fillColor2;
+        this.selectionColor1 = selectionColor1;
+        this.selectionColor2 = selectionColor2;
+    }
+    
+    /**
+     * Paint a gradient fill
+     * @param g  The graphics object on which to draw
+     * @param r  The region to be occupied by the fill
+     * @param color1   The first color in the gradient
+     * @param color2   The second color in the gradient
+     */
+    private void paintGradient(Graphics g, Rectangle r, Color color1, Color color2)
+    {
+        if (g instanceof Graphics2D) {
+            Graphics2D g2d = (Graphics2D)g;
+            Paint origPaint = g2d.getPaint();
+
+            // Paint a gradient from top to bottom:
+            GradientPaint gp = new GradientPaint(
+                r.x,r.y, color1,
+                r.x+(r.width/2), r.y+r.height, color2);
+
+            g2d.setPaint(gp);
+            //g2d.fillRect(r.x-1, r.y, r.width+1, r.height);
+            g2d.fillRoundRect(r.x - 2, r.y, r.width + 2, r.height, 6, 6);
+            g2d.setPaint(origPaint);
+        }
+    }
+    
+    /**
+     * Overrides the default method in order to draw the border 
+     */
+    public void paint(Graphics g, int offs0, int offs1, Shape bounds,
+            JTextComponent c, View view)
+    {        
+        // Should only render part of View.
+        try {
+            // --- determine locations ---
+            offs0 = Math.max(offs0, view.getStartOffset());
+            offs1 = Math.min(offs1, view.getEndOffset());
+            
+            Shape s = view.modelToView(offs0, Position.Bias.Forward, offs1, Position.Bias.Backward, bounds);
+            Rectangle r = s.getBounds();
+            
+            paintGradient(g, r, innerColor1, innerColor2);
+
+            g.setColor(borderColor);
+            
+            int selStart = c.getSelectionStart();
+            int selEnd = c.getSelectionEnd();
+            boolean overLaps = selStart != selEnd;
+            overLaps &= (selStart < offs1 && selEnd >= offs0);
+                   
+            if (overLaps) {
+                Shape origClip = g.getClip();
+                Rectangle clip = (origClip != null) ? origClip.getBounds() : bounds.getBounds();
+                if (selEnd < offs1) {
+                    int clipR = view.modelToView(selEnd, bounds,
+                            Position.Bias.Backward).getBounds().x;
+                    clip.width = Math.min(clip.width, clipR - clip.x);
+                }
+                if (selStart > offs0) {
+                    int clipL = view.modelToView(selStart, bounds,
+                            Position.Bias.Forward).getBounds().x;
+                    int diff = clipL - clip.x;
+                    if (diff > 0) {
+                        clip.x = clipL;
+                        clip.width -= diff;
+                    }
+                }
+
+                g.setClip(clip);
+                paintGradient(g, r, selectionColor1, selectionColor2);
+                g.setClip(origClip);
+            }
+
+            g.drawRoundRect(r.x-2,r.y, r.width+2, r.height-1, 6, 6);
+            
+            r.x -= 2;
+            r.width += 3;
+        } catch (BadLocationException e) {
+            // throw new RuntimeException(e);
+            return;
+        }
+    }
+
+    @Override
+    public void issueRepaint(int p0, int p1, Shape viewBounds,
+            JTextComponent editor, View rootView)
+    {
+        try {
+            Shape s = rootView.modelToView(p0, Position.Bias.Forward, p1, Position.Bias.Backward, viewBounds);
+            Rectangle r = s.getBounds();
+            r.x -= 2;
+            r.width += 4;
+            editor.repaint(r);
+        }
+        catch (BadLocationException ble) {
+            throw new RuntimeException(ble);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeCaret.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeCaret.java
new file mode 100644
index 0000000000000000000000000000000000000000..262b0e73d16a93ac3bb40b97ee91300211478a1d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeCaret.java
@@ -0,0 +1,183 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.awt.Point;
+import java.awt.event.FocusEvent;
+import java.awt.event.MouseEvent;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultCaret;
+import javax.swing.text.LayeredHighlighter;
+import javax.swing.text.Position;
+
+import bluej.utility.Debug;
+
+
+/**
+ * A customised caret for Moe. It gets most of its behaviour from
+ * Swing's "DefaultCaret" and adds some functionality.
+ *
+ * @author  Michael Kolling
+ */
+public class MoeCaret extends DefaultCaret  
+{
+    private static final Color bracketHighlightColour = new Color(230, 200, 200);
+    
+    private static final LayeredHighlighter.LayerPainter bracketPainter = 
+        new BracketMatchPainter(bracketHighlightColour);
+        
+    private MoeEditor editor;
+
+    private boolean persistentHighlight = false;
+    
+    // matching bracket highlight holder
+    private Object matchingBracketHighlight;
+
+    /**
+     * Constructs a Moe Caret
+     */
+    public MoeCaret(MoeEditor editor) 
+    {
+        super();
+        this.editor = editor;
+        setBlinkRate(0);
+    }
+
+    /**
+     * Redefinition of caret positioning (after mouse click). Here, we
+     * first check whether the click was in the tag line. If it was, we
+     * toggle the breakpoint, if not we just position the caret as usual.
+     */
+    protected void positionCaret(MouseEvent e) 
+    {
+        Point pt = new Point(e.getX(), e.getY());
+        Position.Bias[] biasRet = new Position.Bias[1];
+        int pos = getComponent().getUI().viewToModel(getComponent(), pt, biasRet);
+
+        if (e.getX() > MoeSyntaxView.TAG_WIDTH) {
+            super.positionCaret(e);
+        }
+        else {
+            editor.toggleBreakpoint(pos);
+        }
+    }
+
+    /**
+     * Tries to move the position of the caret from
+     * the coordinates of a mouse event, using viewToModel(). 
+     * This will cause a selection if the dot and mark
+     * are different.
+     *
+     * @param e the mouse event
+     */
+    protected void moveCaret(MouseEvent e) 
+    {
+        if (e.getX() > MoeSyntaxView.TAG_WIDTH) {
+            super.moveCaret(e);
+        }
+    }
+    
+    /**
+     * Set the dot and mark position
+     */
+    public void setDot(int pos)
+    {
+        persistentHighlight = false;
+        super.setDot(pos);
+    }
+    
+    /**
+     * Set the dot position (leave the mark where it is).
+     */
+    public void moveDot(int pos)
+    {
+        persistentHighlight = false;
+        super.moveDot(pos);
+    }
+
+    @Override
+    protected void fireStateChanged()
+    {
+        // Note this is called when the caret is moved.
+        super.fireStateChanged();
+        editor.caretMoved();
+    }
+    
+    /**
+     * Target text component lost focus.
+     */
+    public void focusLost(FocusEvent e)
+    {
+        super.focusLost(e);
+    }
+    
+    /**
+     * Set the highlight (of the selection) as persistent - that is, it won't
+     * become invisible if the component loses focus. This lasts until the
+     * caret position is changed.
+     */
+    public void setPersistentHighlight()
+    {
+        setSelectionVisible(true);
+        persistentHighlight = true;
+    }
+     
+    /**
+     * Paint matching bracket if caret is directly after a bracket.  
+     */
+    public void paintMatchingBracket()
+    {
+        int matchBracket = editor.getBracketMatch();
+        // remove existing bracket if needed
+        removeBracket();
+        if(matchBracket != -1) {
+            try {
+                matchingBracketHighlight = getComponent().getHighlighter().addHighlight(matchBracket, matchBracket + 1, bracketPainter);
+            }
+            catch(BadLocationException ble) {
+                Debug.reportError("bad location exception thrown");
+                ble.printStackTrace();
+            }
+        }      
+    }
+    
+    /**
+     * remove the existing matching bracket if it exists
+     */
+    public void removeBracket()
+    {
+        if(matchingBracketHighlight != null) {
+            getComponent().getHighlighter().removeHighlight(matchingBracketHighlight);
+            matchingBracketHighlight = null;        
+        }  
+    }
+    
+    @Override
+    public void setSelectionVisible(boolean vis)
+    {
+        if (vis || ! persistentHighlight) {
+            super.setSelectionVisible(vis);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeDocumentListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeDocumentListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..264553a02b05e83d7b6419e84ee06d65c3e4a419
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeDocumentListener.java
@@ -0,0 +1,48 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+/**
+ * An interface for listening to parse events on a MoeSyntaxDocument.
+ * 
+ * @author Davin McCall
+ */
+public interface MoeDocumentListener
+{
+    /**
+     * A parse error was encountered while parsing (part of) the document
+     * 
+     * @param position   The position of the error
+     * @param size       The length of the error
+     * @param message    The error message
+     */
+    public void parseError(int position, int size, String message);
+    
+    /**
+     * A range of the document has been scheduled to be re-parsed. Any current errors within
+     * the specified range should be considered invalid.
+     * 
+     * @param position  The beginning of the range
+     * @param size      The size of the range
+     */
+    public void reparsingRange(int position, int size);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditor.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditor.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6100c4772bb20ab6fa31fb4e2c2ff40faa58de8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditor.java
@@ -0,0 +1,3838 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.FocusTraversalPolicy;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GraphicsEnvironment;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterJob;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Properties;
+
+import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Caret;
+import javax.swing.text.Document;
+import javax.swing.text.EditorKit;
+import javax.swing.text.Element;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.HTMLFrameHyperlinkEvent;
+
+import bluej.BlueJEvent;
+import bluej.BlueJEventListener;
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.compiler.Diagnostic;
+import bluej.editor.EditorWatcher;
+import bluej.parser.AssistContent;
+import bluej.parser.CodeSuggestions;
+import bluej.parser.ParseUtils;
+import bluej.parser.SourceLocation;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.lexer.LocatableToken;
+import bluej.parser.nodes.ParsedCUNode;
+import bluej.pkgmgr.JavadocResolver;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.DBox;
+import bluej.utility.DBoxLayout;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+import bluej.utility.GradientFillPanel;
+import bluej.utility.Utility;
+
+/**
+ * Moe is the editor of the BlueJ environment. This class is the main class of
+ * this editor and implements the top-level functionality.
+ * 
+ * <p>MoeEditor implements the Editor interface, which defines the interface to the
+ * rest of the BlueJ system.
+ * 
+ * @author Michael Kolling
+ * @author Bruce Quig
+ * @author Damiano Bolla
+ */
+
+public final class MoeEditor extends JFrame
+    implements bluej.editor.Editor, BlueJEventListener, HyperlinkListener, DocumentListener, MouseListener
+{
+    // -------- CONSTANTS --------
+
+    // version number
+    final static int version = 300;
+    final static String versionString = "3.0.0";
+
+    // colours
+    final static Color cursorColor = new Color(255, 0, 100);                 // cursor
+
+    final static Color infoColor = new Color(240, 240, 240);
+    final static Color lightGrey = new Color(224, 224, 224);
+    final static Color selectionColour = Config.getSelectionColour();
+    final static Color envOpColour = Config.ENV_COLOUR;
+
+    // Fonts
+    public static int printFontSize = Config.getPropInteger("bluej.fontsize.printText", 10);
+    public static Font printFont = new Font("Monospaced", Font.PLAIN, printFontSize);
+
+    // Strings
+    private final String implementationString = Config.getString("editor.implementationLabel");
+    private final String interfaceString = Config.getString("editor.interfaceLabel");
+
+    // suffixes for resources
+    final static String LabelSuffix = "Label";
+    final static String ActionSuffix = "Action";
+    final static String TooltipSuffix = "Tooltip";
+    final static String AcceleratorSuffix = "Accelerator";
+
+    // file suffixes
+    private final static String CRASHFILE_SUFFIX = "#";
+    private final static String BACKUP_SUFFIX = "~";
+
+    // other
+    final static String COMPILED = "compiled";
+    private final static int NAVIVIEW_WIDTH = 90;       // width of the "naviview" (min-source) box
+
+    // -------- CLASS VARIABLES --------
+
+    private static boolean matchBrackets = false;
+    
+    private static final Color highlightBorderColor = new Color(212, 172,45);
+    
+    protected static AdvancedHighlightPainter searchHighlightPainter =
+        new MoeBorderHighlighterPainter(highlightBorderColor, Config.getHighlightColour(),
+                Config.getHighlightColour2(), Config.getSelectionColour2(),
+                Config.getSelectionColour());;
+
+    // -------- INSTANCE VARIABLES --------
+
+    private EditorWatcher watcher;
+    private Properties resources;
+
+    private AbstractDocument document;
+    private MoeSyntaxDocument sourceDocument;
+    private HTMLDocument htmlDocument;
+
+    private MoeActions actions;
+    public MoeUndoManager undoManager;
+
+    private JEditorPane currentTextPane;    // text component currently displayed
+    private JEditorPane sourcePane;         // the component holding the source text
+
+    private JEditorPane htmlPane;           // the component holding the javadoc html
+    private MoeCaret moeCaret;
+
+    private Info info;                      // the info number label
+    private JPanel statusArea;              // the status area
+    private StatusLabel saveState;          // the status label
+    private JComboBox interfaceToggle;
+    private GoToLineDialog goToLineDialog;
+
+    // find functionality
+    private FindPanel finder;
+    private ReplacePanel replacer;
+
+    private JScrollPane scrollPane;
+    private NaviView naviView;              // Navigation view (mini-source view)
+    private EditorDividerPanel dividerPanel;  // Divider Panel to indicate separation between the
+                                            // editor and navigation view
+    private JComponent toolbar;             // The toolbar
+    private JPopupMenu popup;               // Popup menu options
+
+    private String filename;                // name of file or null
+    private long lastModified;              // time of last modification of file
+    private String windowTitle;             // title of editor window
+    private String docFilename;             // path to javadoc html file
+    private Charset characterSet;           // character set of the file
+
+    private boolean sourceIsCode;           // true if current buffer is code
+    private boolean viewingHTML;
+
+    private int currentStepPos;             // position of step mark (or -1)
+    private boolean mayHaveBreakpoints;     // true if there were BP here
+    private boolean ignoreChanges = false;
+    private boolean tabsAreExpanded = false;
+
+    private MoePrinter printer;
+    private PrintDialog printDialog;
+
+    private TextInsertNotifier doTextInsert = new TextInsertNotifier();
+
+    /**
+     * list of actions that are dis/enabled depending on the selected view
+     * (source/documentation)
+     */
+    private static ArrayList<String> editActions;
+    /**
+     * list of actions that are disabled in the readme text file
+     */
+    private static ArrayList<String> readMeActions;
+
+    /** Used to obtain javadoc for arbitrary methods */
+    private JavadocResolver javadocResolver;
+    private ReparseRunner reparseRunner;
+
+    /** Search highlight tags for both text panes */
+    private List<Object> sourceSearchHighlightTags = new ArrayList<Object>();
+    private List<Object> htmlSearchHighlightTags = new ArrayList<Object>();
+    
+    /** Manages display of compiler and parse errors */
+    private MoeErrorManager errorManager = new MoeErrorManager(this);
+    
+    /**
+     * Property map, allows BlueJ extensions to associate property values with
+     * this editor instance; otherwise unused.
+     */
+    private HashMap<String,Object> propertyMap = new HashMap<String,Object>();
+    
+    // Blackbox data recording:
+    private ArrayList<String> previousDoc = null;
+
+
+    /**
+     * Constructor. Title may be null.
+     */
+    public MoeEditor(MoeEditorParameters parameters)
+    {
+        super("Moe");
+        watcher = parameters.getWatcher();
+        resources = parameters.getResources();
+        javadocResolver = parameters.getJavadocResolver();
+
+        filename = null;
+        windowTitle = parameters.getTitle();
+        sourceIsCode = parameters.isCode();
+        viewingHTML = false;
+        currentStepPos = -1;
+        mayHaveBreakpoints = false;
+        matchBrackets = PrefMgr.getFlag(PrefMgr.MATCH_BRACKETS);
+        undoManager = new MoeUndoManager(this);
+
+        initWindow(parameters.getProjectResolver());
+    }
+
+    // --------------------------------------------------------------------
+
+    /*
+     * Load the file "filename" and show the editor window.
+     */
+    @Override
+    public boolean showFile(String filename, Charset charset, boolean compiled,
+            String docFilename, Rectangle bounds)
+    {
+        this.filename = filename;
+        this.docFilename = docFilename;
+        this.characterSet = charset;
+
+        if (bounds != null) {
+            if (bounds.x > (Config.screenBounds.width - 80))
+                bounds.x = Config.screenBounds.width - 80;
+            
+            if (bounds.y > (Config.screenBounds.height - 80))
+                bounds.y = Config.screenBounds.height - 80;
+            
+            if (bounds.width > 0 && bounds.height > 0) {
+                setBounds(bounds);
+            }
+            else {
+                setLocation(bounds.x, bounds.y);
+            }
+        }
+
+        boolean loaded = false;
+
+        if (filename != null) {
+            try {
+                // check for crash file
+                String crashFilename = filename + CRASHFILE_SUFFIX;
+                String backupFilename = crashFilename + "backup";
+                File crashFile = new File(crashFilename);
+                if (crashFile.exists()) {
+                    File backupFile = new File(backupFilename);
+                    backupFile.delete();
+                    crashFile.renameTo(backupFile);
+                    DialogManager.showMessage(this, "editor-crashed");
+                }
+
+                // FileReader reader = new FileReader(filename);
+                FileInputStream inputStream = new FileInputStream(filename);
+                Reader reader = new InputStreamReader(inputStream, charset);
+                sourcePane.read(reader, null);
+                try {
+                    reader.close();
+                    inputStream.close();
+                }
+                catch (IOException ioe) {}
+                File file = new File(filename);
+                lastModified = file.lastModified();
+                
+                recordLoadContent();
+
+                sourcePane.addMouseListener(this);
+                sourceDocument = (MoeSyntaxDocument) sourcePane.getDocument();
+                naviView.setDocument(sourceDocument);
+                sourceDocument.addDocumentListener(this);
+                sourceDocument.addUndoableEditListener(undoManager);
+                document = sourceDocument;
+                
+                sourceDocument.enableParser(false);
+                loaded = true;
+                
+                scheduleReparseRunner();
+            }
+            catch (FileNotFoundException ex) {
+                clear();
+            }
+            catch (IOException ex) {
+                Debug.reportError("Couldn't open file", ex);
+            }
+        }
+        else {
+            if (docFilename != null) {
+                if (new File(docFilename).exists()) {
+                    showInterface(true);
+                    loaded = true;
+                    interfaceToggle.setEnabled(false);
+                }
+            }
+        }
+
+        if (!loaded) {
+            // should exist, but didn't
+            return false;
+        }
+
+        info.message(Config.getString("editor.info.version") + " " + versionString);
+
+        setWindowTitle();
+        sourcePane.setFont(PrefMgr.getStandardEditorFont());
+
+        setCompileStatus(compiled);
+
+        return true;
+    }
+
+    /*
+     * Reload the editor content from the associated file, discarding unsaved
+     * edits.
+     */
+    @Override
+    public void reloadFile()       // inherited from Editor, redefined
+    {
+        doReload();
+    }
+
+    /*
+     * Wipe out contents of the editor.
+     */
+    @Override
+    public void clear()       // inherited from Editor, redefined
+    {
+        ignoreChanges = true;
+        sourcePane.setText("");
+        ignoreChanges = false;
+    }
+
+    /**
+     * Insert a string into the buffer. The editor is not immediately
+     * redisplayed. This function is typically used in a sequence "clear;
+     * [insertText]*; setVisible(true)". If the selection is on, it is replaced
+     * by the new text.
+     * 
+     * @param text  the text to be inserted
+     * @param caretBack  move the caret to the beginning of the inserted text
+     */
+    public void insertText(String text, boolean caretBack)       // inherited from Editor, redefined
+    {
+        sourcePane.replaceSelection(text);
+        if (caretBack) {
+            sourcePane.setCaretPosition(sourcePane.getCaretPosition() - text.length());
+        }
+    }
+
+    /**
+     * Show the editor window. This includes whatever is necessary of the
+     * following: make visible, de-iconify, bring to front of window stack.
+     * 
+     * @param vis  The new visible value
+     */
+    public void setVisible(boolean vis)       // inherited from Editor, redefined
+    {
+        if (vis) {
+            sourcePane.setFont(PrefMgr.getStandardEditorFont());
+            checkBracketStatus();
+        }
+
+        super.setVisible(vis);              // show the window
+
+        if(vis) {
+            setState(Frame.NORMAL);         // de-iconify
+            toFront();                      // window to front  
+            Utility.bringToFront(this);        
+        }
+    }
+
+    /**
+     * Refresh the editor window.
+     */
+    public void refresh()       // inherited from Editor, redefined
+    {
+        sourcePane.setFont(PrefMgr.getStandardEditorFont());
+        checkBracketStatus();
+        currentTextPane.repaint();
+        
+        Info.resetFont();
+        info.refresh();
+        StatusLabel.resetFont();
+        saveState.refresh();
+    }
+
+    /*
+     * Save the buffer to disk under current filename, if there any changes.
+     * This method may be called often.
+     */
+    @Override
+    public void save()
+        throws IOException
+    {
+        IOException failureException = null;
+        if (saveState.isChanged()) {
+            Writer writer = null;
+            try {
+                // The crash file is used during writing and will remain in
+                // case of a crash during the write operation. The backup
+                // file always contains the last version.
+                String crashFilename = filename + CRASHFILE_SUFFIX;
+                String backupFilename = filename + BACKUP_SUFFIX;
+
+                // make a backup to the crash file
+                FileUtility.copyFile(filename, crashFilename);
+
+                OutputStream ostream = new BufferedOutputStream(new FileOutputStream(filename));
+                writer = new OutputStreamWriter(ostream, characterSet);
+                sourcePane.write(writer);
+                writer.close(); writer = null;
+                setSaved();
+                lastModified = new File(filename).lastModified();
+
+                if (PrefMgr.getFlag(PrefMgr.MAKE_BACKUP)) {
+                    // if all went well, rename the crash file as a normal
+                    // backup
+                    File crashFile = new File(crashFilename);
+                    File backupFile = new File(backupFilename);
+                    backupFile.delete();
+                    crashFile.renameTo(backupFile);
+                }
+                else {
+                    File crashFile = new File(crashFilename);
+                    crashFile.delete();
+                }
+            }
+            catch (IOException ex) {
+                failureException = ex;
+                info.warning(Config.getString("editor.info.errorSaving") + " - " + ex.getLocalizedMessage());
+            }
+            finally {
+                try {
+                    if(writer != null)
+                        writer.close();
+                }
+                catch (IOException ex) {
+                    failureException = ex;
+                }
+            }
+        }
+
+        // If an error occurred, set a message in the editor status bar, and
+        // re-throw the exception.
+        if (failureException != null) {
+            info.warning(Config.getString("editor.info.errorSaving")
+                    + " - " + failureException.getLocalizedMessage());
+            throw failureException;
+        }
+    }
+
+    /**
+     * The editor wants to close. Do this through the EditorManager so that we
+     * can be removed from the list of open editors.
+     */
+    public void close()       // inherited from Editor, redefined
+    {
+        try {
+            save();
+        }
+        catch (IOException ioe) {}
+        // temporary - should really be done by watcher from outside
+        doClose();
+    }
+
+    /**
+     * Display a message (used for compile/runtime errors). An editor must
+     * support at least two lines of message text, so the message can contain a
+     * newline character.
+     * 
+     * @param message  the message to be displayed
+     * @param lineNumber  The line to highlight
+     * @param column   the column to move the cursor to
+     * @param beep   if true, do a system beep
+     * @param setStepMark  if true, set step mark (for single stepping)
+     * @param help  name of help group (may be null)
+     */
+    public void displayMessage(String message, int lineNumber, int column, boolean beep, 
+            boolean setStepMark, String help)        // inherited from Editor
+    {
+        switchToSourceView();
+
+        Element line = getSourceLine(lineNumber);
+        int pos = line.getStartOffset();
+
+        if (setStepMark) {
+            setStepMark(pos);
+        }
+
+        // highlight the line
+
+        sourcePane.setCaretPosition(pos);
+        sourcePane.moveCaretPosition(line.getEndOffset() - 1);  // w/o line break
+        moeCaret.setPersistentHighlight();
+
+        // display the message
+
+        if (beep) {
+            info.warning(message);
+        }
+        else {
+            info.message(message);
+        }
+
+        if (help != null) {
+            info.setHelp(help);
+        }
+    }
+    
+    @Override
+    public void displayDiagnostic(Diagnostic diagnostic)
+    {
+        switchToSourceView();
+        
+        Element line = getSourceLine((int) diagnostic.getStartLine());
+        int pos = line.getStartOffset();
+        
+        // Limit diagnostic display to a single line.
+        int startPos = getPosFromColumn(line, (int) diagnostic.getStartColumn());
+        int endPos;
+        if (diagnostic.getStartLine() != diagnostic.getEndLine()) {
+            endPos = line.getEndOffset() - 1;
+        }
+        else {
+            endPos = getPosFromColumn(line, (int) diagnostic.getEndColumn());
+        }
+        
+        // highlight the error and the line on which it occurs
+
+        errorManager.removeErrorHighlight();
+        errorManager.addErrorHighlight(startPos, endPos);
+        
+        sourcePane.setCaretPosition(pos);
+        sourcePane.moveCaretPosition(line.getEndOffset() - 1); // w/o line break
+        moeCaret.setPersistentHighlight();
+
+        // display the message
+
+        info.message(diagnostic.getMessage());
+        info.setHelp("javac"); // TODO the compiler name, or the additional help text,
+                               // should really be a property of the diagnostic object.
+    }
+    
+    /**
+     * Get a position in a line from a column number, where the column number assumes
+     * tab stops are every 8 spaces.
+     */
+    private int getPosFromColumn(Element line, int column)
+    {
+        int spos = line.getStartOffset();
+        int epos = line.getEndOffset();
+        int testPos = Math.min(epos - spos - 1, column - 1);
+        if (testPos == 0) {
+            return spos;
+        }
+        
+        try {
+            int cpos = 0; // what the actual column is so far
+            int tpos = 0; // where we are in the string
+            String lineText = sourceDocument.getText(spos, testPos);
+            
+            while (cpos < column - 1) {
+                int tabPos = lineText.indexOf('\t', tpos);
+                if (tabPos == -1) {
+                    // No more tabs...
+                    tpos += column - cpos - 1;
+                    return Math.min(spos + tpos, epos - 1);
+                }
+                
+                int newcpos = cpos + (tabPos - tpos);
+                if (newcpos >= column) {
+                    tpos += column - cpos - 1;
+                    return spos + tpos;
+                }
+
+                cpos = newcpos;
+                
+                cpos += 8; // hit tab
+                cpos -= cpos % 8;  // back to tab stop
+
+                tpos = tabPos + 1; // skip over the tab char
+            }
+        }
+        catch (BadLocationException ble) {
+            // Shouldn't happen.
+            throw new RuntimeException(ble);
+        }
+        return spos;
+    }
+
+    /**
+     * Set the selection of the editor (in the source pane) to be {@code len} characters on
+     * line {@code lineNumber}, starting with column {@code columnNumber}.
+     * 
+     * @param lineNumber  the line to select characters on
+     * @param columnNumber  the column to start selection at (1st column is 1 - not 0)
+     * @param len         the number of characters to select
+     */
+    public void setSelection(int lineNumber, int columnNumber, int len)
+    {
+        Element line = getSourceLine(lineNumber);
+
+        sourcePane.select(line.getStartOffset() + columnNumber - 1, 
+                line.getStartOffset() + columnNumber + len - 1);
+    }
+
+    /**
+     * Select a specified area of text in the source pane.
+     * 
+     * @param lineNumber1  The new selection value
+     * @param columnNumber1  The new selection value
+     * @param lineNumber2  The new selection value
+     * @param columnNumber2  The new selection value
+     */
+    public void setSelection(int lineNumber1, int columnNumber1, int lineNumber2, int columnNumber2)
+    {
+        /*
+         * if (lineNumber2 < lineNumber1) return; if (lineNumber2 == lineNumber1 &&
+         * (columnNumber2 < columnNumber1)) return;
+         */
+        Element line1 = getSourceLine(lineNumber1);
+        Element line2 = getSourceLine(lineNumber2);
+
+        sourcePane.select(line1.getStartOffset() + columnNumber1 - 1, line2.getStartOffset() + columnNumber2 - 1);
+    }
+
+    /**
+     * Remove the step mark (the mark that shows the current line when
+     * single-stepping through code). If it is not currently displayed, do
+     * nothing.
+     */
+    public void removeStepMark()        // inherited from Editor
+    {
+        if (currentStepPos != -1) {
+            SimpleAttributeSet a = new SimpleAttributeSet();
+            a.addAttribute(MoeSyntaxView.STEPMARK, Boolean.FALSE);
+            sourceDocument.setParagraphAttributes(currentStepPos, a);
+            currentStepPos = -1;
+            // remove highlight as well
+            sourcePane.setCaretPosition(sourcePane.getCaretPosition());
+            // force an update of UI
+            repaint();
+        }
+    }
+
+    /**
+     * Change class name.
+     * 
+     * @param title  new window title
+     * @param filename  new file name
+     */
+    public void changeName(String title, String filename, String docFilename)
+    {
+        this.filename = filename;
+        this.docFilename = docFilename;
+        windowTitle = title;
+        setWindowTitle();
+    }
+
+    /**
+     * Set the "compiled" status
+     * 
+     * @param compiled  True if the class has been compiled.
+     */
+    public void setCompiled(boolean compiled)
+    {
+        setCompileStatus(compiled);
+        if (compiled) {
+            info.message(Config.getString("editor.info.compiled"));
+            errorManager.removeErrorHighlight();
+        }
+    }
+
+    /**
+     * Called when all the breakpoints have been cleared. The editor should
+     * update its display to show that no breakpoints are set.
+     */
+    public void removeBreakpoints()
+    {
+        // This may be a callback in response to a modification event.
+        // If we try to remove breakpoints during the modification notification,
+        // AbstractDocument throws an exception.
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                clearAllBreakpoints();
+            }
+        });
+    }
+
+    /**
+     * The editor must re-set all its breakpoints via the EditorWatcher
+     * interface.
+     */
+    public void reInitBreakpoints()
+    {
+        if (mayHaveBreakpoints) {
+            mayHaveBreakpoints = false;
+            for (int i = 1; i <= numberOfLines(); i++) {
+                if (lineHasBreakpoint(i)) {
+                    if (watcher != null)
+                        watcher.breakpointToggleEvent(this, i, true);
+                    mayHaveBreakpoints = true;
+                }
+            }
+        }
+    }
+
+    /**
+     *  Determine whether this buffer has been modified.
+     *
+     * @return    a boolean indicating whether the file is modified
+     */
+    public boolean isModified()        // inherited from Editor
+    {
+        return (saveState.isChanged());
+    }
+
+    /**
+     * Set this editor to read-only.
+     * 
+     * @param readOnly  The new readOnly value
+     */
+    public void setReadOnly(boolean readOnly)
+    {
+        if (readOnly) {
+            saveState.setState(StatusLabel.READONLY);
+            updateUndoControls();
+            updateRedoControls();
+        }
+        sourcePane.setEditable(!readOnly);
+    }
+
+    /**
+     * Returns if this editor is read-only. Accessor for the setReadOnly
+     * property.
+     * 
+     * @return a boolean indicating whether the editor is read-only.
+     */
+    public boolean isReadOnly()
+    {
+        return !sourcePane.isEditable();
+    }
+
+    /**
+     * Set this editor to display either the interface or the source code of
+     * this class
+     * 
+     * @param interfaceStatus  If true, display class interface, otherwise source.
+     */
+    public void showInterface(boolean interfaceStatus)
+    {
+        interfaceToggle.setSelectedIndex(interfaceStatus ? 1 : 0);
+    }
+
+    /**
+     * Tell whether the editor is currently displaying the interface or the
+     * source of the class.
+     * 
+     * @return True, if interface is currently shown, false otherwise.
+     */
+    public boolean isShowingInterface()
+    {
+        return viewingHTML;
+    }
+
+    /**
+     * Returns the current caret location within the edited text.
+     * 
+     * @return An object describing the current caret location.
+     */
+    public SourceLocation getCaretLocation()
+    {
+        int caretOffset = sourcePane.getCaretPosition();
+        return getLineColumnFromOffset(caretOffset);
+    }
+
+    /**
+     * Returns the SourceLocation object corresponding to the given offset in the
+     * source text.
+     * 
+     * @param offset  The number of characters from the beginning of text (starting
+     *                from zero)
+     * @return the SourceLocation object or null if the offset points outside the
+     *         text.
+     */
+    public SourceLocation getLineColumnFromOffset(int offset)
+    {
+        if (offset < 0) {
+            return null;
+        }
+        
+        Element map = sourceDocument.getDefaultRootElement();
+        int lineNumber = map.getElementIndex(offset);
+
+        Element lineElement = map.getElement(lineNumber);
+        if (offset >= lineElement.getEndOffset()) {
+            return null;
+        }
+        
+        int column = offset - lineElement.getStartOffset();
+
+        return new SourceLocation(lineNumber+1, column+1);
+    }
+
+    /**
+     * Sets the current Caret location within the edited text (source pane).
+     * 
+     * @param location  The location in the text to set the Caret to.
+     * @throws IllegalArgumentException
+     *             if the specified TextLocation represents a position which
+     *             does not exist in the text.
+     */
+    public void setCaretLocation(SourceLocation location)
+    {
+        sourcePane.setCaretPosition(getOffsetFromLineColumn(location));
+    }
+
+    /**
+     * Returns the location where the current selection (in the source pane)
+     * begins.
+     * 
+     * @return the current beginning of the selection or null if no text is
+     *         selected.
+     */
+    public SourceLocation getSelectionBegin()
+    {
+        Caret aCaret = sourcePane.getCaret();
+
+        // If the dot is == as the mark then there is no selection.
+        if (aCaret.getDot() == aCaret.getMark()) {
+            return null;
+        }
+
+        int beginOffset = Math.min(aCaret.getDot(), aCaret.getMark());
+
+        return getLineColumnFromOffset(beginOffset);
+    }
+
+    /**
+     * Returns the location where the current selection (in the
+     * source pane) ends.
+     * 
+     * @return the current end of the selection or null if no text is selected.
+     */
+    public SourceLocation getSelectionEnd()
+    {
+        Caret aCaret = sourcePane.getCaret();
+
+        // If the dot is == as the mark then there is no selection.
+        if (aCaret.getDot() == aCaret.getMark()) {
+            return null;
+        }
+
+        int endOffset = Math.max(aCaret.getDot(), aCaret.getMark());
+
+        return getLineColumnFromOffset(endOffset);
+    }
+
+    /**
+     * Returns the source text between two locations as a string.
+     * 
+     * @param begin  The beginning of the text to get
+     * @param end    The end of the text to get
+     * @return  The text between the 'begin' and 'end' positions.
+     * @throws IllegalArgumentException
+     *             if either of the specified TextLocations represent a position
+     *             which does not exist in the text.
+     */
+    public String getText(SourceLocation begin, SourceLocation end)
+    {
+        int first = getOffsetFromLineColumn(begin);
+        int last = getOffsetFromLineColumn(end);
+        int beginOffset = Math.min(first, last);
+        int endOffset = Math.max(first, last);
+
+        try {
+            return sourceDocument.getText(beginOffset, endOffset - beginOffset);
+        }
+        catch (BadLocationException exc) {
+            throw new IllegalArgumentException(exc.getMessage());
+        }
+    }
+
+    /**
+     * Request to the editor to replace the text between 'begin' and 'end' with
+     * the given newText. If begin and end point to the same location, the text
+     * is inserted.
+     * 
+     * @param begin  The start position of text to replace
+     * @param end    The end position of text to replace
+     * @param newText  The text to insert
+     * @throws IllegalArgumentException
+     *             if either of the specified SourceLocation represent a position
+     *             which does not exist in the text.
+     * @throws BadLocationException
+     *             if internally the text points outside a location in the text.
+     */
+    public void setText(SourceLocation begin, SourceLocation end, String newText)
+    throws BadLocationException
+    {
+        int start = getOffsetFromLineColumn(begin);
+        int finish = getOffsetFromLineColumn(end);
+
+        int beginOffset = Math.min(start, finish);
+        int endOffset = Math.max(start, finish);
+
+        if (beginOffset != endOffset) {
+            sourceDocument.remove(beginOffset, endOffset - beginOffset);
+        }
+
+        sourceDocument.insertString(beginOffset, newText, null);
+    }
+
+    /**
+     * Request to the editor to mark the source text between two positions as selected.
+     * 
+     * @param begin  The start position of the selection
+     * @param end  The end position of the selection
+     * @throws IllegalArgumentException
+     *             if either of the specified TextLocations represent a position
+     *             which does not exist in the text.
+     */
+    public void setSelection(SourceLocation begin, SourceLocation end)
+    {
+        int start = getOffsetFromLineColumn(begin);
+        int finish = getOffsetFromLineColumn(end);
+
+        int selectionStart = Math.min(start, finish);
+        int selectionEnd = Math.max(start, finish);
+
+        sourcePane.setCaretPosition(selectionStart);
+        sourcePane.moveCaretPosition(selectionEnd);
+    }
+
+    /**
+     * Translates a SourceLocation into an offset into the source text
+     * held by the editor.
+     * 
+     * @param location  position to be translated
+     * @return the offset into the content of this editor
+     * @throws IllegalArgumentException
+     *             if the specified SourceLocation represent a position which does
+     *             not exist in the text.
+     */
+    public int getOffsetFromLineColumn(SourceLocation location)
+    {
+        int col = location.getColumn() - 1;
+        int line = location.getLine() - 1;
+        
+        if (line < 0 || col < 0) {
+            throw new IllegalArgumentException("line or column < 1");
+        }
+        
+        Element map = sourceDocument.getDefaultRootElement();
+        if (line >= map.getElementCount()) {
+            throw new IllegalArgumentException("line=" + location.getLine()
+                    + " is out of bound");
+        }
+
+        Element lineElement = sourceDocument.getDefaultRootElement()
+                .getElement(line);
+
+        int lineOffset = lineElement.getStartOffset();
+        int lineLen = lineElement.getEndOffset() - lineOffset;
+
+        if (col >= lineLen) {
+            throw new IllegalArgumentException("column=" + location.getColumn() + " greater than line len=" + lineLen);
+        }
+
+        return lineOffset + col;
+    }
+
+    /**
+     * Returns a property of the current editor.
+     *
+     * @param  propertyKey  The propertyKey of the property to retrieve.
+     * @return              the property value or null if it is not found
+     */
+    public Object getProperty(String propertyKey)
+    {
+        return propertyMap.get(propertyKey);
+    }
+
+
+    /**
+     * Set a property for the current editor. Any existing property with
+     * this key will be overwritten.
+     *
+     * @param  propertyKey  The property key of the new property
+     * @param  value        The new property value
+     */
+    public void setProperty(String propertyKey, Object value)
+    {
+        if ( propertyKey == null ) {
+            return;
+        }
+
+        propertyMap.put(propertyKey,value);
+    }
+
+    /**
+     * Returns the length of the line indicated in the edited text.
+     * Zero is a valid value if the given line has no characters in it.
+     *
+     * @param  line  the line in the text for which the length should be calculated, starting from 0
+     * @return       the length of the line, -1 if line is invalid
+     */
+    public int getLineLength(int line)
+    {
+        if (line < 0) {
+            return -1;
+        }
+
+        Element lineElement = sourceDocument.getDefaultRootElement().getElement(line);
+        if (lineElement == null) {
+            return -1;
+        }
+
+        int startOffset = lineElement.getStartOffset();
+
+        return lineElement.getEndOffset() - startOffset;
+    }
+
+    /**
+     * Returns the length of the source document.
+     *
+     * It is possible to obtain the line and column of the last character of text by using
+     * this method together with the getLineColumnFromOffset() method.
+     *
+     * @return the source length (>= 0)
+     */
+    public int getTextLength ()
+    {
+        return sourceDocument.getLength();
+    }
+
+    /**
+     * Return the number of lines in the source document.
+     */
+    public int numberOfLines()
+    {
+        return sourceDocument.getDefaultRootElement().getElementCount();
+    }
+
+    /*
+     * @see bluej.editor.Editor#getParsedNode()
+     */
+    public ParsedCUNode getParsedNode()
+    {
+        return sourceDocument.getParser();
+    }
+    
+    // --------------------------------------------------------------------
+    // ------------ end of interface inherited from Editor ----------------
+    // --------------------------------------------------------------------
+
+    /**
+     * Update the state of controls bound to "undo".
+     */
+    public void updateUndoControls()
+    {
+        boolean canUndo = undoManager.canUndo();
+        displayMenuItem("undo", canUndo);
+        displayToolbarItem("undo", canUndo);
+    }
+
+    /**
+     * Update the state of controls bound to "redo".
+     */
+    public void updateRedoControls()
+    {
+        boolean canRedo = undoManager.canRedo();
+        displayMenuItem("redo", canRedo);
+        displayToolbarItem("redo", canRedo);
+    }
+    
+    /**
+     * Check whether the source file has changed on disk. If it has, reload.
+     */
+    private void checkForChangeOnDisk()
+    {
+        if (filename == null) {
+            return;
+        }
+        File file = new File(filename);
+        long modified = file.lastModified();
+        if(modified != lastModified) {
+            if (saveState.isChanged()) {
+                int answer = DialogManager.askQuestion(this, "changed-on-disk");
+                if (answer == 0)
+                    doReload();
+                else
+                    lastModified = modified; // don't ask again for this change
+            }
+            else {
+                doReload();
+            }
+        }
+    }
+    
+    /**
+     * Schedule the ReparseRunner on the AWT event queue, if it is not already scheduled.
+     */
+    private void scheduleReparseRunner()
+    {
+        if (reparseRunner == null) {
+            reparseRunner = new ReparseRunner(this);
+            EventQueue.invokeLater(reparseRunner);
+        }
+    }
+    
+    /**
+     * Informs the editor that the re-parse runner has de-scheduled itself due to lack
+     * of work.
+     */
+    public void reparseRunnerFinished()
+    {
+        reparseRunner = null;
+    }
+    
+    // ---- BlueJEventListener interface ----
+
+    /**
+     * A BlueJEvent was raised. Check whether it is one that we're interested
+     * in.
+     */
+    public void blueJEvent(int eventId, Object arg)
+    {
+        switch(eventId) {
+        case BlueJEvent.DOCU_GENERATED :
+            BlueJEvent.removeListener(this);
+            refreshHtmlDisplay();
+            break;
+        case BlueJEvent.DOCU_ABORTED :
+            BlueJEvent.removeListener(this);
+            info.warning(Config.getString("editor.info.docAborted"));
+            break;
+        }
+    }
+
+    // -------- DocumentListener interface --------
+
+    /**
+     * A text insertion has taken place.
+     */
+    public void insertUpdate(DocumentEvent e)
+    {
+        //errorManager.insertUpdate(e);
+        removeSearchHighlights();
+        errorManager.removeErrorHighlight();
+        if (!saveState.isChanged()) {
+            saveState.setState(StatusLabel.CHANGED);
+            setChanged();
+        }
+        actions.userAction();
+        doTextInsert.setEvent(e, sourcePane);
+        
+        // This may handle re-indentation; as this mutates the
+        // document, it must be done outside the notification.
+        // Really, this should be done via another mechanism - i.e.
+        // by binding '}' key to a specialised action. TODO.
+        SwingUtilities.invokeLater(doTextInsert);
+        
+        scheduleReparseRunner();
+    }
+
+    /**
+     * A text removal has taken place.
+     */
+    public void removeUpdate(DocumentEvent e)
+    {
+        //errorManager.removeUpdate(e);
+        removeSearchHighlights();
+        errorManager.removeErrorHighlight();
+        if (!saveState.isChanged()) {
+            saveState.setState(StatusLabel.CHANGED);
+            setChanged();
+        }
+        actions.userAction();
+        
+        scheduleReparseRunner();
+    }
+
+    /**
+     * Document properties have changed
+     */
+    public void changedUpdate(DocumentEvent e) { }
+    
+    // --------------------------------------------------------------------
+    /**
+     * Clear the message in the info area.
+     */
+    public void clearMessage()
+    {
+        info.clear();
+    }
+
+    /**
+     * Display a message into the info area.
+     * 
+     * @param msg  the message to display
+     */
+    public void writeMessage(String msg)
+    {
+        info.message(msg);
+    }
+
+    /**
+     * Write a warning message into the info area. Typically some form of
+     * unexpected behaviour has occurred.
+     * 
+     * @param msg  Description of the Parameter
+     */
+    public void writeWarningMessage(String msg)
+    {
+        info.warning(msg);
+    }
+
+    // ==================== USER ACTION IMPLEMENTATIONS ===================
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * User requests "save"
+     */
+    public void userSave()
+    {
+        if (saveState.isSaved())
+            info.message(Config.getString("editor.info.noChanges"));
+        else {
+            try {
+                save();
+            }
+            catch (IOException ioe) {}
+            // Note we can safely ignore the exception here: a message has
+            // already been displayed in the editor status bar
+        }
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * User requests "reload"
+     */
+    public void reload()
+    {
+        if (filename == null) {
+            info.warning(Config.getString("editor.info.cannotReload"), 
+                    Config.getString("editor.info.reload"));
+        }
+        else if (saveState.isChanged()) {
+            int answer = DialogManager.askQuestion(this, "really-reload");
+            if (answer == 0)
+                doReload();
+        }
+        else {
+            doReload();
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Prints source code from Editor
+     * 
+     * @param printerJob  A PrinterJob to print to.
+     */
+    public void print(PrinterJob printerJob)
+    {
+        if (printDialog == null) {
+            printDialog = new PrintDialog(this);
+        }
+
+        if (printDialog.display()) {
+            PrintHandler pt = new PrintHandler(printerJob, getPageFormat(printerJob), printDialog.printLineNumbers(), printDialog.printHighlighting());
+            pt.print();
+        }
+    }
+
+    /**
+     * Return a validated version of the global PageFormat for BlueJ
+     */
+    public PageFormat getPageFormat(PrinterJob job)
+    {
+        return job.validatePage(PkgMgrFrame.getPageFormat());
+    }
+
+    /**
+     * Generalised version of print function. This is what is typically called
+     * when print is initiated from within the source code editor menu. This
+     * sets up and runs the print process as a separate lower priority thread.
+     */
+    public void print()
+    {
+        if (printDialog == null)
+            printDialog = new PrintDialog(this);
+
+        if (printDialog.display()) {
+            // create a printjob
+            PrinterJob job = PrinterJob.getPrinterJob();
+            if (job.printDialog()) {
+                PrintHandler pt = new PrintHandler(job, getPageFormat(job), printDialog.printLineNumbers(), printDialog.printHighlighting());
+                Thread printJobThread = new Thread(pt);
+                printJobThread.setPriority((Thread.currentThread().getPriority() - 1));
+                printJobThread.start();
+            }
+        }
+    }
+
+    /**
+     * Implementation of the "page setup" user function. This provides a dialog
+     * for print page setup. PageSetup is global to BlueJ. Calling this from the 
+     * Editor is effectively the same as calling from PkgMgrFrame as this saves 
+     * back to PkgMgrFrame's global page format object.
+     */
+    public void pageSetup()
+    {
+        PrinterJob job = PrinterJob.getPrinterJob();
+        PageFormat pageFormat = job.pageDialog(PkgMgrFrame.getPageFormat());
+        PkgMgrFrame.setPageFormat(pageFormat);
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * The editor has been closed. Hide the editor window now.
+     */
+    public void doClose()
+    {
+        setVisible(false);
+        if (watcher != null) {
+            //setting the naviview visible property when an editor is closed
+            watcher.setProperty(EditorWatcher.NAVIVIEW_EXPANDED_PROPERTY, String.valueOf(dividerPanel.isExpanded()));
+            watcher.closeEvent(this);
+        }
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * Check whether TABs need expanding in this editor. If they do, return
+     * true, and mark tabs as no longer needing expanding (i.e. subsequent
+     * calls will return false).
+     */
+    public boolean checkExpandTabs()
+    {
+        if (tabsAreExpanded)
+            return false;
+
+        else {
+            tabsAreExpanded = true;
+            return true;
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * toggleReplacePanelVisible sets the replace panel editor in/visible
+     * if visible sets the necessary other values
+     */
+    public void toggleReplacePanelVisible()
+    {
+        if (replacer.isVisible() || !finder.isVisible()) {
+            replacer.setVisible(false);
+            return;
+        }
+        else {
+            replacer.setVisible(true);
+            finder.requestFindfieldFocus();
+        }
+    }
+
+    /**
+     * Opens or close the replace panel (and if opening it, set the focus into
+     * the find field).
+     */
+    protected void setReplacePanelVisible(boolean visible)
+    {
+        if (visible) {
+            if (!finder.isVisible()) {
+                finder.setVisible(visible);
+            }
+            replacer.setVisible(visible);
+            finder.requestFindfieldFocus();
+            finder.setFindReplaceIcon(true);
+        }
+        else {
+            replacer.setVisible(false);
+            finder.setFindReplaceIcon(false);
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Replaces the selected text with the replaceString; moves the caret to the 
+     * position it was in before the replace was requested and writes a message
+     */
+    public void replace(String replaceString)
+    {
+        int caretPos = sourcePane.getCaretPosition();
+        String searchString=finder.getSearchString();
+        if (getSourcePane().getSelectedText()==null|| getSourcePane().getSelectedText().length()<=0){
+            //in case the selection has been lost due to moving it in the editor
+            if (finder.getSearchString()!=null && finder.getSearchString().length()>0)
+                searchString=finder.getSearchTextfield();
+            else {
+                writeMessage("Invalid search string ");
+                return;
+            }
+        }
+        String replaceText = smartFormat(searchString, replaceString);
+        insertText(replaceText, true);
+        //move the caret back to where it was before the replace
+        sourcePane.setCaretPosition(caretPos);
+        finder.find(true);
+        //editor.writeMessage("Replaced " + count + " instances of " + searchString);
+        writeMessage("Replaced an instance of " + 
+                searchString);
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * Implementation of "find-next" user function.
+     */
+    public void findNext(boolean backwards)
+    {
+        String selection= currentTextPane.getSelectedText();
+        if (selection==null){
+            selection=finder.getSearchString();
+        }
+        //if the find panel is open- next/backwards should function like prev, next
+        //if it is not open, it should do a single find forward or backwards
+        if (finder.isVisible()){
+            finder.setSearchString(selection);
+            if (backwards) {
+                finder.getPrev();
+            }
+            else {
+                finder.getNext();
+            }
+        } else {
+            removeSearchHighlights();
+            removeSelection(currentTextPane);
+            findString(selection, backwards, !finder.getMatchCase(), true);
+        }
+    }
+
+    // --------------------------------------------------------------------    
+    /**
+     * Do a find with info in the info area.
+     */
+    boolean findString(String s, boolean backward,
+            boolean ignoreCase, boolean wrap)
+    {
+        if (s.length() == 0) {
+            info.message(" ");
+            return false;
+        }
+
+        boolean found;
+        if (backward){
+            found = doFindBackward(s, ignoreCase, wrap);
+        }
+        else {
+            setCaretPositionForward(1);
+            found = doFind(s, ignoreCase, wrap);
+        }
+
+        StringBuffer msg = new StringBuffer(Config.getString("editor.find.find.label") + " ");
+        msg.append(backward ? Config.getString("editor.find.backward") : Config.getString("editor.find.forward"));
+        if (ignoreCase || wrap) {
+            msg.append(" (");
+        }
+        if (ignoreCase) {
+            msg.append(Config.getString("editor.find.ignoreCase").toLowerCase() + ", ");
+        }
+        if (wrap) { 
+            msg.append(Config.getString("editor.find.wrapAround").toLowerCase() + ", ");
+        }
+        if (ignoreCase || wrap) { 
+            msg.replace(msg.length() - 2, msg.length(), "): ");
+        }
+        else { 
+            msg.append(": ");
+        }
+
+        msg.append(s);
+        if (found) {
+            info.message(msg.toString());
+        }
+        else {
+            info.warning(msg.toString(), Config.getString("editor.info.notFound"));
+        }
+
+        return found;
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Search for and select the given search string forwards from
+     * the current caret position. Returns false if not found.
+     */
+    boolean doFind(String s, boolean ignoreCase, boolean wrap)
+    {
+        int docLength = document.getLength();
+        int startPosition = currentTextPane.getCaretPosition();
+        int endPos = docLength;
+
+        boolean found = false;
+        boolean finished = false;
+
+        // first line searched starts from current caret position
+        int start = startPosition;
+        Element line = getLineAt(start);
+        int lineEnd = Math.min(line.getEndOffset(), endPos);
+
+        // following lines search from start of line
+        try {
+            while (!found && !finished) {
+                String lineText = document.getText(start, lineEnd - start);
+
+                if (lineText != null && lineText.length() > 0) {
+                    int foundPos = findSubstring(lineText, s, ignoreCase, false);
+                    if (foundPos != -1) {
+                        currentTextPane.select(start + foundPos, start + foundPos + s.length());
+                        currentTextPane.getCaret().setSelectionVisible(true);
+                        found = true;
+                    }
+                }
+                if (lineEnd >= endPos) {
+                    if (wrap) {
+                        // do the wrapping
+                        endPos = startPosition;
+                        line = document.getParagraphElement(0);
+                        start = line.getStartOffset();
+                        lineEnd = Math.min(line.getEndOffset(), endPos);
+                        wrap = false;
+                        // don't wrap again
+                    }
+                    else {
+                        finished = true;
+                    }
+                }
+                else {
+                    // go to next line
+                    line = document.getParagraphElement(lineEnd + 1);
+                    start = line.getStartOffset();
+                    lineEnd = Math.min(line.getEndOffset(), endPos);
+                }
+            }
+        }
+        catch (BadLocationException ex) {
+            Debug.reportError("Error in editor find operation", ex);
+        }
+        return found;
+    }
+
+    /**
+     * Do a find backwards without visible feedback. Returns
+     * false if not found.
+     */
+    boolean doFindBackward(String s, boolean ignoreCase, boolean wrap)
+    {
+        int docLength = document.getLength();
+        int startPosition = currentTextPane.getCaretPosition() - 1;
+        if (startPosition < 0) {
+            startPosition = docLength;
+        }
+        int endPos = 0;                   // where the search ends
+
+        boolean found = false;
+        boolean finished = false;
+
+        int start = startPosition;        // start of next partial search
+        Element line = getLineAt(start);
+        int lineStart = Math.max(line.getStartOffset(), endPos);
+
+        try {
+            while (!found && !finished) {
+                String lineText = document.getText(lineStart, start - lineStart);
+                if (lineText != null && lineText.length() > 0) {
+                    int foundPos = findSubstring(lineText, s, ignoreCase, true);
+                    if (foundPos != -1) {
+                        currentTextPane.select(lineStart + foundPos, lineStart + foundPos + s.length());
+                        currentTextPane.getCaret().setSelectionVisible(true);
+                        found = true;
+                    }
+                }
+                if (lineStart <= endPos) {            // reached end of search
+                    if (wrap) {                       // do the wrapping around
+                        endPos = startPosition;
+                        line = document.getParagraphElement(docLength);
+                        start = line.getEndOffset();
+                        lineStart = Math.max(line.getStartOffset(), endPos);
+                        wrap = false;                 // don't wrap again
+                    }
+                    else {
+                        finished = true;
+                    }
+                }
+                else {                                // go to next line
+                    line = document.getParagraphElement(lineStart - 1);
+                    start = line.getEndOffset();
+                    lineStart = Math.max(line.getStartOffset(), endPos);
+                }
+            }
+        }
+        catch (BadLocationException ex) {
+            Debug.reportError("Error in editor find operation", ex);
+        }
+        return found;
+    }
+
+    /**
+     * doFindSelect - finds all the instances in the document from where the 
+     * caret position is, optionally selects the first one and highlights all others
+     * @param select indicates whether the first occurrence should be selected or only highlighted
+     * @param s search string 
+     * 
+     * @return Returns false if not found.
+     */
+    int doFindSelect(String s, boolean ignoreCase, boolean wrap)
+    {
+        boolean select=true; //first item found should be selected so initialised to true
+        int docLength = document.getLength();
+        int startPosition = currentTextPane.getCaretPosition();
+        int endPos = docLength;
+        int highlightCount = 0;
+
+        boolean finished = false;
+
+        int start = startPosition;
+        Element line = document.getParagraphElement(start);
+        int lineEnd = line.getEndOffset();   
+        int foundPos =0; 
+        try {
+            while (!finished) {
+                String lineText = document.getText(start, lineEnd - start);
+                while (lineText != null && lineText.length() > 0) {
+                    foundPos = findSubstring(lineText, s, ignoreCase, false, foundPos);
+                    if (foundPos != -1) {
+                        addSearchHighlight(start + foundPos, start + foundPos + s.length());
+                        highlightCount++;
+                        if (select) {
+                            currentTextPane.select(start + foundPos, start + foundPos + s.length());
+                            setSelectionVisible();  
+                            //reset the start position to the first selection start
+                            //in order to ensure that none are missed
+                            startPosition=start+foundPos;
+                            select=false;
+                        }
+                        foundPos=foundPos+s.length();
+                    } else {
+                        lineText=null;
+                    }
+                }
+                if (lineEnd >= endPos) {
+                    if (wrap) {
+                        // do the wrapping
+                        endPos = Math.min(startPosition + s.length() - 1, document.getLength());
+                        line = document.getParagraphElement(0);
+                        start = line.getStartOffset();
+                        lineEnd = Math.min(line.getEndOffset(), endPos);
+                        wrap = false;
+                        // don't wrap again
+                    }
+                    else {
+                        finished = true;
+                    }
+                }
+                else {
+                    // go to next line
+                    line = document.getParagraphElement(lineEnd + 1);
+                    start = line.getStartOffset();
+                    lineEnd = Math.min(line.getEndOffset(), endPos);
+                }
+            }
+        }
+        catch (BadLocationException ex) {
+            Debug.reportError("Error in editor find operation", ex);
+        }
+        return highlightCount;
+    }
+    
+    /**
+     * Add a search highlight to the currently displayed pane.
+     */
+    private void addSearchHighlight(int startPos, int endPos)
+    {
+        try {
+            MoeHighlighter highlighter = (MoeHighlighter) currentTextPane.getHighlighter();
+            Object tag = highlighter.addHighlight(startPos, endPos, searchHighlightPainter);
+            if (currentTextPane == sourcePane) {
+                sourceSearchHighlightTags.add(tag);
+            }
+            else {
+                htmlSearchHighlightTags.add(tag);
+            }
+        }
+        catch (BadLocationException ble) {
+            Debug.reportError("Error adding search highlight", ble);
+        }
+    }
+
+    /**
+     * Transfers caret to user specified line number location.
+     */
+    public void goToLine()
+    {
+        if (goToLineDialog == null) {
+            goToLineDialog = new GoToLineDialog(this);
+        }
+
+        DialogManager.centreDialog(goToLineDialog);
+        goToLineDialog.showDialog(numberOfLines());
+        int newPosition = goToLineDialog.getLineNumber();
+        if (newPosition > 0) {
+            setSelection(newPosition, 1, 0);
+        }
+    }
+
+    /**
+     * Find the position of a substring in a given string, 
+     * can specify direction and whether the search should ignore case
+     * Return the position of the substring or -1.
+     *
+     * @param  text        the full string to be searched
+     * @param  sub         the substring that we're looking for
+     * @param  ignoreCase  if true, case is ignored
+     * @param  backwards   Description of the Parameter
+     * @return             Description of the Return Value
+     * @returns            the index of the substring, or -1 if not found
+     */
+    private int findSubstring(String text, String sub, 
+            boolean ignoreCase, boolean backwards)
+    {
+        int strlen = text.length();
+        int sublen = sub.length();
+
+        if (sublen == 0) {
+            return -1;
+        }
+
+        boolean found = false;
+        int pos = (backwards ? strlen - sublen : 0);
+        boolean itsOver = (backwards ? (pos < 0) : (pos + sublen > strlen));
+
+        while (!found && !itsOver) {
+            found = text.regionMatches(ignoreCase, pos, sub, 0, sublen);
+            if (found) {
+                return pos;
+            }
+            if (!found) {
+                pos = (backwards ? pos - 1 : pos + 1);
+                itsOver = (backwards ? (pos < 0) : (pos + sublen > strlen));
+            }
+        }       
+        return -1;
+    }
+
+    /**
+     * Find the position of a substring in a given string, 
+     * can specify direction and whether the search should ignoring case
+     * Return the position of the substring or -1.
+     *
+     * @param  text        the full string to be searched
+     * @param  sub         the substring that we're looking for
+     * @param  ignoreCase  if true, case is ignored
+     * @param  backwards   Description of the Parameter
+     * @param  foundPos   Offset for the string search
+     * @return             Description of the Return Value
+     * @returns            the index of the substring, or -1 if not found
+     */
+    private int findSubstring(String text, String sub, boolean ignoreCase, 
+            boolean backwards, int foundPos)
+    {
+        int strlen = text.length();
+        int sublen = sub.length();
+
+        if (sublen == 0) {
+            return -1;
+        }
+
+        boolean found = false;
+        int pos = foundPos;
+        boolean itsOver = (backwards ? (pos < 0) : (pos + sublen > strlen));
+        while (!found && !itsOver) {
+            found = text.regionMatches(ignoreCase, pos, sub, 0, sublen);                
+            if (found) {
+                return pos;
+            }
+            if (!found) {
+                pos = (backwards ? pos - 1 : pos + 1);
+                itsOver = (backwards ? (pos < 0) : (pos + sublen > strlen));
+            }
+        }      
+        return -1;
+    }
+    // --------------------------------------------------------------------
+    
+    /**
+     * Implementation of "compile" user function.
+     */
+    public void compile()
+    {
+        if (watcher == null) {
+            return;
+        }
+        if (!viewingCode()) {
+            info.warning(" ");
+            return;
+        }
+
+        info.message(Config.getString("editor.info.compiling"));
+        watcher.compile(this);
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * Toggle the interface popup menu. This is used when using keys to toggle
+     * the interface view. Toggling the menu will result in invoking the action.
+     */
+    public void toggleInterfaceMenu()
+    {
+        if (!sourceIsCode)
+            return;
+
+        if (interfaceToggle.getSelectedIndex() == 0)
+            interfaceToggle.setSelectedIndex(1);
+        else
+            interfaceToggle.setSelectedIndex(0);
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * Implementation of "toggle-interface-view" user function. The menu has
+     * already been changed - now see what it is and do it.
+     */
+    public void toggleInterface()
+    {
+        if (!sourceIsCode) {
+            return;
+        }
+
+        boolean wantHTML = (interfaceToggle.getSelectedItem() == interfaceString);
+        if (wantHTML && !viewingHTML) {
+            switchToInterfaceView();
+        }
+        else if (!wantHTML && viewingHTML) {
+            switchToSourceView();
+        }
+    }
+
+    /**
+     * Allow the enabling/disabling of print menu option. Added to disable the
+     * printing og javadoc html for the time being until until implemented.
+     * (This is reliant on the use of j2sdk1.4 and Java Unified Print Service
+     * implementation JSR 6)
+     * 
+     * @param flag  true to enable printing from menu.
+     */
+    public void enablePrinting(boolean flag)
+    {
+        Action printAction = actions.getActionByName("print");
+        if (printAction != null) {
+            printAction.setEnabled(flag);
+        }
+        Action pageSetupAction = actions.getActionByName("page-setup");
+        if (pageSetupAction != null) {
+            pageSetupAction.setEnabled(flag);
+        }
+
+    }   
+
+    /**
+     * Check if an item is in the reserved list for disabled interface options
+     *  
+     * @return boolean reflects if it is enabled ie false=disabled
+     * @param buttonText  String with button text name
+     */
+    private boolean isEditAction(String text)
+    {       
+        ArrayList<String> editActions = getEditActions();
+        if (editActions!=null && editActions.contains(text)) {
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * Check whether an action is not valid for the project "readme" (i.e. if it is only
+     * valid for source files).
+     * 
+     * @param actionName String representing the action name
+     * @return true if it is an action that should be disabled while editing the readme file,
+     *         or false otherwise
+     */
+    private boolean isNonReadmeAction(String actionName)
+    {
+        ArrayList<String> flaggedActions = getNonReadmeActions();
+        if (flaggedActions!=null && flaggedActions.contains(actionName)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Get a list of actions not applicable in the readme.txt file
+     */
+    private static ArrayList<String> getNonReadmeActions ()
+    {
+        if (readMeActions==null) {
+            readMeActions=new ArrayList<String>();
+            readMeActions.add("compile");
+            readMeActions.add("autoindent");
+            readMeActions.add("insert-method");
+            readMeActions.add("toggle-interface-view");
+        }
+        return readMeActions;
+    }
+    /**
+     * Returns a list of names for the actions which are only valid in an editing
+     * context, that is, when the display shows the source and not the documentation.
+     *  
+     * @return list of editing action names
+     */
+    private static ArrayList<String> getEditActions()
+    {
+        if (editActions == null) {
+            editActions=new ArrayList<String>();
+            editActions.add("save");
+            editActions.add("reload");
+            editActions.add("print");
+            editActions.add("page-setup");
+            editActions.add("compile");
+            editActions.add("cut-to-clipboard");
+            editActions.add("indent-block");
+            editActions.add("deindent-block");
+            editActions.add("comment-block");
+            editActions.add("uncomment-block");
+            editActions.add("insert-method");
+            editActions.add("replace");
+            editActions.add("go-to-line");
+            editActions.add("paste-from-clipboard");
+            editActions.add("toggle-breakpoint");
+            editActions.add("autoindent");
+        }
+
+        return editActions;
+    }
+    
+    /**
+     * Sets the search start to the beginning of the document/current pos in the
+     * sourcepane; removes all the selections and highlights; resets search string 
+     * and initiates a search (if the find panel is visible)
+     */
+    private void initSearch()
+    {
+        //current caret position may be invalid in the new view
+        //so reset it to the current pos in that pane/0 in the documentation
+        if (isShowingInterface()){
+            finder.setSearchStart(0);
+        }    
+        else{
+            finder.setSearchStart(getCurrentTextPane().getCaretPosition());
+        }
+        //reset the search string to null
+        finder.setSearchString(null);
+        //as the search is cleared between switches in the view
+        //there should be no selections/highlights from the previous search
+        removeSearchHighlights();
+        removeSelections();
+        //reset the search and replace strings
+        finder.setSearchString(null);
+        replacer.setReplaceString(null);
+        replacer.populateReplaceField(null);
+        if (finder.isVisible()){
+            initFindPanel();
+        }
+    }
+    
+    // --------------------------------------------------------------------
+    
+    /**
+     * Switch on the source view (if it isn't showing already).
+     */
+    private void switchToSourceView()
+    {
+        if (!viewingHTML) {
+            return;
+        }
+        resetMenuToolbar(true);
+        document = sourceDocument;
+        currentTextPane = sourcePane;
+        viewingHTML = false;
+        scrollPane.setViewportView(currentTextPane);
+        dividerPanel.endTemporaryHide();
+        currentTextPane.requestFocus();
+        initSearch();
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * Switch on the javadoc interface view (it it isn't showing already). If
+     * necessary, generate it first.
+     */
+    private void switchToInterfaceView()
+    {
+        if (viewingHTML) {
+            return;
+        }
+        resetMenuToolbar(false);
+        dividerPanel.beginTemporaryHide();
+        try {
+            save();
+            displayInterface();
+        }
+        catch (IOException ioe) {
+            // Could display a dialog here. However, the error message
+            // (from save() call) will already be displayed in the editor
+            // status bar.
+        }
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * Refresh the HTML display.
+     */
+    private void refreshHtmlDisplay()
+    {
+        FileInputStream fis = null;
+        try {
+            File urlFile = new File(getDocPath());
+            URL myURL = urlFile.toURI().toURL();
+            
+            HTMLEditorKit ekit = new HTMLEditorKit();
+            htmlDocument = (HTMLDocument) ekit.createDefaultDocument();
+            htmlDocument.setBase(myURL);
+            // Must ignore character set META tag, otherwise an exception will be thrown;
+            // HTMLEditorKit doesn't support changing character set:
+            htmlDocument.putProperty("IgnoreCharsetDirective", true);
+            htmlDocument.putProperty(Document.StreamDescriptionProperty, myURL);
+            
+            fis = new FileInputStream(urlFile);
+            Reader r = new InputStreamReader(fis, characterSet);
+            ekit.read(r, htmlDocument, 0);
+            
+            htmlPane.setDocument(htmlDocument);
+            
+            info.message(Config.getString("editor.info.docLoaded"));
+            if (isShowingInterface()){
+                document=htmlDocument;
+            }
+        }
+        catch (Exception exc) {
+            info.warning(Config.getString("editor.info.docDisappeared"), getDocPath());
+            Debug.reportError("loading class interface failed: " + exc);
+            if (fis != null) {
+                try {
+                    fis.close();
+                }
+                catch (Exception e) {}
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * Check whether javadoc file is up to date.
+     * 
+     * @return True is the currently existing documentation is up-to-date.
+     */
+    private boolean docUpToDate()
+    {
+        if (filename == null) {
+            return true;
+        }
+        try {
+            File src = new File(filename);
+            File doc = new File(docFilename);
+
+            if (!doc.exists() || (src.exists() && (src.lastModified() > doc.lastModified()))) {
+                return false;
+            }
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * This method resets the value of the menu and toolbar according to the view
+     * 
+     * @param sourceView true if called from source view setup; false from documentation view setup
+     */
+    private void resetMenuToolbar(boolean sourceView)
+    {
+        boolean canUndo=false;
+        boolean canRedo=false;
+        displayMenubar(sourceView);
+        displayToolbar(sourceView);
+        //if the view is source view need to decide whether to display 
+        //the undo and redo according to the undoManager; if it
+        //is the documentation view then they are always disabled
+        if (sourceView){
+            if (undoManager.canUndo())
+                canUndo=true;   
+            if (undoManager.canRedo())
+                canRedo=true;
+        }
+        displayMenuItem("undo", canUndo);
+        displayToolbarItem("undo", canUndo);
+        displayMenuItem("redo", canRedo);
+        displayToolbarItem("redo", canRedo);
+    }
+
+    /**
+     * This method changes the display of the menubar based on the
+     * view (source/documentation) that is selected.
+     * 
+     * @param sourceView true if viewing source; false if viewing documentation
+     */
+    private void displayMenubar(boolean sourceView)
+    {
+        JMenuBar menuBar=(JMenuBar) getJMenuBar(); 
+        JMenu menu=null;
+        Component[] menubarComponent = menuBar.getComponents();
+        for (int i=0;i<menubarComponent.length; i++ ){
+            if (menubarComponent[i] instanceof JMenu){
+                menu=(JMenu)menubarComponent[i]; 
+                for (int j=0; j<menu.getMenuComponentCount(); j++){
+                    if (menu.getMenuComponent(j) instanceof JMenuItem){
+                        if (isEditAction(((JMenuItem)menu.getMenuComponent(j)).getName())){                  
+                            ((JMenuItem)menu.getMenuComponent(j)).setEnabled(sourceView);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * This method changes the display of the toolbar based on the view
+     * (source/documentation) that is selected
+     * 
+     * @param sourceView true if viewing source; false if viewing documentation
+     */
+    private void displayToolbar(boolean sourceView)
+    {
+        JPanel toolbar=null;
+        Component contentPaneItem;
+        JButton actionButton;
+        Component[] c = getContentPane().getComponents();
+        for (int i=0;i<c.length; i++ ){
+            contentPaneItem=c[i];
+            if(contentPaneItem.getName()!=null && contentPaneItem.getName().equals("toolbar")) {
+                toolbar=(JPanel)contentPaneItem;
+            }
+        }
+
+        if (toolbar==null) {
+            return;
+        }
+        
+        Component[] toolbarComponent = toolbar.getComponents();
+        for (int i=0;i<toolbarComponent.length; i++ ) {
+            if (toolbarComponent[i] instanceof JButton) {                   
+                actionButton=(JButton)toolbarComponent[i];
+                if (isEditAction(actionButton.getName())) {
+                    actionButton.setEnabled(sourceView);
+                }
+            }
+        }
+    }
+
+    /**
+     * This method changes the display of the menubar based on the interface that is selected
+     * 
+     * @param sourceView true if called from sourceView setup; false from documentation View setup
+     */
+    private void displayMenuItem(String itemName, boolean sourceView)
+    {
+        JMenuBar menuBar=(JMenuBar) getJMenuBar(); 
+        JMenu menu=null;
+        JMenuItem menuItem;
+        Component[] menubarComponent = menuBar.getComponents();
+        for (int i=0;i<menubarComponent.length; i++ ){
+            if (menubarComponent[i] instanceof JMenu){
+                menu=(JMenu)menubarComponent[i]; 
+                for (int j=0; j<menu.getMenuComponentCount(); j++){
+                    if (menu.getMenuComponent(j) instanceof JMenuItem){
+                        menuItem=(JMenuItem)menu.getMenuComponent(j);
+                        if (menuItem.getName().equals(itemName)){                   
+                            menuItem.setEnabled(sourceView);
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * This method enables/disables the display of the toolbar item specified
+     * 
+     * @param sourceView true if called from sourceView setup; false from documentation View setup
+     */
+    private void displayToolbarItem(String itemName, boolean sourceView)
+    {
+        JPanel toolbar=null;
+        Component contentPaneItem;
+        Component[] c = getContentPane().getComponents();
+        for (int i=0;i<c.length; i++ ){
+            contentPaneItem=c[i];
+            if(contentPaneItem.getName()!=null && contentPaneItem.getName().equals("toolbar")) { 
+                toolbar=(JPanel)contentPaneItem;
+            }
+        }
+
+        if (toolbar==null) {
+            return;
+        }
+
+        Component[] toolbarComponent = toolbar.getComponents();
+        for (int i=0;i<toolbarComponent.length; i++ ){
+            if (toolbarComponent[i] instanceof JButton){                
+                JButton actionButton=(JButton)toolbarComponent[i];
+                if (actionButton.getName().equals(itemName)){
+                    actionButton.setEnabled(sourceView);
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * We want to display the interface view. This will generate the
+     * documentation if necessary.
+     * 
+     * Don't call this directly to switch to the interface view. Call
+     * switchToInterfaceView() instead.
+     */
+    private void displayInterface()
+    {
+        info.message(Config.getString("editor.info.loadingDoc"));
+        boolean generateDoc = ! docUpToDate();
+
+        // The following all used to be done in a separate thread, but this is not
+        // necessary - setPage() operates asynchronously anyway.
+        if (htmlPane == null) {
+            createHTMLPane();
+            if (! generateDoc) {
+                refreshHtmlDisplay();
+            }
+        }
+        else if (! generateDoc) {
+            info.message(Config.getString("editor.info.docLoaded"));
+        }
+
+        if (generateDoc) {
+            // clear the existing document
+            htmlDocument = new HTMLDocument();
+            htmlPane.setDocument(htmlDocument);
+
+            // interface needs to be re-generated
+            info.message(Config.getString("editor.info.generatingDoc"));
+            BlueJEvent.addListener(this);
+            if (watcher != null) {
+                watcher.generateDoc();
+            }
+        }
+
+        document = htmlDocument;
+        currentTextPane = htmlPane;
+        viewingHTML = true;
+        scrollPane.setViewportView(htmlPane);
+        currentTextPane.requestFocus();
+        initSearch();
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Create the HTML plane used to display javadoc.
+     */
+    private void createHTMLPane()
+    {
+        htmlPane = new JEditorPane();
+        htmlPane.setHighlighter(new MoeHighlighter());
+        htmlPane.setEditorKit(new HTMLEditorKit());
+        htmlPane.setEditable(false);
+        htmlPane.addHyperlinkListener(this);
+        htmlPane.setInputMap(JComponent.WHEN_FOCUSED, new InputMap() {
+            public Object get(KeyStroke keyStroke)
+            {
+                // Define no action for up/down, which allows the parent scroll
+                // pane to process the keys instead. This means the view will scroll,
+                // rather than just moving an invisible cursor.
+                Object action = super.get(keyStroke);
+                if ("caret-up".equals(action) || "caret-down".equals(action)) {
+                    return null;
+                }
+                return action;
+            }
+        });
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * A hyperlink was activated in the document. Do something appropriate.
+     */
+    public void hyperlinkUpdate(HyperlinkEvent e)
+    {
+        info.clear();
+        if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+            JEditorPane pane = (JEditorPane) e.getSource();
+            if (e instanceof HTMLFrameHyperlinkEvent) {
+                HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
+                HTMLDocument doc = (HTMLDocument) pane.getDocument();
+                doc.processHTMLFrameHyperlinkEvent(evt);
+            }
+            else {
+                try {
+                    pane.setPage(e.getURL());
+                }
+                catch (Throwable t) {
+                    info.warning("cannot display hyperlink: " + e.getURL());
+                    Debug.reportError("hyperlink failed: " + t);
+                }
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * Implementation of "toggle-breakpoint" user function.
+     */
+    public void toggleBreakpoint()
+    {
+        if (!viewingCode()) {
+            info.warning(" ");            // cause a beep
+            return;
+        }
+        toggleBreakpoint(sourcePane.getCaretPosition());
+    }
+
+    /**
+     * Toggle a breakpoint at a given position.
+     */
+    public void toggleBreakpoint(int pos)
+    {
+        if (positionHasBreakpoint(pos))
+            setUnsetBreakpoint(pos, false);        // remove
+        else
+            setUnsetBreakpoint(pos, true);         // set
+    }
+
+    /**
+     * Clear all known breakpoints.
+     */
+    private void clearAllBreakpoints()
+    {
+        if (mayHaveBreakpoints) {
+
+            for (int i = 1; i <= numberOfLines(); i++) {
+                if (lineHasBreakpoint(i)) {
+                    doRemoveBreakpoint(getPositionInLine(i));
+                }
+            }
+            mayHaveBreakpoints = false;
+        }
+    }
+
+    /**
+     * Check whether a position in the current document has a breakpoint set
+     * (should only be called after a check that the current document is the source doc)
+     */
+    private boolean positionHasBreakpoint(int pos)
+    {
+        Element line = getSourceLine(getLineNumberAt(pos));
+        return Boolean.TRUE.equals(line.getAttributes().getAttribute(MoeSyntaxView.BREAKPOINT));
+    }
+    
+    /**
+     * Check whether a line in the source document has a breakpoint set
+     */
+    private boolean lineHasBreakpoint(int lineNo)
+    {
+        Element line = getSourceLine(lineNo);
+        return (Boolean.TRUE.equals(line.getAttributes().getAttribute(MoeSyntaxView.BREAKPOINT)));
+    }
+
+    /**
+     * Try to set or remove a breakpoint (depending on the parameter) at the
+     * given position in the source document. Informs the watcher.
+     */
+    private void setUnsetBreakpoint(int pos, boolean set)
+    {
+        if (watcher != null) {
+            int line = getLineNumberAt(pos);
+            String result = watcher.breakpointToggleEvent(this, line, set);
+
+            if (result == null) {
+                // no problem, go ahead
+                SimpleAttributeSet a = new SimpleAttributeSet();
+                if (set) {
+                    a.addAttribute(MoeSyntaxView.BREAKPOINT, Boolean.TRUE);
+                    mayHaveBreakpoints = true;
+                }
+                else {
+                    a.addAttribute(MoeSyntaxView.BREAKPOINT, Boolean.FALSE);
+                }
+
+                sourceDocument.setParagraphAttributes(pos, a);
+            }
+            else {
+                info.warning(result);
+            }
+
+            // force an update of UI
+            repaint();
+        }
+        else {
+            info.warning(Config.getString("editor.info.cannotSetBreak"));
+        }
+
+    }
+
+    /**
+     * Remove a breakpoint without question.
+     */
+    private void doRemoveBreakpoint(int pos)
+    {
+        SimpleAttributeSet a = new SimpleAttributeSet();
+        a.addAttribute(MoeSyntaxView.BREAKPOINT, Boolean.FALSE);
+        sourceDocument.setParagraphAttributes(pos, a);
+        repaint();
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Try to set or remove a step mark (depending on the parameter) at the
+     * given position.
+     * 
+     * @param pos  A position in the line where we'd like the step mark.
+     */
+    private void setStepMark(int pos)
+    {
+        removeStepMark();
+        SimpleAttributeSet a = new SimpleAttributeSet();
+        a.addAttribute(MoeSyntaxView.STEPMARK, Boolean.TRUE);
+        sourceDocument.setParagraphAttributes(pos, a);
+        currentStepPos = pos;
+        // force an update of UI
+        repaint();
+    }
+
+    // ========================= SUPPORT ROUTINES ==========================
+
+    // --------------------------------------------------------------------
+    /**
+     * Return a boolean representing whether in source editing view
+     */
+    private boolean viewingCode()
+    {
+        return sourceIsCode && (!viewingHTML);
+    }
+
+    // --------------------------------------------------------------------
+    /**
+     * Find and return a line (by line number) in the source document
+     */
+    private Element getSourceLine(int lineNo)
+    {
+        return sourceDocument.getDefaultRootElement().getElement(lineNo - 1);
+    }
+
+    // --------------------------------------------------------------------
+    /**
+     * Find and return a line by text position in the current document
+     */
+    private Element getLineAt(int pos)
+    {
+        return document.getParagraphElement(pos);
+    }
+
+    // --------------------------------------------------------------------
+    /**
+     * Find and return a position in the source document.
+     */
+    private int getPositionInLine(int lineNo)
+    {
+        return getSourceLine(lineNo).getStartOffset();
+    }
+
+    // --------------------------------------------------------------------
+    /**
+     * Return the number of the line containing position 'pos' in the source document.
+     */
+    private int getLineNumberAt(int pos)
+    {
+        return sourceDocument.getDefaultRootElement().getElementIndex(pos) + 1;
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * Revert the buffer contents to the last saved version. Do not ask any
+     * question - just do it. Must have a file name.
+     */
+    public void doReload()
+    {
+        removeSearchHighlights();
+        Reader reader = null;
+        boolean isShowingSrc = sourceDocument == document;
+        
+        try {
+            FileInputStream inputStream = new FileInputStream(filename);
+            reader = new InputStreamReader(inputStream, characterSet);
+            sourcePane.read(reader, null);
+            try {
+                reader.close();
+                inputStream.close();
+            }
+            catch (IOException ioe) {}
+            File file = new File(filename);
+            lastModified = file.lastModified();
+            
+            recordLoadContent();
+
+            sourceDocument = (MoeSyntaxDocument) sourcePane.getDocument();
+            sourceDocument.enableParser(false);
+            naviView.setDocument(sourceDocument);
+
+            // flag document type as a java file by associating a
+            // JavaTokenMarker for syntax colouring if specified
+            sourceDocument.addDocumentListener(this);
+            sourceDocument.addUndoableEditListener(undoManager);
+
+            // We want to inform the watcher that the editor content has changed,
+            // and then inform it that we are in "saved" state (synced with file).
+            // But first set state to saved to avoid unnecessary writes to disk.
+            saveState.setState(StatusLabel.SAVED);
+            setChanged(); // contents may have changed - notify watcher
+            setSaved();  // notify watcher that we are saved
+            
+            scheduleReparseRunner();
+        }
+        catch (FileNotFoundException ex) {
+            info.warning(Config.getString("editor.info.fileDisappeared"));
+        }
+        catch (IOException ex) {
+            info.warning(Config.getString("editor.info.fileReadError"));
+            setChanged();
+        }
+        finally {
+            try {
+                if (reader != null) {
+                    reader.close();
+                }
+            }
+            catch (IOException ioe) {}
+            
+            if (isShowingSrc) {
+                document = sourceDocument;
+            }
+            
+            if (finder != null && finder.isVisible()) {
+               finder.find(true);
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Checks that current status of syntax highlighting option is consistent
+     * with desired option eg off/on. Called when refreshing or making visible
+     * to pick up any Preference Manager changes to this functionality
+     */
+    private void checkBracketStatus()
+    {
+        matchBrackets = PrefMgr.getFlag(PrefMgr.MATCH_BRACKETS);
+        // tidies up leftover highlight if matching is switched off
+        // while highlighting a valid bracket or refreshes bracket in open
+        // editor
+        if (matchBrackets) {
+            doBracketMatch();
+        }
+        else {
+            moeCaret.removeBracket();
+        }
+    }
+
+    /**
+     * Tell whether we are currently matching brackets.
+     * 
+     * @return True, if we are matching brackets, otherwise false.
+     */
+    public boolean matchBrackets()
+    {
+        return matchBrackets;
+    }
+    
+    /**
+     * Set the caret inactive or active. When "inactive" the standard Moe caret is replaced
+     * with a dummy caret which does not paint or do anything which the default caret does.
+     * This makes it much, much faster to move around (any text insert or remove operation
+     * moves the caret, so these become faster as well).
+     * 
+     * <p>Calls to setCaretActive(false) should always be paired with calls to
+     * setCaretActive(true).
+     * 
+     * @param active  True, if the Moe caret should be active; false to replace it temporarily
+     *                with a fast dummy caret.
+     */
+    public void setCaretActive(boolean active)
+    {
+        if (! active) {
+            //moeCaret.deinstall(currentTextPane);
+            currentTextPane.setCaret(new NullCaret(moeCaret.getMark(), moeCaret.getDot()));
+        }
+        else {
+            //moeCaret.install(currentTextPane);
+            Caret caret = currentTextPane.getCaret();
+            currentTextPane.setCaret(moeCaret);
+            moeCaret.setDot(caret.getMark());
+            moeCaret.moveDot(caret.getDot());
+        }
+    }
+
+    // --------------------------------------------------------------------
+    /**
+     * Toggle the editor's 'compiled' status. If compiled, enable the breakpoint
+     * function.
+     */
+    private void setCompileStatus(boolean compiled)
+    {
+        actions.getActionByName("toggle-breakpoint").setEnabled(compiled && viewingCode());
+        if (compiled) {
+            sourceDocument.putProperty(COMPILED, Boolean.TRUE);
+        }
+        else {
+            sourceDocument.putProperty(COMPILED, Boolean.FALSE);
+        }
+
+        currentTextPane.repaint();
+    }
+
+    // --------------------------------------------------------------------
+    /**
+     * Set the saved/changed status of this buffer to SAVED.
+     */
+    private void setSaved()
+    {
+        info.message(Config.getString("editor.info.saved"));
+        saveState.setState(StatusLabel.SAVED);
+        if (watcher != null) {
+            watcher.saveEvent(this);
+        }
+    }
+
+    // --------------------------------------------------------------------
+    /**
+     * Buffer just went from saved to changed state (called by StatusLabel)
+     */
+    private void setChanged()
+    {
+        if (ignoreChanges) {
+            return;
+        }
+        setCompileStatus(false);
+        if (watcher != null) {
+            watcher.modificationEvent(this);
+        }
+    }
+
+    /**
+     * Notification (from the caret) that the caret position has moved.
+     */
+    public void caretMoved()
+    {
+        int caretPos = sourcePane.getCaretPosition();
+        String errCode = errorManager.getErrorAtPosition(caretPos);
+        if (errCode != null) {
+            info.message(ParserMessageHandler.getMessageForCode(errCode));
+        }
+        else {
+            clearMessage();
+        }
+        
+        // the selection may have changed and therefore need to determine
+        // whether it is logical to have the buttons enabled/disabled
+        enableReplaceButtons();
+        if (matchBrackets) {
+            doBracketMatch();
+        }
+        actions.userAction();
+    }
+
+    /**
+     * Returns the position of the matching bracket for the source pane's
+     * current caret position. Returns -1 if not found or not valid/appropriate
+     * 
+     * @return the int representing bracket position
+     */
+    public int getBracketMatch()
+    {
+        int pos = -1;
+        try {
+            int caretPos = sourcePane.getCaretPosition();
+            if (caretPos != 0) {
+                caretPos--;
+            }
+            pos = TextUtilities.findMatchingBracket(sourceDocument, caretPos);
+        }
+        catch (BadLocationException ble) {
+            Debug.reportError("Bad document location reached while trying to match brackets");
+        }
+        return pos;
+    }
+
+    /**
+     * delegates bracket matching to the source pane's caret
+     */
+    private void doBracketMatch()
+    {
+        moeCaret.paintMatchingBracket();
+    }
+
+    /**
+     * Set the window title to show the defined title, or else the file name.
+     */
+    private void setWindowTitle()
+    {
+        String title = windowTitle;
+
+        if (title == null) {
+            if (filename == null)
+                title = "Moe:  <no name>";
+            else
+                title = "Moe:  " + filename;
+        }
+        setTitle(title);
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Return the path to the class documentation.
+     */
+    private String getDocPath()
+    {
+        return docFilename;
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Gets the resource attribute of the MoeEditor object
+     */
+    private String getResource(String name)
+    {
+        return Config.getPropString(name, null, resources);
+    }
+
+
+
+    // ======================= WINDOW INITIALISATION =======================
+
+    /**
+     * Create all the Window components.
+     * 
+     * @param projectResolver  the entity resolver for the project. If this is null
+     *   then it is assumed that this editor is for a README or other plain text file.
+     */
+    private void initWindow(EntityResolver projectResolver)
+    {
+        Image icon = BlueJTheme.getIconImage();
+        if (icon != null) {
+            setIconImage(icon);
+        }
+
+        // prepare the content pane
+
+        JPanel contentPane = new GradientFillPanel(new BorderLayout(6,6));
+        contentPane.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
+        setContentPane(contentPane);
+
+        // create and add info and status areas
+
+        JPanel bottomArea = new JPanel();
+
+        // create panel for info/status
+        bottomArea.setLayout(new BorderLayout(6, 1));
+        bottomArea.setOpaque(false);
+        
+        JPanel finderPanel = new JPanel(new DBoxLayout(DBox.Y_AXIS, 0, 0));
+        finderPanel.setBorder(BorderFactory.createEmptyBorder(0, BlueJTheme.componentSpacingLarge, 0, 0));
+        finderPanel.setOpaque(false);
+        
+        int smallSpc = BlueJTheme.componentSpacingSmall;
+        
+        //area for new find functionality
+        finder=new FindPanel(this);
+        finder.setVisible(false);
+        finder.setBorder(BorderFactory.createEmptyBorder(0, 0, smallSpc, 0));
+        finder.setName("FinderPanel");
+        finder.setAlignmentX(0.0f);
+        finder.setOpaque(false);
+        finderPanel.add(finder);
+
+        replacer=new ReplacePanel(this, finder);
+        replacer.setVisible(false);
+        replacer.setBorder(BorderFactory.createEmptyBorder(0, 0, smallSpc, 0));
+        replacer.setAlignmentX(0.0f);
+        replacer.setOpaque(false);
+        finderPanel.add(replacer);
+        
+        bottomArea.add(finderPanel, BorderLayout.NORTH);
+
+        statusArea = new JPanel();
+        statusArea.setLayout(new GridLayout(0, 1));
+        // one column, many rows
+        statusArea.setBackground(infoColor);
+        statusArea.setBorder(BorderFactory.createLineBorder(Color.black));
+
+        saveState = new StatusLabel(StatusLabel.SAVED);
+        statusArea.add(saveState);
+        //bottomArea.add(statusArea, BorderLayout.EAST);
+
+        info = new Info();
+        JPanel commentsPanel=new JPanel(new BorderLayout(6,1));
+        commentsPanel.setOpaque(false);
+        commentsPanel.add(info, BorderLayout.CENTER);
+        commentsPanel.add(statusArea, BorderLayout.EAST);
+
+        bottomArea.add(commentsPanel, BorderLayout.SOUTH);
+
+        contentPane.add(bottomArea, BorderLayout.SOUTH);
+
+        // create the text document
+
+        if (projectResolver != null) {
+            sourceDocument = new MoeSyntaxDocument(projectResolver, errorManager);
+        }
+        else {
+            sourceDocument = new MoeSyntaxDocument();  // README file
+        }
+        sourceDocument.addDocumentListener(this);
+        sourceDocument.addUndoableEditListener(undoManager);               
+
+        // create the text pane
+
+        EditorKit kit;
+        if (projectResolver != null) {
+            kit = new MoeSyntaxEditorKit(projectResolver, errorManager);
+        }
+        else {
+            kit = new ReadmeEditorKit();
+        }
+        //MoeSyntaxEditorKit kit = new MoeSyntaxEditorKit(false, projectResolver);
+        sourcePane = new MoeEditorPane();
+        sourcePane.setDocument(sourceDocument);
+        sourcePane.setCaretPosition(0);
+        sourcePane.setMargin(new Insets(2, 0, 2, 0));
+        sourcePane.setOpaque(true);
+        sourcePane.setEditorKit(kit);
+        moeCaret = new MoeCaret(this);
+        sourcePane.setCaret(moeCaret);
+        sourcePane.setBackground(MoeSyntaxDocument.getBackgroundColor());
+        sourcePane.setSelectionColor(selectionColour);
+        sourcePane.setCaretColor(cursorColor);
+
+        // default showing:
+        currentTextPane = sourcePane;
+
+        JPanel editorPane = new JPanel();
+        editorPane.setLayout(new BoxLayout(editorPane, BoxLayout.X_AXIS));
+        editorPane.setOpaque(false);
+        scrollPane = new JScrollPane(currentTextPane);
+        scrollPane.getVerticalScrollBar().setUnitIncrement(16);
+        
+        naviView = new NaviView(sourceDocument, scrollPane.getVerticalScrollBar());
+        naviView.setPreferredSize(new Dimension(NAVIVIEW_WIDTH, 0));
+        naviView.setMaximumSize(new Dimension(NAVIVIEW_WIDTH, Integer.MAX_VALUE));
+        naviView.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+        
+        dividerPanel=new EditorDividerPanel(naviView, getNaviviewExpandedProperty());
+        dividerPanel.setOpaque(false);
+      
+        editorPane.add(scrollPane);
+        editorPane.add(dividerPanel);
+        editorPane.add(naviView);
+
+        contentPane.add(editorPane, BorderLayout.CENTER);
+
+        // get table of edit actions
+
+        actions = MoeActions.getActions(sourcePane);
+        actions.setUndoEnabled(false);
+        actions.setRedoEnabled(false);
+
+        // create menubar and menus
+
+        JMenuBar menubar = createMenuBar();
+        menubar.setName("menubar");
+        setJMenuBar(menubar);
+
+        // create toolbar
+
+        toolbar = createToolbar();
+        toolbar.setName("toolbar");
+        toolbar.setOpaque(false);
+        contentPane.add(toolbar, BorderLayout.NORTH);
+        
+        //add popup menu
+        
+        popup= createPopupMenu();
+
+        // add event listener to handle the window close requests
+
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) {
+                close();
+            }
+            public void windowActivated(WindowEvent e) {
+                checkForChangeOnDisk();
+            }
+        });
+
+        setFocusTraversalPolicy(new MoeFocusTraversalPolicy());
+
+        setWindowTitle();
+        pack();
+        
+        // Set the size, respecting the current environment maximums.
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        Rectangle maxBounds = ge.getMaximumWindowBounds();
+        int myWidth = Math.min(900, (int) maxBounds.getWidth());
+        int myHeight = Math.min(700, (int) maxBounds.getHeight());
+        setSize(myWidth, myHeight);
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Create the editor's menu bar.
+     */
+    private JMenuBar createMenuBar()
+    {
+        JMenuBar menubar = new JMenuBar();
+        JMenu menu = null;
+
+        String[] menuKeys = getResource("menubar").split(" ");
+        for (int i = 0; i < menuKeys.length; i++) {
+            menu = createMenu(menuKeys[i]);
+            if (menu != null) {
+                menubar.add(menu);
+            }
+        }
+        return menubar;
+    }
+
+    // --------------------------------------------------------------------
+    
+    /**
+     * Create the pop up menu bar
+     */
+    private JPopupMenu createPopupMenu()
+    {
+        JMenuItem menuItem;
+        Action action;
+        String label;
+        String actionName;
+        popup = new JPopupMenu();
+        String [] popupKeys=getResource("popupmenu").split(" ");
+        for (int i=0; i< popupKeys.length; i++){
+            label = Config.getString("editor." + popupKeys[i] + LabelSuffix);
+            actionName = getResource(popupKeys[i] + ActionSuffix);
+            action = actions.getActionByName(actionName);
+            if (action == null) {               
+                Debug.message("Moe: cannot find action " + popupKeys[i]);
+            }
+            else {
+                menuItem=new JMenuItem(action);
+                menuItem.setText(label);
+                popup.add(menuItem);
+            }
+        }      
+        return popup;
+
+    }
+    
+    // --------------------------------------------------------------------
+
+    /**
+     * Create a single menu for the editor's menu bar. The key for the menu (as
+     * defined in moe.properties) is supplied.
+     */
+    private JMenu createMenu(String key)
+    {
+        JMenuItem item;
+        String label;
+
+        // get menu title
+        JMenu menu = new JMenu(Config.getString("editor." + key + LabelSuffix));
+        int mnemonic = Config.getMnemonicKey("editor." + key + LabelSuffix);
+        menu.setMnemonic(mnemonic);
+
+        // get menu definition
+        String itemString = getResource(key);
+        if (itemString == null) {
+            Debug.message("Moe: cannot find menu definition for " + key);
+            return null;
+        }
+
+        // cut menu definition into separate items
+        String[] itemKeys = itemString.split(" ");
+
+        // create menu item for each item
+        for (int i = 0; i < itemKeys.length; i++) {
+            if (itemKeys[i].equals("-")) {
+                menu.addSeparator();
+            }
+            else {
+                Action action = actions.getActionByName(itemKeys[i]);
+                if (action == null) {
+                    Debug.message("Moe: cannot find action " + itemKeys[i]);
+                }
+                else {
+                    item = menu.add(action);
+                    label = Config.getString("editor." + itemKeys[i] + LabelSuffix);
+                    if (label != null) {
+                        item.setText(label);
+                    }
+                    KeyStroke[] keys = actions.getKeyStrokesForAction(action);
+                    if (keys != null) {
+                        item.setAccelerator(chooseKey(keys));
+                    }
+                    item.setName(itemKeys[i]); 
+                    if (isNonReadmeAction(itemKeys[i])){
+                        item.setEnabled(sourceIsCode);
+                    }
+                }               
+            }
+        }
+        return menu;
+    }
+
+    /**
+     * Choose a key to use in the menu from all defined keys.
+     */
+    private KeyStroke chooseKey(KeyStroke[] keys)
+    {
+        if (keys.length == 1) {
+            return keys[0];
+        }
+        else {
+            KeyStroke key = keys[0];
+            // give preference to shortcuts using letter keys (CTRL-V, rather
+            // than F2)
+            for (int i = 1; i < keys.length; i++) {
+                if (keys[i].getKeyCode() >= 'A' && keys[i].getKeyCode() <= 'Z') {
+                    key = keys[i];
+                }
+            }
+            return key;
+        }
+    }
+
+
+    /**
+     * Create the toolbar.
+     * 
+     * @return The toolbar component, ready made.
+     */
+    private JComponent createToolbar()
+    {
+        JPanel toolbar = new JPanel();
+        toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.X_AXIS));
+
+        String[] toolGroups = getResource("toolbar").split(" ");
+        for (String group : toolGroups) {
+            addToolbarGroup(toolbar, group);
+        }
+
+        toolbar.add(Box.createHorizontalGlue());
+        toolbar.add(Box.createHorizontalGlue());
+        toolbar.add(createInterfaceSelector());
+
+        return toolbar;
+    }
+
+
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Create the toolbar.
+     * 
+     * @return The toolbar component, ready made.
+     */
+    private void addToolbarGroup(JComponent toolbar, String group)
+    {
+        String[] toolKeys = group.split(":");
+        for (int i = 0; i < toolKeys.length; i++) {
+            toolbar.add(createToolbarButton(toolKeys[i]));
+            if(!Config.isMacOSLeopard()) toolbar.add(Box.createHorizontalStrut(3));
+        }
+    }
+
+
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Create a button on the toolbar.
+     * 
+     * @param key  The internal key identifyting the action and label
+     * @param position  The position in the button group. One of "first", 
+     *                  "middle", "last", "only". Only used on MacOS.
+     */
+    private AbstractButton createToolbarButton(String key)
+    {
+        final String label = Config.getString("editor." + key + LabelSuffix);
+        AbstractButton button;
+
+        String actionName = getResource(key + ActionSuffix);
+        if (actionName == null) {
+            actionName = key;
+        }
+        Action action = actions.getActionByName(actionName);
+        Action tbAction = new ToolbarAction(action, label);
+
+
+        button = new JButton(tbAction);
+        button.setName(actionName);
+
+        if (action == null) {
+            button.setEnabled(false);
+            Debug.message("Moe: action not found for button " + label);
+        }
+        
+        if (isNonReadmeAction(actionName) && !sourceIsCode){
+            button.setEnabled(false);
+        }
+
+        button.setRequestFocusEnabled(false);
+        // never get keyboard focus
+
+        if (!Config.isMacOS()) {
+            // on all other platforms than MacOS, the default insets needs to
+            // be changed to make the buttons smaller
+            Insets margin = button.getMargin();
+            button.setMargin(new Insets(margin.top, 3, margin.bottom, 3));
+        }
+        else {
+            Utility.changeToMacButton(button);
+        }
+        button.setFont(PrefMgr.getStandardFont());
+        return button;
+    }
+
+
+
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Create a combo box for the toolbar
+     */
+    private JComboBox createInterfaceSelector()
+    {
+        String[] choiceStrings = {implementationString, interfaceString};
+        interfaceToggle = new JComboBox(choiceStrings);
+
+        interfaceToggle.setRequestFocusEnabled(false);
+        interfaceToggle.setFont(PrefMgr.getStandardFont());
+        interfaceToggle.setBorder(new EmptyBorder(2, 2, 2, 2));
+        interfaceToggle.setForeground(envOpColour);
+        interfaceToggle.setOpaque(false);
+
+        String actionName = "toggle-interface-view";
+        Action action = actions.getActionByName(actionName);
+        if (action != null) {           // should never be null...
+            interfaceToggle.setAction(action);
+        }
+        else {
+            interfaceToggle.setEnabled(false);
+            Debug.message("Moe: action not found: " + actionName);
+        }
+        if (!sourceIsCode) {
+            interfaceToggle.setEnabled(false);
+        }
+        return interfaceToggle;
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Inner class for printing thread to allow printing to occur as a
+     * background operation.
+     * 
+     * @author Bruce Quig
+     */
+    class PrintHandler
+    implements Runnable
+    {
+        PrinterJob printJob;
+        PageFormat pageFormat;
+        boolean lineNumbers;
+        boolean syntaxHighlighting;
+
+        /**
+         * Construct the PrintHandler.
+         */
+        public PrintHandler(PrinterJob pj, PageFormat format, boolean lineNumbers, boolean syntaxHighlighting)
+        {
+            super();
+            printJob = pj;
+            pageFormat = format;
+            this.lineNumbers = lineNumbers;
+            this.syntaxHighlighting = syntaxHighlighting;
+        }
+
+        /**
+         * Implementation of Runnable interface
+         */
+        public void run()
+        {
+            print();
+        }
+
+        /**
+         * Create MoePrinter and then invoke print method
+         */
+        public void print()
+        {
+            if (printer == null) {
+                printer = new MoePrinter();
+            }
+
+            // print document, using new pageformat object at present
+            info.message(Config.getString("editor.info.printing"));
+            if (printer.printDocument(printJob, sourceDocument, lineNumbers, syntaxHighlighting, windowTitle, printFont, pageFormat)) {
+                info.message(Config.getString("editor.info.printed"));
+            }
+            else {
+                info.message(Config.getString("editor.info.cancelled"));
+            }
+
+        }
+
+    }
+
+    // --------------------------------------------------------------------
+
+    /**
+     * Class for thread listening to edit changes.
+     */
+    class TextInsertNotifier
+    implements Runnable
+    {
+        private DocumentEvent evt;
+        private JEditorPane editorPane;
+
+        /**
+         * Sets the event attribute of the TextInsertNotifier object
+         */
+        public void setEvent(DocumentEvent e, JEditorPane editorPane)
+        {
+            evt = e;
+            this.editorPane = editorPane;
+        }
+
+        /**
+         * Main processing method for the TextInsertNotifier object
+         */
+        public void run()
+        {
+            actions.textInsertAction(evt, editorPane);
+        }
+    }
+
+    /**
+     * Custom focus traversal implementation to make sure that the text area
+     * gets and never loses focus.
+     */
+    class MoeFocusTraversalPolicy extends FocusTraversalPolicy
+    {
+        public Component getComponentAfter(Container focusCycleRoot,  Component aComponent) {
+            if (aComponent.equals(finder.getFindTField())) {
+                if (replacer.isVisible()){
+                    return replacer.getReplaceText();
+                }
+            } 
+            return currentTextPane;
+        }
+
+        public Component getComponentBefore(Container focusCycleRoot,  Component aComponent) {
+            if (aComponent.equals(replacer.getReplaceText())) {
+                return finder.getFindTField();
+            } 
+            return currentTextPane;
+        }
+
+        public Component getDefaultComponent(Container focusCycleRoot) {
+            return currentTextPane;
+        }
+
+        public Component getFirstComponent(Container focusCycleRoot) {
+            return currentTextPane;
+        }
+
+        public Component getInitialComponent(Window window) {
+            return currentTextPane;
+        }
+
+        public Component getLastComponent(Container focusCycleRoot) {
+            return currentTextPane;
+        }
+    }
+
+    /**
+     * An abstract action which delegates to a sub-action, and which
+     * mirrors the "enabled" state of the sub-action. This allows having
+     * actions with alternative labels.
+     * 
+     * @author Davin McCall
+     */
+    class ToolbarAction extends AbstractAction implements PropertyChangeListener
+    {
+        private Action subAction;
+
+        public ToolbarAction(Action subAction, String label)
+        {
+            super(label);
+            this.subAction = subAction;
+            subAction.addPropertyChangeListener(this);
+            setEnabled(subAction.isEnabled());
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            subAction.actionPerformed(e);
+        }
+
+        public void propertyChange(PropertyChangeEvent evt)
+        {
+            // If the enabled state of the sub-action changed,
+            // then we should change our own state.
+            if (evt.getPropertyName().equals("enabled")) {
+                Object newVal = evt.getNewValue();
+                if (newVal instanceof Boolean) {
+                    boolean state = ((Boolean) newVal).booleanValue();
+                    setEnabled(state);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets the find panel to be visible and if there is a selection/or previous search 
+     * it starts a automatic find of what was selected in the text/or previous search. If 
+     * it is the source pane then the replace button is enabled; if it is the interface pane 
+     * then the replace button and replace panel are set to disabled and invisible
+     */
+    public void initFindPanel()
+    {
+        finder.displayFindPanel(currentTextPane.getSelectedText());
+        //functionality for the replace button to be enabled/disabled according to view
+        if (isShowingInterface())
+        {
+            finder.setReplaceEnabled(false);
+            replacer.setVisible(false);
+        }
+        else
+        {
+            finder.setReplaceEnabled(true);
+        }
+    }
+
+    /**
+     * Sets the caret forward by the value indicated if this does not 
+     * exceed the document length; Else it sets it to the document length
+     */
+    public void setCaretPositionForward (int caretPos)
+    {
+        int docLength = document.getLength();
+        if (currentTextPane.getCaretPosition() + caretPos <= docLength) {
+            currentTextPane.setCaretPosition(currentTextPane.getCaretPosition() + caretPos);
+        } else { 
+            currentTextPane.setCaretPosition(docLength);
+        }
+    }
+
+    /**
+     * Get the source pane.
+     */
+    public JEditorPane getSourcePane()
+    {
+        return sourcePane;
+    }
+    
+    /**
+     * Get the current pane.
+     */
+    public JEditorPane getCurrentTextPane()
+    {
+        return currentTextPane;
+    }    
+    
+    /**
+     * Get the source document that this editor is editing.
+     */
+    public MoeSyntaxDocument getSourceDocument()
+    {
+        return sourceDocument;
+    }
+    
+    /**
+     * Removes the selected highlights (in both the source/doc pane) 
+     * Note: the other highlights such as the brackets etc remain
+     */
+    public void removeSearchHighlights()
+    {
+        for (Object tag : sourceSearchHighlightTags) {
+            sourcePane.getHighlighter().removeHighlight(tag);
+        }
+        sourceSearchHighlightTags.clear();
+        
+        for (Object tag : htmlSearchHighlightTags) {
+            htmlPane.getHighlighter().removeHighlight(tag);
+        }
+        htmlSearchHighlightTags.clear();
+    }
+    
+    /**
+     * Removes the selection in the textpane specified
+     * @param textPane specified textpane (source/html)
+     */
+    private void removeSelection(JEditorPane textPane)
+    {
+        if (textPane!=null){
+            textPane.setSelectionEnd(textPane.getSelectionStart());
+        }
+    }
+    
+    /**
+     * Removes the selections 
+     */
+    public void removeSelections()
+    {
+        removeSelection(sourcePane);
+        removeSelection(htmlPane);
+    }
+
+    /**
+     * Create and pop up the content assist (code completion) dialog.
+     */
+    protected void createContentAssist()
+    {
+        //need to recreate the dialog each time it is pressed as the values may be different 
+        CodeSuggestions suggests = sourceDocument.getParser().getExpressionType(sourcePane.getCaretPosition(),
+                sourceDocument);
+        if (suggests != null) {
+            LocatableToken suggestToken = suggests.getSuggestionToken();
+            AssistContent[] values = ParseUtils.getPossibleCompletions(suggests, "", javadocResolver);
+            if (values != null && values.length > 0) {
+                CodeCompletionDisplay codeCompletionDlg = new CodeCompletionDisplay(this, 
+                        suggests.getSuggestionType().toString(false), 
+                        values, suggestToken);
+                int cpos = sourcePane.getCaretPosition();
+                try {
+                    Rectangle pos = sourcePane.modelToView(cpos);
+                    Point spLoc = sourcePane.getLocationOnScreen();
+                    int xpos = pos.x + spLoc.x;
+                    int ypos = pos.y + pos.height + spLoc.y;
+                    codeCompletionDlg.setLocation(xpos, ypos);
+                    codeCompletionDlg.setVisible(true);
+                    codeCompletionDlg.requestFocus();
+                    return;
+                }
+                catch (BadLocationException ble) {}
+            }
+        }
+        info.warning("No completions available.");
+    }
+
+    /**
+     * Does some clever formatting to ensure that the replacement matches
+     * the original on the formatting eg upper/lower case
+     */
+    private String smartFormat(String original, String replacement)
+    {
+        if(original == null || replacement == null) {
+            return replacement;
+        }
+
+        // only do smart stuff if search and replace strings were entered in lowercase.
+        // check here. if not lowercase, just return.
+
+        if( !isLowerCase(replacement) || !isLowerCase(original)) {
+            return replacement;
+        }
+        if(isUpperCase(original)) {
+            return replacement.toUpperCase();
+        }
+        if(isTitleCase(original)) {
+            return Character.toTitleCase(replacement.charAt(0)) + 
+                replacement.substring(1);
+        }
+        
+        return replacement;
+    }
+
+    /**
+     * True if the string is in lower case.
+     */
+    public boolean isLowerCase(String s)
+    {
+        for(int i=0; i<s.length(); i++) {
+            if(! Character.isLowerCase(s.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * True if the string is in Upper case.
+     */
+    public boolean isUpperCase(String s)
+    {
+        for(int i=0; i<s.length(); i++) {
+            if(! Character.isUpperCase(s.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * True if the string is in title case.
+     */
+    public boolean isTitleCase(String s)
+    {
+        if(s.length() < 2) {
+            return false;
+        }
+        return Character.isUpperCase(s.charAt(0)) &&
+                Character.isLowerCase(s.charAt(1));
+    }
+
+    /**
+     * Sets the find panel to be visible
+     */
+    public void setFindPanelVisible()
+    {
+        finder.setVisible(true);
+    }
+
+    /**
+     * Replace all instances of the search String with a replacement.
+     * -check for valid search criteria
+     * -start at beginning
+     * -do initial find
+     * -replace until not found, no wrapping!
+     * -print out number of replacements (?)
+     */
+    public void replaceAll(String replaceString)
+    {
+        //remove selection and remove highlighting 
+        int caretPos = sourcePane.getCaretPosition();
+        if (getSelectionBegin()!=null) {
+            sourcePane.setCaretPosition(getSelectionBegin().getColumn());
+        }
+        removeSearchHighlights();
+        String searchString = finder.getSearchString();
+        boolean isMatchCase=finder.getMatchCase();
+        int count = 0;
+        while(doFindBackward(searchString, !isMatchCase, false)) {
+            insertText(smartFormat(searchString, replaceString), true);
+            count++;
+        }        
+        while(doFind(searchString, !isMatchCase,false)) 
+        {
+            insertText(smartFormat(searchString, replaceString), false);
+            count++;
+        }
+
+        removeSearchHighlights();
+        sourcePane.setCaretPosition(caretPos);
+
+
+        if(count > 0) {
+            writeMessage(Config.getString("editor.replaceAll.replaced").trim() + " " +
+                    count + " " + Config.getString("editor.replaceAll.intancesOf").trim() + " " +
+                    searchString);
+        }
+        else {
+            writeMessage(Config.getString("editor.replaceAll.string").trim() + " " +
+                    searchString + " " + Config.getString("editor.replaceAll.notFoundNothingReplaced"));
+        }
+    }
+
+    /**
+     * Sets the caret selection visible. The visibility will be persistent,
+     * until the caret is repositioned.
+     */
+    protected void setSelectionVisible()
+    {
+        Caret caret = currentTextPane.getCaret();
+        caret.setSelectionVisible(true);
+        if (caret instanceof MoeCaret) {
+            MoeCaret mcaret = (MoeCaret) caret;
+            mcaret.setPersistentHighlight();
+        }
+    }
+
+    /**
+     * getFindSearchString() returns the search string in the find panel
+     */
+    protected String getFindSearchString()
+    {
+        return finder.getSearchString();
+    }
+
+    /**
+     * Enables/disables the once and all buttons on the replace panel
+     * @param enable  True to enable; false to disable
+     */
+    protected void enableReplaceButtons(boolean enable)
+    {
+        replacer.enableButtons(enable);
+    }
+    
+    /**
+     * Enables/disables the once and all buttons on the replace panel
+     */
+    protected void enableReplaceButtons()
+    {
+        replacer.enableButtons();
+    }
+
+    /**
+     * When the mouse is clicked away from the selected text, 
+     * the replace buttons need to be disabled
+     */
+    public void mouseClicked(MouseEvent e) { }
+
+    public void mouseEntered(MouseEvent e) { }
+
+    public void mouseExited(MouseEvent e) { }
+
+    public void mousePressed(MouseEvent e)
+    {
+        showPopup(e);
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+        showPopup(e);
+    }
+    
+    /**
+     * Displays the popup menu, if triggered by the given mouse event
+     */
+    private void showPopup(MouseEvent e)
+    {
+        if (e.isPopupTrigger()) {
+            popup.show(e.getComponent(),
+                       e.getX(), e.getY());
+        }
+    }
+ 
+    /**
+     * Populates the find field and requests focus
+     */
+    public void setFindTextfield(String text)
+    {
+        finder.populateFindTextfield(text);
+    }
+    
+    /**
+     * Determines whether the Naviview should initially be expanded or not.
+     */
+    protected boolean getNaviviewExpandedProperty()
+    {
+        if (watcher != null && watcher.getProperty(EditorWatcher.NAVIVIEW_EXPANDED_PROPERTY)!=null)
+        {
+            return Boolean.parseBoolean(watcher.getProperty(EditorWatcher.NAVIVIEW_EXPANDED_PROPERTY));
+        }
+        else {
+            return PrefMgr.getNaviviewExpanded();
+        }
+    }
+    
+    /**
+     * Returns whether the editor text represents source code, or something else
+     * (such as the README.txt file).
+     * 
+     * @return true if source code; 
+     *         false if not
+     */
+    protected boolean containsSourceCode() 
+    {
+        return sourceIsCode;
+    }
+    
+    private void recordLoadContent()
+    {
+        previousDoc = new ArrayList<String>();
+        getLines(previousDoc);
+    }
+    
+    private void getLines(ArrayList<String> lines)
+    {
+        Element parent = sourceDocument.getDefaultRootElement();
+        lines.ensureCapacity(parent.getElementCount());
+        for (int i = 0; i < parent.getElementCount(); i++)
+        {
+            String line = "";
+            try {
+                line = sourceDocument.getText(parent.getElement(i).getStartOffset(), parent.getElement(i).getEndOffset() - parent.getElement(i).getStartOffset());
+            }
+            catch (BadLocationException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+            lines.add(line);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditorManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditorManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..5aa56fee51c113d99e09be807a68001e6307aeb5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditorManager.java
@@ -0,0 +1,219 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import bluej.Config;
+import bluej.editor.Editor;
+import bluej.editor.EditorWatcher;
+import bluej.parser.entity.EntityResolver;
+import bluej.pkgmgr.JavadocResolver;
+
+/**
+ * Implementation of EditorManager for the Moe editor.
+ * 
+ * @author Michael Kolling
+ */
+
+public final class MoeEditorManager
+    extends bluej.editor.EditorManager
+{
+    // public static variables
+
+    protected static MoeEditorManager editorManager;   // the manager object itself
+
+    // private variables
+
+    private Properties resources;
+    private List<MoeEditor> editors; // open editors
+
+    // user preferences
+
+    private boolean showLineNum;
+    private boolean showToolBar;
+
+    // =========================== PUBLIC METHODS ===========================
+
+    public MoeEditorManager()
+    {
+        editors = new ArrayList<MoeEditor>(4);
+               
+        showToolBar = true;
+        showLineNum = false;
+
+        resources = Config.moeUserProps;
+
+        editorManager = this;   // make this object publicly available
+    }
+
+
+    // ------------------------------------------------------------------------
+    
+    /*
+     * Open an editor to display a class. The filename may be "null"
+     * to open an empty editor (e.g. for displaying a view). The editor
+     * is initially hidden. A call to "Editor::show" is needed to make
+     * is visible after opening it.
+     *
+     * @param filename     name of the source file to open (may be null)
+     * @param docFilename  name of the corresponding javadoc file 
+     * @param windowTitle  title of window (usually class name)
+     * @param watcher      an watcher to be notified of edit events
+     * @param compiled     true, if the class has been compiled
+     * @param bounds       the bounds of the window to appear on screen
+     * @param projectResolver   A resolver for external symbols
+     * 
+     * @return          the new editor, or null if there was a problem
+     */
+    @Override
+    public Editor openClass(String filename, 
+                String docFilename,
+                Charset charset,
+                String windowTitle,
+                EditorWatcher watcher, 
+                boolean compiled,
+                Rectangle bounds,
+                EntityResolver projectResolver,
+                JavadocResolver javadocResolver)
+    {
+        return openEditor (filename, docFilename, charset, true, windowTitle, watcher, compiled,
+                           bounds, projectResolver, javadocResolver);
+    }
+
+    // ------------------------------------------------------------------------
+    
+    /*
+     * Open an editor to display a text document. The difference to
+     * "openClass" is that code specific functions (such as compile,
+     * debug, view) are disabled in the editor. The filename may be
+     * "null" to open an empty editor. The editor is initially hidden.
+     * A call to "Editor.show" is needed to make is visible after
+     * opening it.
+     *
+     * @param filename          name of the source file to open (may be null)
+     * @param windowTitle       title of window (usually class name)
+     * @returns                 the new editor, or null if there was a problem
+     */
+    @Override
+    public Editor openText(String filename, Charset charset, String windowTitle,
+                           Rectangle bounds)
+    {
+        return openEditor(filename, null, charset, false, windowTitle, null, false, bounds, null, null);
+    }
+
+    public void refreshAll()
+    {
+        Iterator<MoeEditor> e = editors.iterator();
+
+        while(e.hasNext()) {
+            Editor ed = e.next();
+
+            if(ed.isShowing()) {
+                ed.refresh();
+            }
+       }
+    }
+
+    // ------------------------------------------------------------------------
+    
+    /**
+     * Sound a beep if the "beep with warning" option is true
+     */
+    public void beep()
+    {
+        if(true) // if beepWarning option is on...
+            Toolkit.getDefaultToolkit().beep();
+    }
+
+    // ------------------------------------------------------------------------
+    
+    /**
+     * Discard the given editor and leave it to be collected by the garbage
+     * collector.
+     */
+    public void discardEditor(Editor ed)
+    {
+        ed.close();
+        editors.remove(ed);
+    }
+
+    // ========================== PACKAGE METHODS ===========================
+
+
+    // ------------------------------------------------------------------------
+ 
+    
+    // ========================== PRIVATE METHODS ===========================
+
+    // ------------------------------------------------------------------------
+    
+    /**
+     * Open an editor to display a class. The filename may be "null"
+     * to open an empty editor (e.g. for displaying a view). The editor
+     * is initially hidden. A call to "Editor::show" is needed to make
+     * is visible after opening it.
+     *
+     * @param filename     name of the source file to open (may be null)
+     * @param docFilename  name of the documentation based on filename
+     * @param charset      the character set of the file contents
+     * @param isCode       true if the file represents code, or false if it is plain text
+     * @param windowTitle  title of window (usually class name)
+     * @param watcher      an object interested in editing events
+     * @param compiled     true, if the class has been compiled
+     * @param bounds       bounds for the editor window. If the width and/or height are
+     *                     zero, then only the position (x,y) are to be used.
+     * @param projectResolver   a resolver for external symbols
+     * @returns       the new editor, or null if there was a problem
+     */
+    private Editor openEditor(String filename, String docFilename,
+            Charset charset,
+            boolean isCode, String windowTitle, 
+            EditorWatcher watcher, boolean compiled, 
+            Rectangle bounds, EntityResolver projectResolver,
+            JavadocResolver javadocResolver)
+    {
+        MoeEditor editor;
+
+        MoeEditorParameters mep = new MoeEditorParameters(windowTitle, watcher,
+                resources, projectResolver, javadocResolver);
+        mep.setCode(isCode);
+        mep.setShowToolbar(showToolBar);
+        mep.setShowLineNum(showLineNum);
+        editor = new MoeEditor(mep);
+        editors.add(editor);
+        if (editor.showFile(filename, charset, compiled, docFilename, bounds)) {
+            return editor;
+        }
+        else {
+            editor.doClose();           // editor will remove itself
+            return null;
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditorPane.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditorPane.java
new file mode 100644
index 0000000000000000000000000000000000000000..498a965bb126b20b23164b7d1730bc7c9676e694
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditorPane.java
@@ -0,0 +1,67 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+
+import javax.swing.JEditorPane;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * MoeJEditorPane - a variation of JEditorPane for Moe. The preferred size
+ * is adjusted to allow for the tag line.
+ *
+ * @author Michael Kolling
+ */
+public final class MoeEditorPane extends JEditorPane
+{
+    /**
+     * Create an editor pane specifically for Moe.
+     */
+    public MoeEditorPane()
+    {
+        super();
+        setBorder(new EmptyBorder(6, 6, 6, 0));
+        setHighlighter(new MoeHighlighter());
+    }
+    
+    /*
+     * Adjust this pane's preferred size to add the tag area.
+     */
+    public Dimension getPreferredSize() 
+    {
+        Dimension d = super.getPreferredSize();
+        d.width += MoeSyntaxView.TAG_WIDTH + 8;  // bit of empty space looks nice
+        return d;
+    }
+
+    /*
+     * Make sure, when we are scrolling to follow the caret,
+     * that we can see the tag area as well.
+     */
+    public void scrollRectToVisible(Rectangle rect)
+    {
+        super.scrollRectToVisible(new Rectangle(rect.x - (MoeSyntaxView.TAG_WIDTH + 4), rect.y,
+                                                rect.width + MoeSyntaxView.TAG_WIDTH + 4, rect.height));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditorParameters.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditorParameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..70cb3408b11aef14de1858bd8ee093f6f726ef6e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeEditorParameters.java
@@ -0,0 +1,136 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.util.Properties;
+
+import bluej.editor.EditorWatcher;
+import bluej.parser.entity.EntityResolver;
+import bluej.pkgmgr.JavadocResolver;
+
+/**
+ * Parameters for the Moe editor.
+ * 
+ * @author Davin McCall
+ */
+public class MoeEditorParameters
+{
+    private String title;
+    private boolean isCode;
+    private EditorWatcher watcher;
+    private boolean showToolbar;
+    private boolean showLineNum;
+    private Properties resources;
+    private EntityResolver projectResolver;
+    private JavadocResolver javadocResolver;
+
+    public MoeEditorParameters(String title, EditorWatcher watcher,
+            Properties resources, EntityResolver projectResolver,
+            JavadocResolver javadocResolver)
+    {
+        this.title = title;
+        this.watcher = watcher;
+        this.resources = resources;
+        this.projectResolver = projectResolver;
+        this.javadocResolver = javadocResolver;
+    }
+
+    public String getTitle()
+    {
+        return title;
+    }
+
+    public void setTitle(String title)
+    {
+        this.title = title;
+    }
+
+    public boolean isCode()
+    {
+        return isCode;
+    }
+
+    public void setCode(boolean isCode)
+    {
+        this.isCode = isCode;
+    }
+
+    public EditorWatcher getWatcher()
+    {
+        return watcher;
+    }
+
+    public void setWatcher(EditorWatcher watcher)
+    {
+        this.watcher = watcher;
+    }
+
+    public boolean isShowToolbar()
+    {
+        return showToolbar;
+    }
+
+    public void setShowToolbar(boolean showToolbar)
+    {
+        this.showToolbar = showToolbar;
+    }
+
+    public boolean isShowLineNum()
+    {
+        return showLineNum;
+    }
+
+    public void setShowLineNum(boolean showLineNum)
+    {
+        this.showLineNum = showLineNum;
+    }
+
+    public Properties getResources()
+    {
+        return resources;
+    }
+
+    public void setResources(Properties resources)
+    {
+        this.resources = resources;
+    }
+
+    public EntityResolver getProjectResolver()
+    {
+        return projectResolver;
+    }
+
+    public void setProjectResolver(EntityResolver projectResolver)
+    {
+        this.projectResolver = projectResolver;
+    }
+    
+    public JavadocResolver getJavadocResolver()
+    {
+        return javadocResolver;
+    }
+    
+    public void setJavadocResolver(JavadocResolver javadocResolver)
+    {
+        this.javadocResolver = javadocResolver;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeErrorManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeErrorManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..006b49b43c2547900412267bc4f13b11a9a7fef1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeErrorManager.java
@@ -0,0 +1,272 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JEditorPane;
+import javax.swing.Timer;
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.BadLocationException;
+
+import bluej.parser.nodes.NodeTree;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * Manages the display of parse and compiler errors for a MoeEditor instance.
+ * 
+ * @author Davin McCall
+ */
+public class MoeErrorManager implements MoeDocumentListener
+{
+    /** Parse error delay in milliseconds */
+    private static final int ERR_DISPLAY_DELAY = 1000;
+    
+    // Error highlight colors
+    private static final Color ERROR_HIGHLIGHT_GRADIENT1 = new Color(240,128,128);
+    private static final Color ERROR_HIGHLIGHT_GRADIENT2 = new Color(240,190,190);
+    private static final Color ERROR_HIGHLIGHT_SELECTED1 = ERROR_HIGHLIGHT_GRADIENT1;
+    private static final Color ERROR_HIGHLIGHT_SELECTED2 = ERROR_HIGHLIGHT_GRADIENT2;
+    
+    private MoeEditor editor;
+    
+    private Object errorHighlightTag = null;
+    
+    /** A timer used to delay the appearance of parse errors until the user is idle */
+    private Timer timer;
+    
+    /** Parse errors that are currently being displayed */
+//    private NodeTree<ParseErrorNode> parseErrors = new NodeTree<ParseErrorNode>();
+    /** Parse errors that haven't yet been displayed */
+//    private NodeTree<ParseErrorNode> pendingErrors = new NodeTree<ParseErrorNode>();
+    
+    /**
+     * Construct a new MoeErrorManager to manage error display for the specified editor instance.
+     * The new manager should be set as the document listener so that it receives notification
+     * of parser errors as they occur.
+     */
+    public MoeErrorManager(MoeEditor editor)
+    {
+        this.editor = editor;
+    }
+    
+    /**
+     * Add a compiler error highlight.
+     * @param startPos  The document position where the error highlight should begin
+     * @param endPos    The document position where the error highlight should end
+     */
+    public void addErrorHighlight(int startPos, int endPos)
+    {
+        JEditorPane sourcePane = editor.getSourcePane();
+        try {
+            MoeHighlighter highlighter = (MoeHighlighter) sourcePane.getHighlighter();
+            AdvancedHighlightPainter painter = new MoeBorderHighlighterPainter(Color.RED,
+                    ERROR_HIGHLIGHT_GRADIENT1, ERROR_HIGHLIGHT_GRADIENT2,
+                    ERROR_HIGHLIGHT_SELECTED1, ERROR_HIGHLIGHT_SELECTED2);
+            errorHighlightTag = highlighter.addHighlight(startPos, endPos, painter);
+        }
+        catch (BadLocationException ble) {
+            throw new RuntimeException(ble);
+        }
+    }
+    
+    /**
+     * Remove any existing compiler error highlight.
+     */
+    public void removeErrorHighlight()
+    {
+        if (errorHighlightTag != null) {
+            JEditorPane sourcePane = editor.getSourcePane();
+            sourcePane.getHighlighter().removeHighlight(errorHighlightTag);
+            errorHighlightTag = null;
+        }
+    }
+    
+    /**
+     * Notify the error manager of an insert update to the document.
+     */
+    public void insertUpdate(DocumentEvent e)
+    {
+//        NodeAndPosition<ParseErrorNode> nap = parseErrors.findNodeAtOrAfter(e.getOffset());
+//        if (nap != null) {
+//            nap.slide(e.getLength());
+//        }
+//        
+//        nap = pendingErrors.findNodeAtOrAfter(e.getOffset());
+//        if (nap != null) {
+//            nap.slide(e.getLength());
+//        }
+//        
+//        if (timer != null) {
+//            timer.restart();
+//        }
+    }
+    
+    /**
+     * Notify the error manager of a remove update to the document.
+     */
+    public void removeUpdate(DocumentEvent e)
+    {
+//        NodeAndPosition<ParseErrorNode> nap = parseErrors.findNodeAtOrAfter(e.getOffset() + e.getLength());
+//        if (nap != null) {
+//            if (nap.getPosition() >= e.getOffset() + e.getLength()) {
+//                nap.slide(-e.getLength());
+//            }
+//        }
+//        
+//        nap = pendingErrors.findNodeAtOrAfter(e.getOffset() + e.getLength());
+//        if (nap != null) {
+//            if (nap.getPosition() >= e.getOffset() + e.getLength()) {
+//                nap.slide(-e.getLength());
+//            }
+//        }
+//
+//        if (timer != null) {
+//            timer.restart();
+//        }
+    }
+    
+    /**
+     * Get the error code (or message) at a particular document position.
+     */
+    public String getErrorAtPosition(int pos)
+    {
+//        NodeAndPosition<ParseErrorNode> nap = parseErrors.findNode(pos);
+//        if (nap != null) {
+//            return nap.getNode().getErrCode();
+//        }
+        return null;
+    }
+    
+    @Override
+    public void parseError(int position, int size, String message)
+    {
+        // Don't add this error if it overlaps an existing error:
+//        NodeAndPosition<ParseErrorNode> nap = parseErrors.findNodeAtOrAfter(position);
+//        while (nap != null && nap.getEnd() == position && nap.getPosition() != position) {
+//            nap = nap.nextSibling();
+//        }
+//        if (nap != null) {
+//            if (nap.getEnd() <= position + size) {
+//                return;
+//            }
+//        }
+//
+//        nap = pendingErrors.findNodeAtOrAfter(position);
+//        while (nap != null && nap.getEnd() == position && nap.getPosition() != position) {
+//            nap = nap.nextSibling();
+//        }
+//        if (nap != null) {
+//            if (nap.getEnd() <= position + size) {
+//                return;
+//            }
+//        }
+//
+//        pendingErrors.insertNode(new ParseErrorNode(null, message), position, size);
+//
+//        if (timer == null) {
+//            timer = new Timer(ERR_DISPLAY_DELAY, new ActionListener() {
+//                @Override
+//                public void actionPerformed(ActionEvent e)
+//                {
+//                    timerExpiry();
+//                }
+//            });
+//
+//            timer.setCoalesce(true);
+//            timer.setRepeats(false);
+//            timer.start();
+//        }
+    }    
+    
+    @Override
+    public void reparsingRange(int position, int size)
+    {
+//        // Remove any parse error highlights in the reparsed range
+//        int endPos = position + size;
+//        
+//        clearReparsedRange(parseErrors, position, endPos);
+//        clearReparsedRange(pendingErrors, position, endPos);
+    }
+    
+//    private void clearReparsedRange(NodeTree<ParseErrorNode> tree, int position, int endPos)
+//    {
+//        NodeAndPosition<ParseErrorNode> nap = tree.findNodeAtOrAfter(position);
+//        while (nap != null && nap.getPosition() <= endPos) {
+//            ParseErrorNode pen = nap.getNode();
+//            JEditorPane sourcePane = editor.getSourcePane();
+//            Object highlightTag = pen.getHighlightTag();
+//            if (highlightTag != null) {
+//                sourcePane.getHighlighter().removeHighlight(highlightTag);
+//            }
+//            
+//            NodeAndPosition<ParseErrorNode> nnap = nap.nextSibling();
+//            pen.remove();
+//            nap = nnap;
+//        }
+//    }
+    
+    /**
+     * The timer expired... make pending errors visible
+     */
+//    private void timerExpiry()
+//    {
+//        NodeAndPosition<ParseErrorNode> nap = pendingErrors.findNodeAtOrAfter(0);
+//        while (nap != null) {
+//            ParseErrorNode pen = nap.getNode();
+//            
+//            int position = nap.getPosition();
+//            int size = nap.getSize();
+//
+//            JEditorPane sourcePane = editor.getSourcePane();
+//            int caretPos = sourcePane.getCaretPosition();
+//            
+//            try {
+//                MoeHighlighter mhiliter = (MoeHighlighter) sourcePane.getHighlighter();
+//                Object highlightTag = mhiliter.addHighlight(
+//                        position, position + size,
+//                        new MoeBorderHighlighterPainter(Color.RED, Color.RED, Color.PINK,
+//                                Color.RED, Color.PINK)
+//                );
+//
+//                parseErrors.insertNode(new ParseErrorNode(highlightTag, pen.getErrCode()), position, size);
+//                
+//                // Check if the error overlaps the caret currently
+//                if (caretPos >= position && caretPos <= position + size) {
+//                    if (! editor.isShowingInterface()) {
+//                        editor.writeMessage(ParserMessageHandler.getMessageForCode(pen.getErrCode()));
+//                    }
+//                }
+//            }
+//            catch (BadLocationException ble) {
+//                throw new RuntimeException(ble);
+//            }
+//            
+//            nap = nap.nextSibling();
+//        }
+//        
+//        pendingErrors.clear();
+//        timer = null;
+//    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeHighlighter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeHighlighter.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0b2b21a379ad3bd26a39fc4483fb5b7d30700e8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeHighlighter.java
@@ -0,0 +1,301 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.LayeredHighlighter;
+import javax.swing.text.Position;
+import javax.swing.text.View;
+
+/**
+ * A custom highlighter which handles some things much better than the DefaultHighlighter.
+ * 
+ * @author Davin McCall
+ */
+public class MoeHighlighter extends LayeredHighlighter
+{
+    // Concerns: highlight is specified as between two document positions...
+    //   ... but: painter draws slightly outside the range of those positions
+    //   ... only the painter itself knows its true extent
+    
+    private JTextComponent component;
+    
+    private List<StandardMoeHighlight> highlights = new LinkedList<StandardMoeHighlight>();
+    private LinkedList<MoeHighlight> layeredHighlights = new LinkedList<MoeHighlight>();
+    
+    private abstract static class MoeHighlight
+    {
+        protected Position startPos;
+        protected Position endPos;
+        
+        public MoeHighlight(Position startPos, Position endPos)
+        {
+            this.startPos = startPos;
+            this.endPos = endPos;
+        }
+        
+        //@Override
+        public int getStartOffset()
+        {
+            return startPos.getOffset();
+        }
+        
+        //@Override
+        public int getEndOffset()
+        {
+            return endPos.getOffset();
+        }
+        
+        /**
+         * Issue a repaint to the component, in order that this highlight be repainted.
+         */
+        public void repaintHighlight(JTextComponent component)
+        {
+            int p0 = startPos.getOffset();
+            int p1 = endPos.getOffset();
+            // Must take extra area into account
+            // component.getUI().damageRange(component, p0, p1, Bias.Forward, Bias.Backward);
+            
+            // TextUI interface is pretty bad. We can't find out what the paint region between two positions
+            // is - we only have the option to issue a repaint (via damageRange()). So we make some assumptions
+            // about the UI implementation here.
+            
+            Rectangle r = component.getBounds();
+            Insets insets = component.getInsets();
+            r.x = insets.left;
+            r.y = insets.top;
+            r.width -= insets.left + insets.right;
+            r.height -= insets.top + insets.bottom;
+            
+            View rootView = component.getUI().getRootView(component);
+            try {
+                Rectangle region = rootView.modelToView(p0, Position.Bias.Forward,
+                        p1, Position.Bias.Backward, r).getBounds();
+                component.repaint(region);
+            }
+            catch (BadLocationException ble) {
+                throw new RuntimeException(ble);
+            }
+        }
+        
+        /**
+         * Paint this highlight as a layered highlight
+         * @param g  The graphics context to draw in
+         * @param p0   The start of the damaged region (first damaged character)
+         * @param p1   The end of the damaged region  (one beyond last damaged character)
+         * @param viewBounds  The bounds of the view containing the highlight
+         * @param editor   The component
+         * @param view    The view
+         */
+        public abstract void paint(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor, View view);
+    }
+    
+    /**
+     * A highlight handling layered highlights.
+     */
+    private static class StandardMoeHighlight extends MoeHighlight
+    {
+        private HighlightPainter painter;
+
+        public StandardMoeHighlight(Position startPos, Position endPos, HighlightPainter painter)
+        {
+            super(startPos, endPos);
+            this.painter = painter;
+        }
+        
+        public HighlightPainter getPainter()
+        {
+            return painter;
+        }
+
+        public void paint(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor, View view)
+        {
+            int start = startPos.getOffset();
+            int end = endPos.getOffset();
+
+            if ((p0 < start && p1 > start) ||
+                    (p0 >= start && p0 < end)) {
+                p0 = Math.max(p0, start);
+                p1 = Math.min(p1, end);
+                ((LayerPainter) painter).paintLayer(g, p0, p1, viewBounds, editor, view);
+            }
+        }
+    }
+    
+    /**
+     * A highlight handling advanced highlights.
+     */
+    private static class AdvancedMoeHighlight extends MoeHighlight
+    {
+        private AdvancedHighlightPainter painter;
+        
+        public AdvancedMoeHighlight(Position startPos, Position endPos, AdvancedHighlightPainter painter)
+        {
+            super(startPos, endPos);
+            this.painter = painter;
+        }
+        
+        @Override
+        public void repaintHighlight(JTextComponent component)
+        {
+            int p0 = startPos.getOffset();
+            int p1 = endPos.getOffset();
+            Rectangle r = component.getBounds();
+            Insets insets = component.getInsets();
+            r.x = insets.left;
+            r.y = insets.top;
+            r.width -= insets.left + insets.right;
+            r.height -= insets.top + insets.bottom;
+            
+            View rootView = component.getUI().getRootView(component);
+            painter.issueRepaint(p0, p1, r, component, rootView);
+        }
+        
+        @Override
+        public void paint(Graphics g, int p0, int p1, Shape viewBounds,
+                JTextComponent editor, View view)
+        {
+            painter.paint(g, startPos.getOffset(), endPos.getOffset(), viewBounds, editor, view);
+        }
+    }
+    
+    @Override
+    public Object addHighlight(int p0, int p1, HighlightPainter p)
+            throws BadLocationException
+    {
+        Document doc = component.getDocument();
+        Position pos0 = doc.createPosition(p0);
+        Position pos1 = doc.createPosition(p1);
+        StandardMoeHighlight highlight = new StandardMoeHighlight(pos0, pos1, p);
+        if (p instanceof LayerPainter) {
+            layeredHighlights.add(highlight);
+        }
+        else {
+            highlights.add(highlight);
+        }
+        highlight.repaintHighlight(component);
+        return highlight;
+    }
+    
+    public Object addHighlight(int p0, int p1, AdvancedHighlightPainter p)
+            throws BadLocationException
+    {
+        Document doc = component.getDocument();
+        Position pos0 = doc.createPosition(p0);
+        Position pos1 = doc.createPosition(p1);
+        AdvancedMoeHighlight highlight = new AdvancedMoeHighlight(pos0, pos1, p);
+        layeredHighlights.add(highlight);
+        highlight.repaintHighlight(component);
+        return highlight;
+    }
+    
+    @Override
+    public void changeHighlight(Object tag, int p0, int p1)
+            throws BadLocationException
+    {
+        MoeHighlight highlight = (MoeHighlight) tag;
+        Document doc = component.getDocument();
+        highlight.repaintHighlight(component); // repaint the old area
+        highlight.startPos = doc.createPosition(p0);
+        highlight.endPos = doc.createPosition(p1);
+        highlight.repaintHighlight(component); // repaint the new area
+    }
+    
+    @Override
+    public void install(JTextComponent c)
+    {
+        removeAllHighlights();
+        component = c;
+    }
+
+    @Override
+    public void deinstall(JTextComponent c)
+    {
+        component = null;
+    }
+    
+    @Override
+    public Highlight[] getHighlights()
+    {
+        return highlights.toArray(new Highlight[highlights.size()]);
+    }
+    
+    @Override
+    public void paint(Graphics g)
+    {
+        Rectangle r = component.getBounds();
+        Insets insets = component.getInsets();
+        r.x = insets.left;
+        r.y = insets.top;
+        r.width -= insets.left + insets.right;
+        r.height -= insets.top + insets.bottom;
+        
+        for (StandardMoeHighlight highlight : highlights) {
+            highlight.getPainter().paint(g, highlight.getStartOffset(), highlight.getEndOffset(), r, component);
+        }
+    }
+    
+    @Override
+    public void paintLayeredHighlights(Graphics g, int p0, int p1,
+            Shape viewBounds, JTextComponent editor, View view)
+    {
+        int viewStart = view.getStartOffset();
+        int viewEnd = view.getEndOffset();
+
+        Iterator<MoeHighlight> i = layeredHighlights.descendingIterator();
+        for ( ; i.hasNext(); ) {
+            MoeHighlight highlight = i.next();
+            if (highlight.startPos.getOffset() < viewEnd && highlight.endPos.getOffset() > viewStart) {
+                highlight.paint(g, p0, p1, viewBounds, editor, view);
+            }
+        }
+    }
+    
+    @Override
+    public void removeAllHighlights()
+    {
+        layeredHighlights.clear();
+        highlights.clear();
+        if (component != null) {
+            component.repaint();
+        }
+    }
+    
+    @Override
+    public void removeHighlight(Object tag)
+    {
+        MoeHighlight mh = (MoeHighlight) tag;
+        mh.repaintHighlight(component);
+        highlights.remove(tag);
+        layeredHighlights.remove(tag);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeIndent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeIndent.java
new file mode 100644
index 0000000000000000000000000000000000000000..019bd692fa5ccfb095e8b30f493313befcb9cbab
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeIndent.java
@@ -0,0 +1,517 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010,2011  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.Position;
+
+import bluej.Config;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+import bluej.parser.nodes.ParsedNode;
+import bluej.utility.Debug;
+
+/**
+ * This class contains the "auto layout" functionality of the editor.
+ */
+public class MoeIndent
+{
+    // from beginning string match any number of whitespaces or tabs.
+    private static final Pattern WHITESPACE_TABS = Pattern.compile("^[ \\t]*");
+    // from beginning of string match any number of whitespaces, tabs
+    // and stars, followed by an optional forward slash and star.
+    private static final Pattern WHITESPACE_TABS_STAR = Pattern.compile("^[ \\t*]*(/\\*)?");
+
+    public static class AutoIndentInformation
+    {
+        private boolean perfect;
+        private int newCaretPos;
+        
+        public AutoIndentInformation(boolean perfect, int newCaretPos)
+        {
+            this.perfect = perfect;
+            this.newCaretPos = newCaretPos;
+        }
+        
+        public boolean isPerfect()
+        {
+            return perfect;
+        }
+        
+        public int getNewCaretPosition()
+        {
+            return newCaretPos;
+        }
+    }
+    
+    /**
+     * Perform an auto-layout - calculate the correct indent for each source line, and apply it. Return
+     * information about the applied indentation.
+     */
+    public static AutoIndentInformation calculateIndentsAndApply(MoeSyntaxDocument doc, int caretPos)
+    {
+        return calculateIndentsAndApply(doc, 0, doc.getLength(), caretPos);
+    }
+    
+    /**
+     * Perform an auto-layout - calculate the correct indent for each source line between the given
+     * start and end positions, and apply it. Return information about the applied indentation.
+     */
+    public static AutoIndentInformation calculateIndentsAndApply(MoeSyntaxDocument doc,
+            int startPos, int endPos, int prevCaretPos)
+    {
+        int caretPos = prevCaretPos;
+        Element rootElement = doc.getDefaultRootElement();
+        List<DocumentAction> methodUpdates = new LinkedList<DocumentAction>();
+        List<DocumentAction> updates = new ArrayList<DocumentAction>(rootElement.getElementCount());
+        
+        IndentCalculator ii = new RootIndentCalculator();
+
+        boolean lastLineWasBlank = false;
+        boolean perfect = true;
+        NodeAndPosition<ParsedNode> root = new NodeAndPosition<ParsedNode>(doc.getParser(), 0, doc.getParser().getSize());
+
+        // Track the start and end positions, as they may change due to updates
+        Position startp, endp;
+        try {
+            startp = doc.createPosition(startPos);
+            endp = doc.createPosition(endPos);
+        }
+        catch (BadLocationException ble) {
+            throw new RuntimeException(ble);
+        }
+        
+        // examine if there are missing spaces between methods and add them.
+        // NB. proper indentation of these changes later in this method.
+        checkMethodSpacing(root, rootElement, methodUpdates, startPos, endPos);
+        for (DocumentAction methodUpdate : methodUpdates) {
+            caretPos = methodUpdate.apply(doc, caretPos);
+        }
+        methodUpdates = null;
+        
+        // Remove excessive blank lines:
+        for (int i = 0; i < rootElement.getElementCount(); i++) {
+            Element el = rootElement.getElement(i);
+            // If the element overlaps at all with our area of interest:
+            if (el.getEndOffset() > startp.getOffset() && el.getStartOffset() < endp.getOffset()) {
+                boolean thisLineBlank = isWhiteSpaceOnly(getElementContents(doc, el));
+                if (thisLineBlank) {
+                    try {
+                        if (caretPos >= el.getStartOffset() && caretPos < el.getEndOffset()) {
+                            caretPos = el.getStartOffset();
+                        }
+                        if (lastLineWasBlank) {
+                            // Consecutive blank lines; remove this one:
+                            if (el.getEndOffset() <= doc.getLength()) {
+                                doc.remove(el.getStartOffset(), el.getEndOffset() - el.getStartOffset());
+                                perfect = false;
+                            }
+                        } else {
+                            // Single blank line (thus far), remove all spaces from
+                            // it (and don't interrupt perfect status):
+                            int rmlen = el.getEndOffset() - el.getStartOffset() - 1;
+                            if (rmlen > 0) {
+                                doc.remove(el.getStartOffset(), rmlen);
+                            }
+                        }
+                    }
+                    catch (BadLocationException ble) {
+                        throw new RuntimeException(ble);
+                    }
+                }
+                lastLineWasBlank = thisLineBlank;
+            }
+        }
+        
+        // Line removals may have affected parse node structure. Fix it:
+        doc.flushReparseQueue();
+        
+        // Check indentation of each line, build a list of updates required:
+        for (int i = 0; i < rootElement.getElementCount(); i++) {
+            Element el = rootElement.getElement(i);
+            
+            // If the element overlaps at all with our area of interest:
+            if (el.getEndOffset() > startp.getOffset() && el.getStartOffset() < endp.getOffset()) {
+
+                boolean thisLineBlank = isWhiteSpaceOnly(getElementContents(doc, el));
+                DocumentAction update = null;
+    
+                if (!thisLineBlank) {
+                    String indent = calculateIndent(el, root, ii, doc);
+                    update = new DocumentIndentAction(el, indent);
+                    perfect = perfect && getElementContents(doc, el).startsWith(indent)
+                                      && !isWhiteSpaceOnly(getElementContents(doc, el).substring(indent.length(),indent.length() + 1));
+                }
+    
+                if (update != null) {
+                    updates.add(update);
+                }
+                lastLineWasBlank = thisLineBlank;
+            }
+        }
+
+        // Now apply the required updates:
+        for (DocumentAction update : updates) {
+            caretPos = update.apply(doc, caretPos);
+        }
+
+        return new AutoIndentInformation(perfect, caretPos);
+    }
+
+    /**
+     * Finds the indent for the given element by looking at the nodes in the parse tree
+     * 
+     * @param el The element to calculate the indent for
+     * @param start The Node that is either the one directly containing the given element,
+     *              or is an ancestor of the one that directly contains the given element,
+     *              or may not contain the element at all (in which case null will be returned)
+     * @param startIC The IndentCalculator corresponding to start
+     * @param doc The document involved
+     * @return The indent that the element should have, up to the first non-whitespace character.
+     *         Returns null if start does not contain the given element
+     */
+    private static String calculateIndent(Element el,
+            NodeAndPosition<ParsedNode> start, IndentCalculator startIC, MoeSyntaxDocument doc)
+    {
+        int pos = el.getStartOffset() + findFirstNonIndentChar(getElementContents(doc, el), true);
+        if (pos >= start.getPosition() && pos < start.getEnd()) {
+            // The slightly awkward way to loop through the children of "start":
+            for (Iterator<NodeAndPosition<ParsedNode>> i = start.getNode().getChildren(start.getPosition()); i.hasNext();) {
+                NodeAndPosition<ParsedNode> nap = i.next();
+                String inner = calculateIndent(el, nap, startIC.getForChild(nap.getNode()), doc);
+                if (inner != null) {
+                    return inner;
+                }
+            }
+            try {
+                return startIC.getCurIndent(doc.getText(pos, 1).charAt(0));
+            }
+            catch (BadLocationException e) {
+                return "";
+            }
+        }
+        else {
+            return null;
+        }
+    }
+
+    /**
+     * Loops through the children of the specified {@link root} to look for methods
+     * that have no space between them, then recursively looks at the children
+     * to see if they have any inner methods.
+     *
+     * <p>When it does identify two methods with no gap in between them it adds
+     * a new {@link DocumentAddLineAction} object with the current position
+     * to the {@link updates} list.
+     * @param root      Node to look inside of.
+     * @param map       Map of the document used to get the lines of the method.
+     * @param updates   List to update with new actions where needed.
+     * @param startPos  Start of document region to scan
+     * @param endPos    End of document region to scan
+     */
+    private static void checkMethodSpacing(NodeAndPosition<ParsedNode> root, Element map,
+            List<DocumentAction> updates, int startPos, int endPos)
+    {
+        NodeAndPosition<ParsedNode> current = null;
+        NodeAndPosition<ParsedNode> next = null;
+        for (Iterator<NodeAndPosition<ParsedNode>> i = root.getNode().getChildren(root.getPosition()); i.hasNext();) {
+            next = i.next();
+            if (current != null && 
+                    current.getNode().getNodeType() == ParsedNode.NODETYPE_METHODDEF &&
+                    current.getNode().getNodeType() == next.getNode().getNodeType()) {
+                int currentLine = map.getElementIndex(current.getEnd() - 1);
+                int nextLine = map.getElementIndex(next.getPosition());
+                
+                if (next.getPosition() >= startPos && next.getPosition() <= endPos) {
+                    if ((currentLine + 1) == nextLine) {
+                        updates.add(0, new DocumentAddLineAction(next.getPosition()));
+                    } else if ((currentLine == nextLine)) {
+                        updates.add(0, new DocumentAddLineAction(next.getPosition(), true));
+                    }
+                }
+                else if (current.getEnd() >= startPos && current.getEnd() <= endPos) {
+                    if ((currentLine + 1) == nextLine) {
+                        updates.add(0, new DocumentAddLineAction(current.getEnd()));
+                    } else if ((currentLine == nextLine)) {
+                        updates.add(0, new DocumentAddLineAction(current.getEnd(), true));
+                    }
+                }
+            }
+            current = next;
+            if (current.getPosition() > endPos) {
+                return;
+            }
+            checkMethodSpacing(current, map, updates, startPos, endPos);
+        }
+    }
+    
+    // ---------------------------------------
+    // Indent calculation:
+    
+
+    /**
+     * An interface that calculates the indentation level that
+     * the corresponding node should have.  You should use getForChild as you
+     * descend the parse tree to get the indentation for child nodes.
+     */
+    private static interface IndentCalculator
+    {
+        /**
+         * Gets the IndentCalculator for the given child node of the node that this
+         * IndentCalculator instance corresponds to
+         */
+        public IndentCalculator getForChild(ParsedNode n);
+        /**
+         * Gets the indent for a line in the current node that begins with the
+         * given character.  This allows for comments (such as this one right here)
+         * to have their leading asterisks indented by an extra space. 
+         */
+        public String getCurIndent(char beginsWith);
+    }
+    
+    /**
+     * An implementation of IndentCalculator for the root node of the document.
+     */
+    private static class RootIndentCalculator implements IndentCalculator
+    {
+        public IndentCalculator getForChild(ParsedNode n)
+        {
+            return new NodeIndentCalculator("", n);
+        }
+
+        public String getCurIndent(char beginsWith)
+        {
+            return "";
+        }
+    }
+    
+    /**
+     * An implementation of IndentCalculator for a non-root node of the document.
+     */
+    private static class NodeIndentCalculator implements IndentCalculator
+    {
+        private final String existingIndent;
+        private final ParsedNode parent;
+        
+        private static final int tabSize = Config.getPropInteger("bluej.editor.tabsize", 4);
+        private static final String spaces =
+            "                                                                                   ";
+
+        private final static String STANDARD_INDENT = spaces.substring(0, tabSize);
+        private final static String CONTINUATION_INDENT = STANDARD_INDENT;
+        // To make it line up like this:
+        // /**
+        //  *
+        //  *
+        //  */
+        // This must be a single space:
+        private final static String COMMENT_ASTERISK_INDENT = " ";
+
+        public NodeIndentCalculator(String existingIndent, ParsedNode parent)
+        {
+            this.existingIndent = existingIndent;
+            this.parent = parent;
+        }
+
+        public IndentCalculator getForChild(ParsedNode child)
+        {
+            String newIndent = existingIndent;
+
+            if (child.isInner()) {
+                newIndent += STANDARD_INDENT;
+            }
+            else if (! child.isContainer() && ! parent.isContainer() && ! parent.isInner()) {
+                newIndent += CONTINUATION_INDENT;
+            }
+
+            return new NodeIndentCalculator(newIndent, child);
+        }
+
+        public String getCurIndent(char beginsWith)
+        {
+            if (parent.getNodeType() == ParsedNode.NODETYPE_COMMENT && beginsWith == '*') {
+                return existingIndent + COMMENT_ASTERISK_INDENT;
+            }
+            else {
+                return existingIndent;
+            }
+        }
+    }
+
+
+    /**
+     * Interface representing some document editing action.
+     */
+    private interface DocumentAction
+    {
+        /**
+         * Apply the edit represented by this DocumentAction to the document, and return the
+         * adjusted caret position.
+         */
+        public int apply(MoeSyntaxDocument doc, int prevCaretPos);
+    }
+
+    /**
+     * A class representing an update to the indentation on a line of the document.  This is different
+     * to a LineAction because it intrinsically knows which line it needs to update
+     */
+    private static class DocumentIndentAction implements DocumentAction
+    {
+        private Element el;
+        private String indent;
+
+        public DocumentIndentAction(Element el, String indent)
+        {
+            this.el = el;
+            this.indent = indent;
+        }
+
+        // Because we keep element references, we don't have to worry about the offsets
+        // altering, because they will alter before we process the line, and thus
+        // everything works nicely.
+        public int apply(MoeSyntaxDocument doc, int caretPos)
+        {
+            int spos = el.getStartOffset();
+            int ll = doc.getDefaultRootElement().getElementIndex(spos);
+            if (doc.getDefaultRootElement().getElement(ll) != el) {
+                System.out.println("Element mismatch!!!!");
+            }
+            
+            String line = getElementContents(doc, el);
+            int lengthPrevWhitespace = findFirstNonIndentChar(line, true);
+            boolean anyTabs = line.substring(0, lengthPrevWhitespace).indexOf("\t") != -1;
+            // If we want to put in 4 spaces, and there are already exactly 4 tabs,
+            // without the anyTabs check, we would leave the whitespace alone;
+            // hence why we need the check:
+            if (indent != null && (anyTabs || (indent.length() != lengthPrevWhitespace))) {
+                try {
+                    int origStartOffset = el.getStartOffset(); 
+                    doc.replace(el.getStartOffset(), lengthPrevWhitespace,
+                            indent, null);
+                    
+                    if (caretPos < origStartOffset) {
+                        return caretPos; // before us, not moved
+                    } else if (caretPos >= origStartOffset + lengthPrevWhitespace) {
+                        int changeLength = indent.length() - lengthPrevWhitespace;
+                        return caretPos + changeLength; // after us, move by the change length
+                    } else {
+                        return origStartOffset + indent.length(); // in us, move to end of indent
+                    }
+                }
+                catch (BadLocationException e) {
+                    Debug.reportError("Error doing indent in DocumentUpdate", e);
+                    return caretPos;
+                }
+            } else {
+                return caretPos;
+            }
+        }
+    }
+
+    /**
+     * Get the textual contents of a document element (i.e. a line). 
+     */
+    private static String getElementContents(MoeSyntaxDocument doc, Element el)
+    {
+        try {
+            return doc.getText(el.getStartOffset(), el.getEndOffset() - el.getStartOffset());
+        } catch (BadLocationException e) {
+            Debug.reportError("Error getting element contents in document", e);
+            return "";
+        }
+    }
+
+    /**
+     * Return true if s contains only whitespace (or nothing).
+     */
+    public static boolean isWhiteSpaceOnly(String s)
+    {
+        return s.trim().length() == 0;
+    }
+
+    /**
+     * Find the position of the first non-indentation character in a string.
+     * Indentation characters are [whitespace], //, *, /*, /**.
+     */
+    public static int findFirstNonIndentChar(String line, boolean whitespaceOnly)
+    {
+        // if this line ends a comment, indent whitepace only;
+        // otherwise indent across whitespace, asterisks and comment starts
+        Matcher m = whitespaceOnly ? WHITESPACE_TABS.matcher(line) : WHITESPACE_TABS_STAR.matcher(line);
+        return m.find() ? m.end() : 0;
+    }
+
+    /**
+     * A document action for inserting a blank line in the document.
+     */
+    private static class DocumentAddLineAction implements DocumentAction
+    {
+        private int position;
+        private boolean twoSeparators;
+        
+        public DocumentAddLineAction(int position)
+        {
+            this(position, false);
+        }
+
+        public DocumentAddLineAction(int position, boolean twoSeparators)
+        {
+            this.position = position;
+            this.twoSeparators = twoSeparators;
+        }
+
+        /**
+         * Tries to insert a new line into the document at the stated position.
+         * @param doc   Document to add the new line to.
+         * @param prevCaretPos  Location to move the the cursor to after the operation
+         * @return  The caret position.
+         */
+        public int apply(MoeSyntaxDocument doc, int prevCaretPos)
+        {
+            String lineSeparator = System.getProperty("line.separator");
+            try {
+                if (twoSeparators) {
+                    doc.insertString(position, lineSeparator + lineSeparator, null);
+                } else {
+                    doc.insertString(position, lineSeparator, null);
+                }
+            } catch (BadLocationException ex) {
+                Debug.reportError("Error in adding new line to document", ex);
+            }
+            if (position > prevCaretPos) {
+                return prevCaretPos;
+            } else if (twoSeparators)  {
+                return prevCaretPos + (lineSeparator.length() * 2);
+            } else {
+                return prevCaretPos + lineSeparator.length();
+            }
+        }
+        
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoePlainView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoePlainView.java
new file mode 100644
index 0000000000000000000000000000000000000000..c402a5b37d22e636f669c7b03a6cb8d47b9a56e1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoePlainView.java
@@ -0,0 +1,456 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011,2012  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.Highlighter;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.LayeredHighlighter;
+import javax.swing.text.PlainDocument;
+import javax.swing.text.Position.Bias;
+import javax.swing.text.Segment;
+import javax.swing.text.TabExpander;
+import javax.swing.text.Utilities;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * A better, less buggy version of PlainView, with additional support for a left margin appearing
+ * before the text. This was written with reference to PlainView and emulates it to some degree.
+ * 
+ * @author Davin McCall
+ */
+public class MoePlainView extends View
+{
+    private Font currentFont;      // current font
+    protected FontMetrics metrics; // Metrics of the current font
+    private Element longestLine;   // The longest known line (or null if not currently known)
+    protected int tabSize;         // The current tab width (pixels)
+    
+    private Segment segment = new Segment();
+    
+    private int leftMargin;    // The left margin (before the text)
+    
+    /**
+     * Constructs a BetterPlainView for the specified element.
+     */
+    public MoePlainView(Element elem)
+    {
+        super(elem);
+    }
+    
+    /**
+     * Constructs a BetterPlainView for the specified element, and with the specified left margin.
+     */
+    public MoePlainView(Element elem, int leftMargin)
+    {
+        super(elem);
+        this.leftMargin = leftMargin;
+    }
+
+    @Override
+    public float getPreferredSpan(int axis)
+    {
+        checkMetrics();
+        switch (axis) {
+        case View.X_AXIS:
+            return getLineWidth(getLongestLine()) + leftMargin;
+        case View.Y_AXIS:
+            return getElement().getElementCount() * metrics.getHeight();
+        default:
+            return 0;
+        }
+    }
+    
+    static protected class MoeTabExpander implements TabExpander
+    {
+        private int tabSize;
+        private int leftMargin;
+        
+        public MoeTabExpander(int tabSize, int leftMargin)
+        {
+            this.tabSize = tabSize;
+            this.leftMargin = leftMargin;
+        }
+        
+        @Override
+        public float nextTabStop(float x, int tabOffset)
+        {
+            if (tabSize == 0) {
+                return x;
+            }
+            int ntabs = (((int) x) - leftMargin) / tabSize;
+            return leftMargin + 0 + ((ntabs + 1) * tabSize);
+        }
+    }
+    
+    @Override
+    public Shape modelToView(int pos, final Shape a, Bias b)
+            throws BadLocationException
+    {
+        checkMetrics();
+        Element map = getElement();
+        int lineIndex = map.getElementIndex(pos);
+        Element line = map.getElement(lineIndex);
+        
+        // Get the text in the line, up to the given point
+        Segment s = segment;
+        Document doc = getDocument();
+        doc.getText(line.getStartOffset(), pos - line.getStartOffset(), s);
+        
+        TabExpander tabExpander = new MoeTabExpander(tabSize, leftMargin);
+        
+        // Note that PlainView always returns a rectangle of width 1, at the start of the
+        // character position, which is what the highlight painters expect; So, even though it seems
+        // more correct to return a rectangle containing the entire character, we also just return
+        // a rectangle of width 1.
+        int tpos = Utilities.getTabbedTextWidth(s, metrics, leftMargin, tabExpander, line.getStartOffset());
+        tpos += leftMargin;
+        Rectangle aBounds = a.getBounds();
+        return new Rectangle(aBounds.x + tpos, aBounds.y + lineIndex * metrics.getHeight(), 1, metrics.getHeight());
+    }
+        
+    @Override
+    public int viewToModel(float x, float y, Shape a, Bias[] biasReturn)
+    {
+        checkMetrics();
+        Rectangle aBounds = a.getBounds();
+        
+        if (y < aBounds.y) {
+            biasReturn[0] = Bias.Forward;
+            return 0;
+        }
+        else if (y > aBounds.height + aBounds.y) {
+            biasReturn[0] = Bias.Backward;
+            return getDocument().getLength();
+        }
+        
+        // Otherwise, the y-point represents a line:
+        int lindex = ((int) y - aBounds.y) / metrics.getHeight();
+        if (lindex >= getElement().getElementCount()) {
+            biasReturn[0] = Bias.Backward;
+            return getDocument().getLength();
+        }
+        else if (lindex < 0) {
+            biasReturn[0] = Bias.Forward;
+            return 0;
+        }
+        
+        Element line = getElement().getElement(lindex);
+        
+        if (x <= aBounds.x) {
+            biasReturn[0] = Bias.Forward;
+            return line.getStartOffset();
+        }
+        else if (x > aBounds.x + aBounds.width) {
+            biasReturn[0] = Bias.Backward;
+            return line.getEndOffset() - 1;
+        }
+        
+        Segment s = segment;
+        int lineStart = line.getStartOffset();
+        try {
+            getDocument().getText(lineStart, line.getEndOffset() - lineStart - 1, s);
+        }
+        catch (BadLocationException ble) {
+            // can't happen...??
+            throw new RuntimeException(ble);
+        }
+        
+        TabExpander tx = new MoeTabExpander(tabSize, leftMargin);
+        int offset = Utilities.getTabbedTextOffset(s, metrics, leftMargin, (int)x - aBounds.x, tx, lineStart);
+        
+        biasReturn[0] = Bias.Forward;
+        return Math.min(lineStart + offset, getDocument().getLength());
+    }
+    
+    @Override
+    public void paint(Graphics g, Shape allocation)
+    {
+        checkMetrics();
+        
+        // Paint the text lines, 
+        // and the highlights.
+        
+        JTextComponent host = (JTextComponent) getContainer();
+        Highlighter h = host.getHighlighter();
+        g.setFont(host.getFont());
+        
+        Rectangle clip = g.getClipBounds();
+        Rectangle abounds = allocation.getBounds();
+        
+        int topLine = (clip.y - abounds.y) / metrics.getHeight();
+        int bottomLine = (clip.y + clip.height - abounds.y) / metrics.getHeight();
+        int maxLine = getElement().getElementCount() - 1;
+        
+        LayeredHighlighter lh = (h instanceof LayeredHighlighter) ? (LayeredHighlighter) h : null;
+        
+        if (topLine > maxLine || bottomLine < 0) {
+            return;
+        }
+        
+        bottomLine = Math.min(bottomLine, maxLine);
+        topLine = Math.max(topLine, 0);
+        
+        int mheight = metrics.getHeight();
+        int ypos = abounds.y + topLine * mheight;
+        int textBase = metrics.getAscent();
+        
+        g.setColor(getTextColor());
+        g.setFont(host.getFont());
+        for (int i = topLine; i <= bottomLine; i++) {
+            Element line = getElement().getElement(i);
+            if (lh != null) {
+                // Set up a clip region for just the current line. Stops MoeHighlighter from painting the
+                // highlights over other lines.
+                Rectangle lineClip = new Rectangle(abounds.x, ypos, abounds.width, mheight);
+                Rectangle.intersect(lineClip, clip, lineClip);
+                g.setClip(lineClip);
+                lh.paintLayeredHighlights(g, line.getStartOffset(), line.getEndOffset() - 1, allocation, host, this);
+            }
+            drawLine(i, g, abounds.x + leftMargin, ypos + textBase);
+            ypos += mheight;
+        }
+        g.setClip(clip); // restore original clip bounds
+    }
+    
+    /**
+     * Get the colour for drawing text.
+     */
+    protected Color getTextColor()
+    {
+        JTextComponent host = (JTextComponent) getContainer();
+        return (host.isEnabled()) ? host.getForeground() : host.getDisabledTextColor();
+    }
+    
+    /**
+     * Draw a line of text.
+     * @param lineIndex  The line number
+     * @param g          The graphics context on which to draw
+     * @param x          The x-position
+     * @param y          The y-position (of the text baseline)
+     */
+    protected void drawLine(int lineIndex, Graphics g, int x, int y)
+    {
+        try {
+            Element line = getElement().getElement(lineIndex);
+            getDocument().getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset(), segment);
+            TabExpander tx = new MoeTabExpander(tabSize, x);
+            Utilities.drawTabbedText(segment, x, y, g, tx, line.getStartOffset());
+        }
+        catch (BadLocationException ble) {
+            throw new RuntimeException(ble);
+        }
+    }
+    
+    /**
+     * Make sure font metrics information cached by the view is up-to-date.
+     */
+    protected void checkMetrics()
+    {
+        Component host = getContainer();
+        Font f = host.getFont();
+        if (currentFont != f) {
+            // The font changed, we need to recalculate the
+            // longest line.
+            currentFont = f;
+            metrics = getContainer().getFontMetrics(currentFont);
+            longestLine = null;
+            tabSize = getTabSize() * metrics.charWidth('m');
+        }
+    }
+    
+    /**
+     * Get the width of the given line, not counting margins.
+     */
+    protected int getLineWidth(Element line)
+    {
+        try {
+            getDocument().getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset(), segment);
+            TabExpander tx = new MoeTabExpander(tabSize, leftMargin);
+            int width = Utilities.getTabbedTextWidth(segment, metrics, leftMargin, tx, line.getStartOffset());
+            return width;
+        }
+        catch (BadLocationException ble) {
+            throw new RuntimeException(ble);
+        }
+    }
+    
+    /**
+     * Get the longest line element (find it first if necessary).
+     */
+    private Element getLongestLine()
+    {
+        if (longestLine == null) {
+            determineLongestLine();
+        }
+        return longestLine;
+    }
+    
+    /**
+     * Determine which line is the longest line, and store in {@code longestLine}.
+     */
+    private void determineLongestLine()
+    {
+        Element rootElement = getElement();
+        int lineCount = rootElement.getElementCount();
+        
+        longestLine = null;
+        int maxLineWidth = -1;
+        
+        for (int i = 0; i < lineCount; i++) {
+            Element line = rootElement.getElement(i);
+            int lineWidth = getLineWidth(line);
+            if (lineWidth > maxLineWidth) {
+                longestLine = line;
+                maxLineWidth = lineWidth;
+            }
+        }
+    }
+
+    /**
+     * Get the tab size (in characters), according to the appropriate document attribute.
+     */
+    protected int getTabSize()
+    {
+        Integer i = (Integer) getDocument().getProperty(PlainDocument.tabSizeAttribute);
+        return (i != null) ? i.intValue() : 8;
+    }
+    
+    /**
+     * Mark an (inclusive) line range as in need of repaint.
+     * 
+     * @param line0   The lowest damaged line number
+     * @param line1   The highest damaged line number >= line0
+     * @param a       The view allocation
+     * @param host    The component hosting the view
+     */
+    protected void damageLineRange(int line0, int line1, Shape a, Component host)
+    {
+        if (line1 < line0 || a == null) {
+            return;
+        }
+
+        Rectangle abounds = a.getBounds();
+        int rx = abounds.x;
+        int ry = abounds.y + line0 * metrics.getHeight();
+        int rw = abounds.width;
+        int rh = (line1 - line0 + 1) * metrics.getHeight();
+        
+        host.repaint(rx, ry, rw, rh);
+    }
+
+    /**
+     * Mark the appropriate areas as needing a repaint after changes to the document.
+     */
+    protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f)
+    {
+        checkMetrics();
+        Component host = getContainer();
+        Element elem = getElement();
+        
+        DocumentEvent.ElementChange ec = changes.getChange(elem);
+        Element[] added = (ec != null) ? ec.getChildrenAdded() : null;
+        Element[] removed = (ec != null) ? ec.getChildrenRemoved() : null;
+        
+        if (((added != null) && (added.length > 0)) || 
+            ((removed != null) && (removed.length > 0))) {
+            // lines were added or removed...
+            if (added != null && longestLine != null) {
+                int currentMaxWidth = getLineWidth(longestLine);
+                for (int i = 0; i < added.length; i++) {
+                    int width = getLineWidth(added[i]);
+                    if (width > currentMaxWidth) {
+                        currentMaxWidth = width;
+                        longestLine = added[i];
+                    }
+                }
+            }
+            if (removed != null) {
+                for (int i = 0; i < removed.length; i++) {
+                    if (removed[i] == longestLine) {
+                        longestLine = null;
+                        break;
+                    }
+                }
+            }
+            preferenceChanged(null, true, true);
+            host.repaint();
+        } else {
+            // No elements (lines) were added or removed; the change might be an insert/remove confined
+            // to a single line.
+            Element map = getElement();
+            int line = map.getElementIndex(changes.getOffset());
+            int endLine = map.getElementIndex(changes.getOffset() + changes.getLength());
+            damageLineRange(line, endLine, a, host);
+            
+            getLongestLine();
+            if (changes.getType() == DocumentEvent.EventType.INSERT) {
+                // check to see if the line is longer than current
+                // longest line.
+                int w = getLineWidth(longestLine);
+                Element e = map.getElement(line);
+                if (e == longestLine) {
+                    preferenceChanged(null, true, false);
+                } else if (getLineWidth(e) > w) {
+                    longestLine = e;
+                    preferenceChanged(null, true, false);
+                }
+            } else if (changes.getType() == DocumentEvent.EventType.REMOVE) {
+                if (map.getElement(line) == longestLine) {
+                    // removed from longest line... recalc
+                    determineLongestLine();
+                    preferenceChanged(null, true, false);
+                }                       
+            }
+        }
+    }
+    
+    @Override
+    public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f)
+    {
+        updateDamage(changes, a, f);
+    }
+
+    @Override
+    public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f)
+    {
+        updateDamage(changes, a, f);
+    }
+
+    @Override
+    public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f)
+    {
+        updateDamage(changes, a, f);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoePrinter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoePrinter.java
new file mode 100644
index 0000000000000000000000000000000000000000..0078f63f6c549789ae5b6fe0e40ef3c056a21c00
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoePrinter.java
@@ -0,0 +1,554 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.awt.print.*;
+import java.awt.Graphics;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.print.PrinterJob;
+
+import javax.swing.text.*;
+
+import java.util.*;
+import java.util.stream.IntStream;
+import java.text.DateFormat;
+
+import bluej.utility.Debug;
+import bluej.utility.Utility;
+import bluej.Config;
+
+
+/**
+ * Class to handle printing for the MoeEditor.
+ * This borrows ideas and some source code from Andrew Weiland's Print example
+ * at http://www.wam.umd.edu/~aweiland/Print.java.  Which no longer exists..
+ *
+ * @author Bruce Quig
+ */
+public class MoePrinter
+{
+    static final String CONTINUED_LABEL = Config.getString("editor.printer.continued");
+    private final int HEADER_SPACE = 30;
+    private final int FOOTER_SPACE = 20;
+    private final int LINE_NUMBER_WIDTH = 20;
+    private final int PADDING = 5;
+    
+    private Book pages = new Book();  // This holds each page
+    
+    private static int titleFontSize = Config.getPropInteger("bluej.fontsize.printTitle", 14);
+    private static Font titleFont = new Font("SansSerif", Font.BOLD, titleFontSize);
+    private static Font smallTitleFont = new Font("SansSerif", Font.BOLD, 10);
+    private static Font footerFont = new Font("SansSerif", Font.ITALIC, 9);
+    private static Font lineNumberFont = new Font("SansSerif", Font.PLAIN, 6);
+     
+    private String className;
+    private int tabSize = Config.getPropInteger("bluej.editor.tabsize", 4); 
+
+    /**
+     * Default constructor
+     */
+    public MoePrinter()
+    {
+        // nothing yet
+    }
+
+    /**
+     * Prints the document.  This method produces a copy of the document 
+     * as a List of Strings and delegates the printing to a printText method.
+     *
+     * @returns   true if it was not cancelled.
+     */
+    public boolean printDocument(PrinterJob printJob, MoeSyntaxDocument document, boolean lineNumbers, boolean syntaxHighlighting,
+                                 String className, Font font, PageFormat format) 
+    {
+        List<PrintLine> lines = new ArrayList<PrintLine>();
+
+        this.className = className;
+        // extract tabsize attribute from document and assign to tabSize attribute
+        Integer tabSizeAsInteger =  (Integer)document.getProperty(PlainDocument.tabSizeAttribute);
+        if(tabSizeAsInteger != null)
+            tabSize = tabSizeAsInteger.intValue();
+
+        try{
+            // read lock the document while reading to avoid any subsequent edits
+            // unlikely to happen due to the speed at which the document is read
+            document.readLock();
+
+            //  Get Root element of the document
+            Element root = document.getDefaultRootElement();
+            //get the number of lines (i.e. child elements)
+            int count = root.getElementCount();
+            // Get each line element, get its text and put it in the string list
+            for (int i = 0; i < count; i++) {
+                Element lineElement = (Element)root.getElement(i);
+                lines.add(removeNewLines(new PrintLine(document, lineElement, i+1)));
+            }
+        }
+        // make sure that read lock is removed
+        finally {
+            document.readUnlock();
+        }
+
+        return printText(printJob, lines, font, document, lineNumbers, syntaxHighlighting, format);
+    }
+
+
+    /**
+     * Remove newline and carriage return characters from the end 
+     * of this string. This is needed to fix a printing bug with 
+     * the handling of newline characters on some printers
+     * 
+     * Having trailing spaces in the comments also seems to screw up
+     * the spacing when printing with syntax highlighting, so we remove
+     * them too.
+     */
+    private PrintLine removeNewLines(PrintLine line)
+    {
+        int length = line.length();
+        char lastChar = (length > 0 ? line.charAt(line.length()-1) : 'a');
+
+        while((lastChar == '\n') || (lastChar == '\r') || (lastChar == ' ') || (lastChar == '\t')) {
+            
+            line.chopLast();
+            length = line.length();
+            lastChar = (length > 0 ? line.charAt(line.length()-1) : 'a');
+        }
+        return line;
+    }
+
+
+    /**
+     * Prints the text.  It sets paper size (at present) and paginates text
+     * into a pageable Book for printing.
+     *
+     * @returns   true if it was not cancelled.
+     */
+    private synchronized boolean printText(PrinterJob job, List<PrintLine> text, Font font, MoeSyntaxDocument document, boolean lineNumbers, boolean syntaxHighlighting, PageFormat format) 
+    {
+        try {
+            pages = paginateText(text, format, document, lineNumbers, syntaxHighlighting, font);        
+
+            // set the book pageable so the printjob knows 
+            // we are printing more than one page (maybe)
+            job.setPageable(pages);
+            job.print();
+                
+                return true;
+        }
+        catch (Exception e) {
+            // should it be an error dialog?
+            Debug.reportError("Exception thrown during printing: " + e);
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    /**
+     * The pagination method.  Paginate the text onto Printable page objects.
+     * This includes wrapping long lines of text.
+     */   
+    private Book paginateText(List<PrintLine> text, PageFormat pageFormat, MoeSyntaxDocument document, boolean lineNumbers, boolean syntaxHighlighting, Font font) 
+    {
+        Book book = new Book();
+        int pageNum = 1;        // page #
+
+        // height of text area of a page
+        int height = (int)pageFormat.getImageableHeight() - (HEADER_SPACE + FOOTER_SPACE);
+
+        // number of lines on a page
+        int linesPerPage = height / (font.getSize() + 2);   
+        wrapLines(text, pageFormat, lineNumbers, font);
+
+        // set number of pages
+        int numberOfPages = ((int)(text.size() / linesPerPage)) + 1;  
+
+        List<PrintLine> pageText;      // one page of text
+
+        ListIterator<PrintLine> li = text.listIterator();
+        while ( pageNum <= numberOfPages) {
+            pageText = new ArrayList<PrintLine>(); 
+
+            for (int lineCount = 0; li.hasNext() && lineCount < linesPerPage; lineCount++) { 
+                pageText.add(li.next());
+            }
+        
+            // create a new page object with the text and add it to the book
+            book.append(new MoePage(pageText, document, lineNumbers, syntaxHighlighting, font), pageFormat);  
+            pageNum++;   // increase the page number I am on
+        }
+        return book;  // return the completed book
+    }
+
+
+    /**
+     * Wraps lines so that long lines of text outside of print page dimensions for a 
+     * given page format and font are printed as a new line.  This method iterates 
+     * through each line of text, calculates if there is an overlap and inserts 
+     * overlapping text on the next line.
+     */
+    private void wrapLines(List<PrintLine> text, PageFormat format, boolean lineNumbers, Font font)
+    {
+        // code to wrap lines of text for printing
+        // get a line, get its length, do some font metrics,
+        StyleContext context = new StyleContext();
+        FontMetrics fontMetrics = context.getFontMetrics(font);
+        int maxWidth = (int)format.getImageableWidth() - (PADDING * 2);
+        if (lineNumbers)
+        {
+            maxWidth -= LINE_NUMBER_WIDTH;
+        }
+        int fontWidth = fontMetrics.charWidth('m');           
+        int chars = maxWidth / fontWidth;
+
+        for(ListIterator<PrintLine> li = text.listIterator(); li.hasNext(); ) {
+            PrintLine pl = li.next();
+            String currentLine = Utility.convertTabsToSpaces(pl.toString(), tabSize);
+            int currentLineLength = currentLine.length();
+            int width = fontMetrics.stringWidth(currentLine);
+            
+            // if line needs to be wrapped
+            if(width > maxWidth) {
+                int[] tabSpaces = Utility.calculateTabSpaces(pl.toString(), tabSize);
+                // remove original
+                li.remove();
+                double iterations = (currentLineLength / chars) + 1;
+                for(int begin = 0, end = 0; iterations > 0; iterations--, begin = Utility.advanceChars(pl.toString(),tabSpaces,begin,chars)) {
+                    end = Utility.advanceChars(pl.toString(),tabSpaces,begin,chars);
+                    
+                    PrintLine newSubString = pl.substring(begin, end);
+                    if(newSubString.length() != 0)
+                    {
+                        li.add(newSubString);
+                    }
+                }
+            }
+        }
+    }
+      
+    /* An inner class that defines one page of text based
+     * on data about the PageFormat etc. from the book defined
+     * in the parent class
+     */                         
+    class MoePage implements Printable 
+    { 
+        private List<PrintLine> text;  // the text for the page
+        private MoeSyntaxDocument document;
+        private boolean lineNumbers;
+        private boolean syntaxHighlighting;
+        private Font font;
+
+        MoePage(List<PrintLine> text, MoeSyntaxDocument document, boolean lineNumbers, boolean syntaxHighlighting, Font font) 
+        {
+            this.text = text;  // set the page's text
+            this.font = font;  // set the page's font
+            this.document = document;
+            this.lineNumbers = lineNumbers; // whether to print line numbers
+            this.syntaxHighlighting = syntaxHighlighting; // whether to print with syntax highlighting
+        }
+        
+        /** 
+         * Method that implements Printable interface.   
+         * 
+         */       
+        public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException 
+        { 
+            // the printing part
+            int position;
+            g.setFont(this.font);     // Set the font
+            g.setColor(Color.black);  // set color
+
+            // get co-ordinates for frame
+            int xPosition = (int)pageFormat.getImageableX(); 
+            int yPosition = (int)pageFormat.getImageableY();
+            int width = (int)pageFormat.getImageableWidth();
+            int height = (int)pageFormat.getImageableHeight();
+            
+            // Get some style information:
+            StyleContext context = new StyleContext();
+            final FontMetrics fontMetrics = context.getFontMetrics(font);
+            Color[] colors = MoeSyntaxDocument.getColors();
+            Color def = Color.black;
+
+            // print a header
+            printHeader(g, pageIndex, xPosition, yPosition, width, HEADER_SPACE);
+
+            // print main text area
+            int textYPosition = yPosition + HEADER_SPACE;
+            int textXPosition = xPosition + PADDING + (lineNumbers ? LINE_NUMBER_WIDTH : 0);
+            g.drawRect(xPosition, textYPosition, width, height - (HEADER_SPACE + FOOTER_SPACE));
+            
+            int lineNumberXPosition = xPosition + PADDING;
+            int lastLineNumber = 0;
+            if (lineNumbers)
+            {
+                //The vertical line dividing the line numbers from the code:
+                g.drawLine(xPosition + LINE_NUMBER_WIDTH, textYPosition
+                          ,xPosition + LINE_NUMBER_WIDTH, yPosition + height - FOOTER_SPACE);
+            }
+            
+            
+            // print the text
+            for(ListIterator<PrintLine> li = text.listIterator(); li.hasNext(); ) {
+                position = textYPosition + (this.font.getSize() + 2) * (li.nextIndex() + 1);
+                PrintLine line = li.next();
+                
+                if (lineNumbers && line.getLineNumber() != lastLineNumber)
+                {
+                    g.setColor(Color.black);
+                    g.setFont(lineNumberFont);
+                    g.drawString(Integer.toString(line.getLineNumber()), lineNumberXPosition, position);
+                    lastLineNumber = line.getLineNumber();
+                    g.setFont(font);
+                }
+                
+                int x = textXPosition;
+                
+                Token tokens = document.getParser().getMarkTokensFor(line.getStartOffset(), Math.min(line.getEndOffset(),document.getLength()) - line.getStartOffset(), 0, document);
+                int offset = 0;
+                while (tokens.id != Token.END) {
+                    byte id = tokens.id;
+                    
+                    int length = tokens.length;
+                    Color color;
+                    if(id == Token.NULL)
+                        color = def;
+                    else {
+                        // check we are within the array bounds
+                        // safeguard for updated syntax package
+                        if(id < colors.length)
+                            color = colors[id];
+                        else color = def;
+                    }
+                    if (syntaxHighlighting)
+                    {
+                        g.setColor(color == null ? def : color);
+                    }
+
+                    Segment lineSeg = line.getSegment();
+                    lineSeg.count = length;
+                    lineSeg.offset += offset;
+                    
+                    // workaround for strange problem on Mac:
+                    // trying to print empty lines throws exception
+                    if (lineSeg.count == 0) {
+                        char[] chars = new char[]{' '};
+                        Segment nonBlank = new Segment(chars,0,1);
+                        x = Utilities.drawTabbedText(nonBlank, x, position, g, null, 0);
+                    }
+                    else {
+                        TabExpander tab = Utility.makeTabExpander(lineSeg.toString(), tabSize, fontMetrics);
+                        x = Utilities.drawTabbedText(lineSeg,x,position,g,tab,offset);
+                    }
+                    offset += length;
+                    tokens = tokens.next;
+                } 
+            }
+
+            // print footer
+            int footerYPosition = yPosition + height - FOOTER_SPACE;
+            printFooter(g, xPosition, footerYPosition, width, FOOTER_SPACE); 
+    
+            return Printable.PAGE_EXISTS;   // print the page
+        }       
+        
+        /**
+         * Prints a header box on a page, including a title and page number.
+         */
+        private void printHeader(Graphics g, int pageIndex, int xPos, int yPos, int width, int height) 
+        {
+            // draw title box
+            g.setColor(Color.lightGray);
+            g.fillRect(xPos, yPos, width, height);
+            g.setColor(Color.black);  // set color
+            g.drawRect(xPos, yPos, width, height);
+            int titleYPos = yPos + HEADER_SPACE - this.font.getSize() + 2;
+            String title = "Class " + className;
+
+            // print class name on left
+            // if first page make title bigger
+            if(pageIndex == 0) 
+                g.setFont(titleFont);
+            else {
+                // don't add (continued) if there is no definition
+                if(!"".equals(CONTINUED_LABEL) 
+                   && !"editor.printer.continued".equals(CONTINUED_LABEL))
+                    title = title + " (" + CONTINUED_LABEL + ")";
+                g.setFont(smallTitleFont);
+            }
+            // print class name
+            g.drawString(title, xPos + PADDING, titleYPos); 
+
+            // set to smaller title font for page number
+            g.setFont(smallTitleFont);
+            FontMetrics pfm = g.getFontMetrics(smallTitleFont);
+            // print page number on right
+            String pageInfo = (pageIndex + 1) + "/" + pages.getNumberOfPages();
+            int pageInfoX = xPos + width - PADDING - pfm.stringWidth(pageInfo);
+            g.drawString(pageInfo, pageInfoX, titleYPos);
+            g.setFont(font);
+
+        }
+
+        /**
+         * Prints a footer box on a page that shows the print date.
+         */
+        private void printFooter(Graphics g, int xPos, int yPos, int width, int height) 
+        {
+            // set up font and text position
+            g.setFont(footerFont);
+            FontMetrics pfm = g.getFontMetrics(footerFont);
+            int footerTextYPos = yPos + FOOTER_SPACE - this.font.getSize() + 2;
+        
+            // package name not shown at present
+            //g.drawString("Package: " + className, xPos + PADDING, footerTextYPos);  
+         
+            // print date on right
+            Date today = new Date();
+            DateFormat dateFormat = DateFormat.getDateTimeInstance();
+            String date = dateFormat.format(today);
+            int pageInfoX = xPos + width - PADDING - pfm.stringWidth(date);
+            g.drawString(date, pageInfoX, footerTextYPos);
+            //set font back to original
+            g.setFont(font);
+
+        }
+    
+    }
+    
+    /**
+     * A class that is something like a Segment, but references a MoeSyntaxDocument
+     * rather than simply a char[] like Segment does.
+     *  
+     * @author Neil Brown
+     *
+     */
+    private class PrintLine implements CharSequence
+    {
+        @Override
+      public IntStream chars() {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      public IntStream codePoints() {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+        private MoeSyntaxDocument document;
+        private int startOffset;
+        private int endOffset;
+        private int lineNumber;
+
+        public PrintLine(MoeSyntaxDocument document, int startOffset,
+                int endOffset, int lineNumber) {
+            this.document = document;
+            this.startOffset = startOffset;
+            this.endOffset = endOffset;
+            this.lineNumber = lineNumber;
+        }
+        
+        public PrintLine(MoeSyntaxDocument document, Element e, int lineNumber) {
+            this.document = document;
+            this.startOffset = e.getStartOffset();
+            this.endOffset = e.getEndOffset();
+            this.lineNumber = lineNumber;
+        }
+
+        public int getStartOffset() {
+            return startOffset;
+        }
+        
+        public int getEndOffset() {
+            return endOffset;
+        }
+
+        public int getLineNumber() {
+            return lineNumber;
+        }
+        
+        public int length() {
+            return endOffset - startOffset;
+        }
+        
+        @Override
+        public String toString() {
+            try
+            {
+                if (length() == 0)
+                {
+                    return "";
+                }
+                else
+                {
+                    return document.getText(startOffset, length());
+                }
+            }
+            catch (BadLocationException e)
+            {
+                Debug.reportError("PrintLine.toString(), offsets: " + startOffset + " and " + endOffset, e);
+                return null;
+            }
+        }
+
+        public char charAt(int n) {
+            return toString().charAt(n);
+        }
+
+        public CharSequence subSequence(int start, int end) {
+            return toString().subSequence(start, end);
+        }
+        
+        public void chopLast()
+        {
+            if (endOffset > startOffset)
+                endOffset -= 1;
+        }
+        
+        public PrintLine substring(int begin, int end)
+        {
+            return new PrintLine(document, begin + startOffset, end + startOffset, lineNumber);
+        }
+        
+        public Segment getSegment()
+        {
+            try
+            {
+                Segment seg = new Segment();
+                document.getText(getStartOffset(), getEndOffset() - getStartOffset(), seg);
+                return seg;
+            }
+            catch (BadLocationException e)
+            {
+                Debug.reportError("PrintLine.getSegment(), offsets: " + startOffset + " and " + endOffset, e);
+                return null;
+            }
+        }
+    }
+}
+
+
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxDocument.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxDocument.java
new file mode 100644
index 0000000000000000000000000000000000000000..90b78bac370efb74eb15c20f1bc4c3fc4202bf94
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxDocument.java
@@ -0,0 +1,655 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentEvent.EventType;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.PlainDocument;
+
+import bluej.Config;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.nodes.NodeStructureListener;
+import bluej.parser.nodes.NodeTree;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+import bluej.parser.nodes.ParsedCUNode;
+import bluej.parser.nodes.ParsedNode;
+import bluej.utility.Debug;
+
+
+/**
+ * An implementation of PlainDocument, with an optional added parser to provide
+ * syntax highlighting, scope highlighting, and other advanced functionality.
+ *
+ * @author Bruce Quig
+ * @author Jo Wood (Modified to allow user-defined colours, March 2001)
+ */
+public class MoeSyntaxDocument extends PlainDocument
+{
+    private static Color[] colors = null;
+    
+    private static Color defaultColour = null;
+    private static Color backgroundColour = null;
+    
+    /** Maximum amount of document to reparse in one hit (advisory) */
+    private final static int MAX_PARSE_PIECE = 8000;
+    
+    private ParsedCUNode parsedNode;
+    private EntityResolver parentResolver;
+    private NodeTree<ReparseRecord> reparseRecordTree;
+    
+    private MoeDocumentListener listener;
+    
+    private class PendingError
+    {
+        int position;
+        int size;
+        String errCode;
+        
+        PendingError(int position, int size, String errCode)
+        {
+            this.position = position;
+            this.size = size;
+            this.errCode = errCode;
+        }
+    }
+    
+    /** A list of parse errors which have been detected but not yet indicated to the listener. */
+    private List<PendingError> pendingErrors = new LinkedList<PendingError>();
+    
+    /*
+     * We'll keep track of recent events, to aid in hunting down bugs in the event
+     * that we get an unexpected exception. 
+     */
+    
+    private static int EDIT_INSERT = 0;
+    private static int EDIT_DELETE = 1;
+    private static class EditEvent
+    {
+        int type; //  edit type - INSERT or DELETE
+        int offset;
+        int length;
+    }
+    
+    private List<EditEvent> recentEdits = new LinkedList<EditEvent>();
+    
+    private void recordEvent(DocumentEvent event)
+    {
+        int type;
+        if (event.getType() == DocumentEvent.EventType.INSERT) {
+            type = EDIT_INSERT;
+        }
+        else if (event.getType() == DocumentEvent.EventType.REMOVE) {
+            type = EDIT_DELETE;
+        }
+        else {
+            return;
+        }
+        
+        EditEvent eevent = new EditEvent();
+        eevent.type = type;
+        eevent.offset = event.getOffset();
+        eevent.length = event.getLength();
+        recentEdits.add(eevent);
+        
+        if (recentEdits.size() > 10) {
+            recentEdits.remove(0);
+        }
+    }
+    
+    /**
+     * Create an empty MoeSyntaxDocument.
+     */
+    public MoeSyntaxDocument()
+    {
+        getUserColors();
+        // defaults to 4 if cannot read property
+        int tabSize = Config.getPropInteger("bluej.editor.tabsize", 4);
+        putProperty(tabSizeAttribute, Integer.valueOf(tabSize));
+    }
+    
+    /**
+     * Create an empty MoeSyntaxDocument, which uses the given entity resolver
+     * to resolve symbols.
+     */
+    public MoeSyntaxDocument(EntityResolver parentResolver)
+    {
+        this();
+        // parsedNode = new ParsedCUNode(this);
+        this.parentResolver = parentResolver;
+        if (parentResolver != null) {
+            reparseRecordTree = new NodeTree<ReparseRecord>();
+        }
+    }
+    
+    /**
+     * Create an empty MoeSyntaxDocument, which uses the given entity resolver to
+     * resolve symbols, and which sends parser events to the specified listener.
+     */
+    public MoeSyntaxDocument(EntityResolver parentResolver, MoeDocumentListener listener)
+    {
+        this(parentResolver);
+        this.listener = listener;
+    }
+
+    /**
+     * Access the parsed node structure of this document.
+     */
+    public ParsedCUNode getParser()
+    {
+        flushReparseQueue();
+        return parsedNode;
+    }
+    
+    /**
+     * Get the current parsed node structure of the document, without processing any
+     * pending re-parse operations first.
+     */
+    public ParsedCUNode getParsedNode()
+    {
+        return parsedNode;
+    }
+    
+    /**
+     * Enable the parser. This should be called after loading a document.
+     * @param force  whether to force-enable the parser. If false, the parser will only
+     *                be enabled if an entity resolver is available.
+     */
+    public void enableParser(boolean force)
+    {
+        if (parentResolver != null || force) {
+            parsedNode = new ParsedCUNode(this);
+            parsedNode.setParentResolver(parentResolver);
+            reparseRecordTree = new NodeTree<ReparseRecord>();
+            parsedNode.textInserted(this, 0, 0, getLength(), new NodeStructureListener() {
+                public void nodeRemoved(NodeAndPosition<ParsedNode> node) { }
+                public void nodeChangedLength(NodeAndPosition<ParsedNode> node,
+                        int oldPos, int oldSize) { }
+            });
+        }
+    }
+
+    /**
+     * Run an item from the re-parse queue, if there are any. Return true if
+     * a queued re-parse was processed or false if the queue was empty.
+     */
+    public boolean pollReparseQueue()
+    {
+        return pollReparseQueue(MAX_PARSE_PIECE);
+    }
+    
+    /**
+     * Run an item from the re-parse queue, if there are any, and attempt to
+     * parse the specified amount of document (approximately). Return true if
+     * a queued re-parse was processed or false if the queue was empty.
+     */
+    public boolean pollReparseQueue(int maxParse)
+    {
+        try {
+            if (reparseRecordTree == null) {
+                return false;
+            }
+
+            NodeAndPosition<ReparseRecord> nap = reparseRecordTree.findNodeAtOrAfter(0);
+            if (nap != null) {
+                int pos = nap.getPosition();
+
+                ParsedNode pn = parsedNode;
+                int ppos = 0;
+                if (pn != null) {
+                    // Find the ParsedNode to handle the reparse.
+                    NodeAndPosition<ParsedNode> cn = pn.findNodeAt(pos, ppos);
+                    while (cn != null && cn.getEnd() == pos) {
+                        cn = cn.nextSibling();
+                    }
+                    while (cn != null && cn.getPosition() <= pos) {
+                        ppos = cn.getPosition();
+                        pn = cn.getNode();
+                        cn = pn.findNodeAt(nap.getPosition(), ppos);
+                        while (cn != null && cn.getEnd() == pos) {
+                            cn = cn.nextSibling();
+                        }
+                    }
+
+                    MoeSyntaxEvent mse = new MoeSyntaxEvent(this);
+                    pn.reparse(this, ppos, pos, maxParse, mse);
+                    fireChangedUpdate(mse);
+                    return true;
+                }
+            }
+            return false;
+        }
+        catch (RuntimeException e) {
+            
+            Debug.message("Exception during incremental parsing. Recent edits:");
+            for (EditEvent event : recentEdits) {
+                String eventStr = event.type == EDIT_INSERT ? "insert " : "delete ";
+                eventStr += "offset=" + event.offset + " length=" + event.length;
+                Debug.message(eventStr);
+            }
+            
+            try {
+                Debug.message("--- Source code ---");
+                Debug.message(getText(0, getLength()));
+                Debug.message("--- Source ends ---");
+            }
+            catch (BadLocationException ble) { }
+            
+            throw e;
+        }
+    }
+    
+    /**
+     * Process all of the re-parse queue.
+     */
+    public void flushReparseQueue()
+    {
+        while (pollReparseQueue(getLength())) ;
+    }
+    
+    /**
+     * Schedule a reparse at a certain point within the document.
+     * @param pos    The position to reparse at
+     * @param size   The reparse size. This is a minimum, rather than a maximum; that is,
+     *               the reparse when it occurs must parse at least this much.
+     */
+    public void scheduleReparse(int pos, int size)
+    {        
+        NodeAndPosition<ReparseRecord> existing = reparseRecordTree.findNodeAtOrAfter(pos);
+        if (existing != null) {
+            if (existing.getPosition() > pos && existing.getPosition() <= (pos + size)) {
+                existing.getNode().slideStart(pos - existing.getPosition());
+                return;
+            }
+            else if (existing.getPosition() <= pos) {
+                int nsize = (pos + size) - existing.getPosition();
+                if (nsize > existing.getSize()) {
+                    NodeAndPosition<ReparseRecord> next = existing.nextSibling();
+                    while (next != null && next.getPosition() <= pos + size) {
+                        nsize = Math.max(nsize, next.getEnd() - pos);
+                        NodeAndPosition<ReparseRecord> nnext = next.nextSibling();
+                        next.getNode().remove();
+                        next = nnext;
+                    }
+                    existing.getNode().setSize(nsize);
+                }
+                return;
+            }
+        }
+        
+        ReparseRecord rr = new ReparseRecord();
+        reparseRecordTree.insertNode(rr, pos, size);
+    }
+    
+    /**
+     * Mark a portion of the document as having been parsed. This removes any
+     * scheduled re-parses as appropriate and repaints the appropriate area.
+     */
+    public void markSectionParsed(int pos, int size)
+    {
+        repaintLines(pos, size);
+        
+        // We must first report the range reparsed, and then report and parse errors in the range
+        // to the listener.
+        if (listener != null) {
+            listener.reparsingRange(pos, size);
+            Iterator<PendingError> i = pendingErrors.iterator();
+            while (i.hasNext()) {
+                PendingError pe = i.next();
+                if (pe.position >= pos && pe.position <= pos + size) {
+                    listener.parseError(pe.position, pe.size, pe.errCode);
+                    i.remove();
+                }
+            }
+        }
+        
+        NodeAndPosition<ReparseRecord> existing = reparseRecordTree.findNodeAtOrAfter(pos);
+        while (existing != null && existing.getPosition() <= pos) {
+            NodeAndPosition<ReparseRecord> next = existing.nextSibling();
+            // Remove from end, or a middle portion, or the whole node
+            int rsize = existing.getEnd() - pos;
+            rsize = Math.min(rsize, size);
+            if (rsize == existing.getSize()) {
+                existing.getNode().remove();
+            }
+            else if (existing.getPosition() == pos) {
+                existing.slideStart(rsize);
+                existing = next; break;
+            }
+            else {
+                // the record begins before the point to be removed.
+                int existingEnd = existing.getEnd();
+                existing.setSize(pos - existing.getPosition());
+                // Now we may have to insert a new node, if the middle portion
+                // of the existing node was removed.
+                if (existingEnd > pos + size) {
+                    scheduleReparse(pos + size, existingEnd - (pos + size));
+                    return;
+                }
+            }
+            existing = next;
+        }
+        
+        while (existing != null && existing.getPosition() < pos + size) {
+            int rsize = pos + size - existing.getPosition();
+            if (rsize < existing.getSize()) {
+                existing.slideStart(rsize);
+                return;
+            }
+            NodeAndPosition<ReparseRecord> next = existing.nextSibling();
+            existing.getNode().remove();
+            existing = next;
+        }
+    }
+    
+    /**
+     * Inform any listeners that a parse error has occurred.
+     * 
+     * @param position   The position of the parse error
+     * @param size       The size of the erroneous portion
+     * @param message    The error message
+     */
+    public void parseError(int position, int size, String message)
+    {
+        if (listener != null) {
+            pendingErrors.add(new PendingError(position, size, message));
+        }
+    }
+    
+    /**
+     * Sets attributes for a paragraph.  This method was added to 
+     * provide the ability to replicate DefaultStyledDocument's ability to 
+     * set each lines attributes easily.
+     * This is an added method for the BlueJ adaption of jedit's Syntax
+     * package   
+     *
+     * @param offset the offset into the paragraph >= 0
+     * @param length the number of characters affected >= 0
+     * @param s the attributes
+     * @param replace whether to replace existing attributes, or merge them
+     */
+    public void setParagraphAttributes(int offset, AttributeSet s)
+    {
+        // modified version of method from DefaultStyleDocument
+        try {
+            writeLock();
+            
+            Element paragraph = getParagraphElement(offset);
+            MutableAttributeSet attr = 
+                    (MutableAttributeSet) paragraph.getAttributes();
+            attr.addAttributes(s);
+        } finally {
+            writeUnlock();
+        }
+    }
+    
+    /**
+     * Get the default colour for MoeSyntaxDocuments.
+     */
+    public static Color getDefaultColor()
+    {
+        return defaultColour;
+    }
+    
+    /**
+     * Get the background colour for MoeSyntaxDocuments.
+     */
+    public static Color getBackgroundColor()
+    {
+        return backgroundColour;
+    }
+    
+    /**
+     * Get an array of colours as specified in the configuration file for different
+     * token types. The indexes for each token type are defined in the Token class.
+     */
+    public static Color[] getColors()
+    {
+        return getUserColors();
+    }
+    
+    /**
+     * Allows user-defined colours to be set for syntax highlighting. The file
+     * containing the colour values is 'lib/moe.defs'. If this file is
+     * not found, or not all colours are defined, the BlueJ default colours are
+     * used.
+     * 
+     * @author This method was added by Jo Wood (jwo@soi.city.ac.uk), 9th March,
+     *         2001.
+     */
+    private static Color[] getUserColors()
+    { 
+        if(colors == null) {
+            // Replace with user-defined colours.
+            int    colorInt;
+                        
+            // First determine default colour and background colour
+            colorInt = getPropHexInt("other", 0x000000);
+            defaultColour = new Color(colorInt);
+            
+            colorInt = getPropHexInt("background", 0x000000);
+            backgroundColour = new Color(colorInt);
+
+            // Build colour table.     
+            colors = new Color[Token.ID_COUNT];
+
+            // Comments.
+            colorInt = getPropHexInt("comment", 0x1a1a80);
+            colors[Token.COMMENT1] = new Color(colorInt);    
+
+            // Javadoc comments.
+            colorInt = getPropHexInt("javadoc", 0x1a1a80);
+            colors[Token.COMMENT2] = new Color(colorInt);
+
+            // Stand-out comments (/*#).
+            colorInt = getPropHexInt("stand-out", 0xee00bb);
+            colors[Token.COMMENT3] = new Color(colorInt);
+
+            // Java keywords.
+            colorInt = getPropHexInt("keyword1", 0x660033);
+            colors[Token.KEYWORD1] = new Color(colorInt);
+
+            // Class-based keywords.
+            colorInt = getPropHexInt("keyword2", 0xcc8033);
+            colors[Token.KEYWORD2] = new Color(colorInt);
+
+            // Other Java keywords (true, false, this, super).
+            colorInt = getPropHexInt("keyword3", 0x006699);
+            colors[Token.KEYWORD3] = new Color(colorInt);
+
+            // Primitives.
+            colorInt = getPropHexInt("primitive", 0xcc0000);
+            colors[Token.PRIMITIVE] = new Color(colorInt);
+
+            // String literals.
+            colorInt = getPropHexInt("string", 0x339933);
+            colors[Token.LITERAL1] = new Color(colorInt);
+
+            // Labels
+            colorInt = getPropHexInt("label", 0x999999);
+            colors[Token.LABEL] = new Color(colorInt);
+            
+            // Invalid (eg unclosed string literal)
+            colorInt = getPropHexInt("invalid", 0xff3300);
+            colors[Token.INVALID] = new Color(colorInt);
+            
+            // Operator is not produced by token marker
+            colors[Token.OPERATOR] = new Color(0xcc9900);
+        }
+        return colors;
+    }
+    
+    /**
+     * Identify the token types and positions in a line. This is used for syntax colouring.
+     * @param line  The line number (0 based).
+     */
+    public Token getTokensForLine(int line)
+    {
+        Element lineEl = getDefaultRootElement().getElement(line);
+        int pos = lineEl.getStartOffset();
+        int length = lineEl.getEndOffset() - pos - 1;
+        return parsedNode.getMarkTokensFor(pos, length, 0, this);
+    }
+    
+    /**
+     * Get an integer value from a property whose value is hex-encoded.
+     * @param propName  The name of the property
+     * @param def       The default value if the property is undefined or
+     *                  not parseable as a hexadecimal
+     * @return  The value
+     */
+    private static int getPropHexInt(String propName, int def)
+    {
+        String strVal = Config.getPropString(propName, null, Config.moeUserProps);
+        try {
+            return Integer.parseInt(strVal, 16);
+        }
+        catch (NumberFormatException nfe) {
+            return def;
+        }
+    }
+    
+    /* 
+     * If text was inserted, the reparse-record tree needs to be updated.
+     */
+    @Override
+    protected void fireInsertUpdate(DocumentEvent e)
+    {
+        if (reparseRecordTree != null) {
+            NodeAndPosition<ReparseRecord> napRr = reparseRecordTree.findNodeAtOrAfter(e.getOffset());
+            if (napRr != null) {
+                if (napRr.getPosition() <= e.getOffset()) {
+                    napRr.getNode().resize(napRr.getSize() + e.getLength());
+                }
+                else {
+                    napRr.getNode().slide(e.getLength());
+                }
+            }
+        }
+        
+        MoeSyntaxEvent mse = new MoeSyntaxEvent(this, e);
+        if (parsedNode != null) {
+            parsedNode.textInserted(this, 0, e.getOffset(), e.getLength(), mse);
+        }
+        recordEvent(e);
+        super.fireInsertUpdate(mse);
+    }
+    
+    /* 
+     * If part of the document was removed, the reparse-record tree needs to be updated.
+     */
+    @Override
+    protected void fireRemoveUpdate(DocumentEvent e)
+    {
+        NodeAndPosition<ReparseRecord> napRr = (reparseRecordTree != null) ?
+                reparseRecordTree.findNodeAtOrAfter(e.getOffset()) :
+                    null;
+        int rpos = e.getOffset();
+        int rlen = e.getLength();
+        if (napRr != null && napRr.getEnd() == rpos) {
+            // Boundary condition
+            napRr = napRr.nextSibling();
+        }
+        while (napRr != null && rlen > 0) {
+            if (napRr.getPosition() < rpos) {
+                if (napRr.getEnd() >= rpos + rlen) {
+                    // remove middle
+                    napRr.getNode().resize(napRr.getSize() - rlen);
+                    break;
+                }
+                else {
+                    // remove end and continue
+                    int reduction = napRr.getEnd() - rpos;
+                    napRr.getNode().resize(napRr.getSize() - reduction);
+                    rlen -= reduction;
+                    napRr = napRr.nextSibling();
+                    continue;
+                }
+            }
+            else if (napRr.getPosition() == rpos) {
+                if (napRr.getEnd() > rpos + rlen) {
+                    // remove beginning
+                    napRr.getNode().resize(napRr.getSize() - rlen);
+                    break;
+                }
+                else {
+                    // remove whole node
+                    napRr.getNode().remove();
+                    napRr = reparseRecordTree.findNodeAtOrAfter(e.getOffset());
+                    continue;
+                }
+            }
+            else {
+                // napRr position is greater than delete position
+                if (napRr.getPosition() >= (rpos + rlen)) {
+                    napRr.slide(-rlen);
+                    break;
+                }
+                else if (napRr.getEnd() <= (rpos + rlen)) {
+                    // whole node to be removed
+                    NodeAndPosition<ReparseRecord> nextRr = napRr.nextSibling();
+                    napRr.getNode().remove();
+                    napRr = nextRr;
+                    continue;
+                }
+                else {
+                    // only a portion to be removed
+                    int ramount = (rpos + rlen) - napRr.getPosition();
+                    napRr.slideStart(ramount);
+                    napRr.slide(-rlen);
+                    break;
+                }
+            }
+        }
+        
+        MoeSyntaxEvent mse = new MoeSyntaxEvent(this, e);
+        if (parsedNode != null) {
+            parsedNode.textRemoved(this, 0, e.getOffset(), e.getLength(), mse);
+        }
+        recordEvent(e);
+        super.fireRemoveUpdate(mse);
+    }
+    
+    /**
+     * Notify that the whole document potentially needs repainting.
+     */
+    public void documentChanged()
+    {
+        repaintLines(0, getLength());
+    }
+    
+    /**
+     * Notify that a certain area of the document needs repainting.
+     */
+    public void repaintLines(int offset, int length)
+    {
+        fireChangedUpdate(new DefaultDocumentEvent(offset, length, EventType.CHANGE));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxEditorKit.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxEditorKit.java
new file mode 100644
index 0000000000000000000000000000000000000000..96e2d73ceea86fcb9fe8803a6a393e7bf5cb9a16
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxEditorKit.java
@@ -0,0 +1,111 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import javax.swing.text.DefaultEditorKit;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+import bluej.parser.entity.EntityResolver;
+
+/**
+ * An implementation of <code>EditorKit</code> used for syntax coloring.
+ * This is an adaptation of the SyntaxEditorKit class from JEdit for BlueJ.
+ * 
+ * @author Bruce Quig
+ * @author Michael Kolling
+ */
+public class MoeSyntaxEditorKit extends DefaultEditorKit
+        implements ViewFactory
+{
+    private boolean isTextEval;
+    private EntityResolver projectResolver;
+    private MoeDocumentListener documentListener;
+
+    /**
+     * Create a moe editor kit. There are two modes in which this can operate:
+     * as an editor kit for the standard editor (textEval == false) or as an
+     * editor kit for the text evaluation area (textEval == true).
+     * 
+     * @param textEval  Indicate whether to operate for the text eval area
+     */
+    public MoeSyntaxEditorKit(boolean textEval, EntityResolver projectResolver)
+    {
+        super();
+        isTextEval = textEval;
+        this.projectResolver = projectResolver;
+    }
+    
+    /**
+     * Create a Moe editor kit, for documents which will resolve external references
+     * using the given resolver, and send parse events to the specified listener.
+     */
+    public MoeSyntaxEditorKit(EntityResolver projectResolver, MoeDocumentListener documentListener)
+    {
+        super();
+        isTextEval = false;
+        this.projectResolver = projectResolver;
+        this.documentListener = documentListener;
+    }
+    
+    /**
+     * Returns an instance of a view factory that can be used for
+     * creating views from elements. This implementation returns
+     * the current instance, because this class already implements
+     * <code>ViewFactory</code>.
+     */
+    public ViewFactory getViewFactory()
+    {
+        return this;
+    }
+
+    /**
+     * Creates a view from an element that can be used for painting that
+     * element. This implementation returns a new <code>SyntaxView</code>
+     * instance.
+     * @param elem The element
+     * @return a new MoeSyntaxView for an element
+     * 
+     */
+    public View create(Element elem)
+    {
+        if(isTextEval) {
+            return new bluej.debugmgr.texteval.TextEvalSyntaxView(elem);
+        }
+        else {
+            return new MoeSyntaxView(elem);
+        }
+    }
+
+    /**
+     * Creates a new instance of the default document for this
+     * editor kit. This returns a new instance of
+     * <code>DefaultSyntaxDocument</code>.
+     * 
+     */
+    public Document createDefaultDocument()
+    {
+        return new MoeSyntaxDocument(projectResolver, documentListener);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c533a904307c29841bde89659dfc192af4829ea
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxEvent.java
@@ -0,0 +1,152 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.Element;
+
+import bluej.parser.nodes.NodeStructureListener;
+import bluej.parser.nodes.ParsedNode;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * A representation of document events in a MoeSyntaxDocuments. As well as textual
+ * changes, this can include information about node structure changes.
+ * 
+ * @author Davin McCall
+ */
+public class MoeSyntaxEvent implements DocumentEvent, NodeStructureListener
+{
+    private MoeSyntaxDocument document;
+    private DocumentEvent srcEvent;
+    private List<NodeAndPosition<ParsedNode>> removedNodes =
+        new LinkedList<NodeAndPosition<ParsedNode>>();
+    private Map<ParsedNode,NodeChangeRecord> changedNodes =
+        new HashMap<ParsedNode,NodeChangeRecord>();
+    private EventType eventType;
+    
+    public MoeSyntaxEvent(MoeSyntaxDocument document, DocumentEvent srcEvent)
+    {
+        this.document = document;
+        this.srcEvent = srcEvent;
+        eventType = srcEvent.getType();
+    }
+    
+    public MoeSyntaxEvent(MoeSyntaxDocument document)
+    {
+        this.document = document;
+        eventType = EventType.CHANGE;
+    }
+    
+    /**
+     * Get a list of nodes removed as part of this event.
+     */
+    public List<NodeAndPosition<ParsedNode>> getRemovedNodes()
+    {
+        return removedNodes;
+    }
+    
+    /**
+     * Get a collection of nodes which changed position as part of this event.
+     */
+    public Collection<NodeChangeRecord> getChangedNodes()
+    {
+        return changedNodes.values();
+    }
+    
+    // -------------- DocumentListener interface ------------------
+    
+    public ElementChange getChange(Element elem)
+    {
+        return srcEvent != null ? srcEvent.getChange(elem) : null;
+    }
+    
+    public MoeSyntaxDocument getDocument()
+    {
+        return document;
+    }
+    
+    public int getLength()
+    {
+        return srcEvent != null ? srcEvent.getLength() : 0;
+    }
+
+    public int getOffset()
+    {
+        return srcEvent != null ? srcEvent.getOffset() : 0;
+    }
+    
+    public EventType getType()
+    {
+        return eventType;
+    }
+    
+    // -------------- NodeStructureListener interface ------------------
+    
+    public void nodeRemoved(NodeAndPosition<ParsedNode> node)
+    {
+        removedNodes.add(node);
+        changedNodes.remove(node);
+    }
+    
+    public void nodeChangedLength(NodeAndPosition<ParsedNode> nap, int oldPos,
+            int oldSize)
+    {
+        // We try to optimize a little by storing the original position of any
+        // changed node. If the node is then changed back to the original position,
+        // we can forget about the change.
+        NodeChangeRecord r = changedNodes.get(nap.getNode());
+        if (r == null) {
+            if (nap.getPosition() != oldPos || nap.getSize() != oldSize) {
+                r = new NodeChangeRecord();
+                r.nap = nap;
+                r.originalPos = oldPos;
+                r.originalSize = oldSize;
+                changedNodes.put(nap.getNode(), r);
+            }
+        }
+        else {
+            if (nap.getPosition() == r.originalPos && nap.getSize() == r.originalSize) {
+                changedNodes.remove(nap.getNode());
+            }
+            else {
+                r.nap = nap;
+            }
+        }
+    }
+    
+    /**
+     * Node change record. Purely used for passing data around, hence public fields.
+     */
+    public class NodeChangeRecord
+    {
+        public int originalPos;
+        public int originalSize;
+        public NodeAndPosition<ParsedNode> nap;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxView.java
new file mode 100644
index 0000000000000000000000000000000000000000..a443301a76f5a4d1df8727ef7c6170db387b74fa
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeSyntaxView.java
@@ -0,0 +1,206 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.text.Element;
+import javax.swing.text.Position;
+import javax.swing.text.Segment;
+import javax.swing.text.TabExpander;
+
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+
+/**
+ * MoeSyntaxView is the main view for the Moe editor. It paints all aspects of the
+ * document, performing syntax and scope colouring.
+ *
+ * @author Bruce Quig
+ * @author Michael Kolling
+ * @author Davin McCall
+ */
+public class MoeSyntaxView extends BlueJSyntaxView
+{
+    /**  width of tag area for setting breakpoints */
+    public static final short TAG_WIDTH = 14;
+    protected static final int BREAKPOINT_OFFSET = TAG_WIDTH + 2;
+    protected static final int LEFT_MARGIN = BREAKPOINT_OFFSET + 8;
+    
+    private static boolean syntaxHighlighting = PrefMgr.getFlag(PrefMgr.HILIGHTING);
+    
+    protected Font lineNumberFont;
+    protected Font smallLineNumberFont;
+    protected FontMetrics lineNumberMetrics;
+    
+    // Attributes for lines and document
+    public static final String BREAKPOINT = "break";
+    public static final String STEPMARK = "step";
+    
+    static final Image breakImage =
+        Config.getImageAsIcon("image.editor.breakmark").getImage();
+    static final Image stepImage =
+        Config.getImageAsIcon("image.editor.stepmark").getImage();
+    static final Image breakStepImage =
+        Config.getImageAsIcon("image.editor.breakstepmark").getImage();
+
+    /**
+     * Creates a new MoeSyntaxView for painting the specified element.
+     * @param elem The element
+     */
+    public MoeSyntaxView(Element elem)
+    {
+        super(elem, LEFT_MARGIN);
+    }
+
+    /**
+     * Reset the syntax highlighting status (on/off) according to preferences.
+     */
+    public static void resetSyntaxHighlighting()
+    {
+        syntaxHighlighting = PrefMgr.getFlag(PrefMgr.HILIGHTING);
+    }
+    
+    @Override
+    protected void initialise(Graphics g)
+    {
+        super.initialise(g);
+        lineNumberFont = defaultFont.deriveFont(9.0f);
+        smallLineNumberFont = defaultFont.deriveFont(7.0f);
+        Component c = getContainer();
+        lineNumberMetrics = c.getFontMetrics(lineNumberFont);
+    }
+    
+    /**
+     * Draw the line number in front of the line
+     */
+    protected void drawLineNumber(Graphics g, int lineNumber, int x, int y)
+    {
+        g.setColor(Color.darkGray);
+
+        String number = Integer.toString(lineNumber);
+        int stringWidth = lineNumberMetrics.stringWidth(number);
+        int xoffset = BREAKPOINT_OFFSET - stringWidth - 4;
+
+        if(xoffset < -2)      // if it doesn't fit, shift one pixel over.
+            xoffset++;
+
+        if(xoffset < -2) {    // if it still doesn't fit...
+            g.setFont(smallLineNumberFont);
+            g.drawString(number, x-3, y);
+        }
+        else {
+            g.setFont(lineNumberFont);
+            g.drawString(number, x + xoffset, y);
+        }
+        g.setFont(defaultFont);
+    }
+     
+    /**
+     * Paint the line markers such as breakpoint, step mark
+     */
+    protected void paintLineMarkers(int lineIndex, Graphics g, int x, int y,
+            MoeSyntaxDocument document, Element line)
+    {
+        if(PrefMgr.getFlag(PrefMgr.LINENUMBERS))
+            drawLineNumber(g, lineIndex+1, x, y);
+   
+        // draw breakpoint and/or step image
+   
+        if(hasTag(line, BREAKPOINT)) {
+            if(hasTag(line, STEPMARK)) {
+                g.drawImage(breakStepImage, x-1, y+3-breakStepImage.getHeight(null), 
+                            null);
+            }
+            else {  // break only
+                g.drawImage(breakImage, x-1, y+3-breakImage.getHeight(null), null);
+            }
+        }
+        else if(hasTag(line, STEPMARK)) {
+            g.drawImage(stepImage, x-1, y+3-stepImage.getHeight(null), null);
+        }
+    }
+
+    /* When painting a line also paint the markers (breakpoint marks, step marks) etc.
+     * @see bluej.editor.moe.BlueJSyntaxView#paintTaggedLine(javax.swing.text.Segment, int, java.awt.Graphics, int, int, bluej.editor.moe.MoeSyntaxDocument, java.awt.Color, javax.swing.text.Element)
+     */
+    @Override
+    public void paintTaggedLine(Segment lineText, int lineIndex, Graphics g, int x, int y, 
+            MoeSyntaxDocument document, Color def, Element line, TabExpander tx) 
+    {
+        paintLineMarkers(lineIndex, g, x - LEFT_MARGIN, y, document, line);
+        if (document.getParsedNode() != null && syntaxHighlighting) {
+            paintSyntaxLine(lineText, lineIndex, x, y, g, document, def, tx);
+        }
+        else {
+            paintPlainLine(lineIndex, g, x, y);
+        }
+    }
+        
+   /*
+    * redefined paint method to paint breakpoint area
+    */
+    public void paint(Graphics g, Shape allocation)
+    {
+        // if uncompiled, fill the tag line with grey
+        Rectangle bounds = allocation.getBounds();        
+        if(Boolean.FALSE.equals(getDocument().getProperty(MoeEditor.COMPILED))) {
+            g.setColor(Color.lightGray);
+            g.fillRect(0, 0, bounds.x + TAG_WIDTH,
+                       bounds.y + bounds.height);
+        }
+        
+        Rectangle clip = g.getClipBounds();
+        
+        // Left margin
+        g.setColor(new Color(240, 240, 240));
+        g.drawLine(bounds.x + LEFT_MARGIN - 1, clip.y, bounds.x + LEFT_MARGIN - 1, clip.y + clip.height);
+        
+        // Scope highlighting
+        int spos = viewToModel(bounds.x, clip.y, allocation, new Position.Bias[1]);
+        int epos = viewToModel(bounds.x, clip.y + clip.height - 1, allocation, new Position.Bias[1]);
+        
+        MoeSyntaxDocument document = (MoeSyntaxDocument)getDocument();
+        if (document.getParsedNode() != null) {
+            Element map = getElement();
+            int firstLine = map.getElementIndex(spos);
+            int lastLine = map.getElementIndex(epos);
+            paintScopeMarkers(g, document, allocation, firstLine, lastLine, false);
+        }
+        
+        // paint the lines
+        super.paint(g, allocation);
+
+        // paint the tag separator line
+        g.setColor(Color.black);
+        g.drawLine(bounds.x + TAG_WIDTH, 0,
+                   bounds.x + TAG_WIDTH, bounds.y + bounds.height);
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeUndoManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeUndoManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..121d5ac03943ad67c85c289cd0e97d47fd7c934c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/MoeUndoManager.java
@@ -0,0 +1,106 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.util.LinkedList;
+
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.event.UndoableEditListener;
+import javax.swing.undo.CompoundEdit;
+import javax.swing.undo.UndoManager;
+import javax.swing.undo.UndoableEdit;
+
+/**
+ * An undo/redo manager for the editor. A stack of compound edits is maintained;
+ * the "beginCompoundEdit()" and "endCompoundEdit()" methods can be used to 
+ * create a compound edit (which is treated as a single edit for undo/redo purposes).
+ * 
+ * @author Davin McCall
+ */
+public class MoeUndoManager implements UndoableEditListener
+{
+    LinkedList<CompoundEdit> editStack;
+    UndoManager undoManager;
+    CompoundEdit currentEdit;
+    MoeEditor editor;
+    
+    public MoeUndoManager(MoeEditor editor)
+    {
+        this.editor = editor;
+        undoManager = new UndoManager();
+        currentEdit = undoManager;
+        editStack = new LinkedList<CompoundEdit>();
+    }
+    
+    public void undoableEditHappened(UndoableEditEvent e)
+    {
+        addEdit(e.getEdit());
+    }
+    
+    public void addEdit(UndoableEdit edit)
+    {
+        currentEdit.addEdit(edit);
+        if (currentEdit == undoManager) {
+            editor.updateUndoControls();
+            editor.updateRedoControls();
+        }
+    }
+    
+    public void beginCompoundEdit()
+    {
+        editStack.add(currentEdit);
+        currentEdit = new CompoundEdit();
+    }
+    
+    public void endCompoundEdit()
+    {
+        currentEdit.end();
+        CompoundEdit lastEdit = (CompoundEdit) editStack.removeLast();
+        lastEdit.addEdit(currentEdit);
+        currentEdit = lastEdit;
+        
+        if (currentEdit == undoManager) {
+            editor.updateUndoControls();
+            editor.updateRedoControls();
+        }
+    }
+    
+    public boolean canUndo()
+    {
+        return undoManager.canUndo();
+    }
+    
+    public boolean canRedo()
+    {
+        return undoManager.canRedo();
+    }
+    
+    public void undo()
+    {
+        undoManager.undo();
+    }
+    
+    public void redo()
+    {
+        undoManager.redo();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NVDrawPane.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NVDrawPane.java
new file mode 100644
index 0000000000000000000000000000000000000000..cadad990adfcff8947d157e97ba83431918b81ef
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NVDrawPane.java
@@ -0,0 +1,118 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JEditorPane;
+import javax.swing.plaf.ComponentUI;
+import javax.swing.text.Document;
+import javax.swing.text.View;
+
+/**
+ * A JEditorPane implementation to provide the root view for the document. This is used
+ * by the NaviView component. Basically this provides:
+ * 
+ * <ul>
+ * <li>A means to get the root view for the document
+ * <li>A proxy for repaints due to document updates. The repaints are passed on
+ *     to the NaviView, allowing it to translate co-ordinates appropriately.
+ * </ul>
+ * 
+ * @author Davin McCall
+ */
+public class NVDrawPane extends JEditorPane
+{
+    private NaviView nview;
+    
+    private int repaintTop;
+    private int repaintEnd;
+    
+    public NVDrawPane(NaviView nview)
+    {
+        this.nview = nview;
+        Font smallFont = new Font("Monospaced", Font.BOLD, 1);
+        setFont(smallFont);
+        setEditorKit(new NaviviewEditorKit(nview));
+    }
+
+    @Override
+    public void setDocument(Document doc)
+    {
+        super.setDocument(doc);
+        setBorder(null);
+        fakeRepaint();
+    }
+    
+    @Override
+    protected void setUI(ComponentUI newUI)
+    {
+        super.setUI(newUI);
+        fakeRepaint();
+    }
+    
+    private void fakeRepaint()
+    {
+        // Hack: the BasicTextUI.UpdateHandler passes a null allocation to the view
+        //      if it hasn't painted yet. The result is that same-line updates aren't
+        //      handled. If we do a pretend paint here, the problem is solved.
+        BufferedImage bi = new BufferedImage(1,1, BufferedImage.TYPE_INT_ARGB);
+        Graphics g = bi.getGraphics();
+        g.setClip(0, 0, 1, 1);
+        getUI().paint(g, this);
+    }
+    
+    @Override
+    public void repaint()
+    {
+        if (nview != null) {
+            //nview.repaint();
+            Rectangle r = getBounds();
+            repaint(0, r.x, r.y, r.width, r.height);
+            //nview.repaint();
+        }
+    }
+    
+    @Override
+    public void repaint(long tm, int x, int y, int width, int height)
+    {
+        if (nview != null) {
+            // Note this condition appears impossible, however JEditorPane constructor
+            // does call repaint().
+            repaintTop = y;
+            repaintEnd = y + height;
+            nview.repaintModel(repaintTop, repaintEnd);
+        }
+    }
+    
+    @Override
+    public Rectangle getBounds()
+    {
+        View view = getUI().getRootView(this);
+        Rectangle r = new Rectangle(1,
+                (int) view.getPreferredSpan(View.Y_AXIS));
+        return r;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NaviView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NaviView.java
new file mode 100644
index 0000000000000000000000000000000000000000..08642257d9b7e1e4eca432781dfa433fbcc45fba
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NaviView.java
@@ -0,0 +1,622 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Transparency;
+import java.awt.event.AdjustmentEvent;
+import java.awt.event.AdjustmentListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import javax.swing.JEditorPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollBar;
+import javax.swing.ToolTipManager;
+import javax.swing.text.Document;
+import javax.swing.text.View;
+import javax.swing.text.Position.Bias;
+
+import bluej.Config;
+import bluej.parser.nodes.ParsedNode;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * "NaviView" component. Displays a miniature version of the document in the editor, and allows moving
+ * through the document by clicking/dragging or cycling the mouse wheel.
+ * 
+ * @author Davin Mccall
+ */
+public class NaviView extends JPanel implements AdjustmentListener
+{
+    private static final Image frame = Config.getFixedImageAsIcon("naviview-frame.png").getImage();
+    private static final int frw = 5;  // frame width
+    
+    private Document document;
+    private JEditorPane editorPane;
+    
+    private JScrollBar scrollBar;
+    
+    /** Current view position in terms of this component's co-ordinate space */
+    private int currentViewPos;
+    /** Current view position (bottom) in terms of this component's co-ordinate space */
+    private int currentViewPosBottom;
+    
+    private int dragOffset;
+    private boolean haveToolTip = false;
+    
+    private BufferedImage imgBuffer;
+    private int prefViewHeight;
+    
+    public NaviView(Document document, JScrollBar scrollBar)
+    {
+        this.scrollBar = scrollBar;
+        editorPane = new NVDrawPane(this);
+        
+        setDocument(document);
+        
+        setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+        enableEvents(MouseEvent.MOUSE_WHEEL_EVENT_MASK);
+        setFocusable(true);
+        ToolTipManager.sharedInstance().registerComponent(this);
+    }
+    
+    /**
+     * Set the document displayed in this NaviView.
+     */
+    public void setDocument(Document document)
+    {
+        scrollBar.removeAdjustmentListener(this);
+        this.document = document;
+        editorPane.setDocument(document);
+        if (document != null) {
+            scrollBar.addAdjustmentListener(this);
+        }
+        documentChangedLength();
+    }
+    
+    /**
+     * Get the document displayed by this NaviView.
+     */
+    private Document getDocument()
+    {
+        return document;
+    }
+    
+    /**
+     * Notify the NaviView that the document has changed (vertical) length. Normally
+     * this is called by NaviviewView.
+     */
+    public void documentChangedLength()
+    {
+        View view = editorPane.getUI().getRootView(editorPane);
+        int newPrefHeight = (int) view.getPreferredSpan(View.Y_AXIS);
+        Insets insets = getInsets();
+        int yoffs = insets.top + frw;
+        if (! scrollBar.isVisible()) {
+            // If the scrollbar is invisible, and the document height changes,
+            // we need to repaint the view border
+            int rpHeight = Math.max(newPrefHeight,prefViewHeight) + yoffs + frw;
+            repaint(0, 0, getWidth(), rpHeight);
+        }
+        else {
+            repaint(0, Math.min(newPrefHeight, prefViewHeight) + yoffs,
+                    getWidth(),
+                    Math.abs(newPrefHeight - prefViewHeight) + frw);
+        }
+        prefViewHeight = newPrefHeight;
+    }
+    
+    @Override
+    public Dimension getMinimumSize()
+    {
+        // Overcome the awkward default situation where the minimum size becomes larger
+        // than the preferred size.
+        return getPreferredSize();
+    }
+    
+    @Override
+    public void setVisible(boolean flag)
+    {
+        if (! flag) {
+            scrollBar.removeAdjustmentListener(this);
+        }
+        else {
+            if (! isVisible() && document != null) {
+                scrollBar.addAdjustmentListener(this);
+            }
+        }
+        super.setVisible(flag);
+    }
+    
+    @Override
+    public void setBounds(int x, int y, int width, int height)
+    {
+        super.setBounds(x, y, width, height);
+        if (imgBuffer != null && isVisible() && width > 0) {
+            Insets insets = getInsets();
+            int myHeight = Math.max(getHeight() - insets.top - insets.bottom - frw*2, 1);
+            createImgBuffer(imgBuffer.getGraphics(), prefViewHeight > myHeight);
+        }
+        enqueueRepaint(0, height);
+        repaint();
+    }
+    
+    /**
+     * Convert a y-coordinate in the NaviView co-ordinate space to a line number
+     * in the document.
+     */
+    private int yViewToDocument(int vpos)
+    {
+        View view = editorPane.getUI().getRootView(editorPane);
+        Insets insets = getInsets();
+        vpos -= insets.top + frw;
+        int myHeight = Math.max(getHeight() - insets.top - insets.bottom - frw*2, 1);
+        if (prefViewHeight > myHeight) {
+            vpos = vpos * prefViewHeight / myHeight;
+        }
+        Bias [] breturn = new Bias[1];
+        int pos = view.viewToModel(0, vpos, new Rectangle(5,Integer.MAX_VALUE), breturn);
+        
+        return pos;
+    }
+    
+    /**
+     * Repaint model co-ordinates. The given lines will be translated to
+     * the NaviView component's co-ordinate space.
+     * @param top  The topmost line to repaint
+     * @param bottom  The lowest (numerically higher) line to repaint
+     */
+    public void repaintModel(int top, int bottom)
+    {
+        if (editorPane == null || imgBuffer == null) {
+            return;
+        }
+        
+        Insets insets = getInsets();
+        int myHeight = Math.max(getHeight() - insets.top - insets.bottom - frw*2, 1);
+        
+        if (prefViewHeight > myHeight) {
+            int ptop = top * myHeight / prefViewHeight;
+            int pbottom = (bottom * myHeight + prefViewHeight - 1) / prefViewHeight;
+            enqueueRepaint(ptop, pbottom);
+        }
+        else {
+            enqueueRepaint(top, bottom);
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.event.AdjustmentListener#adjustmentValueChanged(java.awt.event.AdjustmentEvent)
+     */
+    public void adjustmentValueChanged(AdjustmentEvent e)
+    {
+        Insets insets = getInsets();
+        int height = Math.min(prefViewHeight, getHeight() - insets.top - insets.bottom - 2*frw); 
+        
+        int topV = e.getValue() * height / (scrollBar.getMaximum()) + insets.top + frw;
+        int bottomV = (e.getValue() + scrollBar.getVisibleAmount()) * height
+                / scrollBar.getMaximum() + insets.top + frw;
+
+        repaint(0, topV - frw, getWidth(), bottomV - topV + 2 + frw*2);
+        repaint(0, currentViewPos - frw, getWidth(), currentViewPosBottom - currentViewPos + 2 + frw*2);
+
+        currentViewPos = topV;
+        currentViewPosBottom = bottomV;
+    }
+
+    @Override
+    public Point getToolTipLocation(MouseEvent event)
+    {
+        // Returning non-null unconditionally seems to make the tooltip persist as a small square
+        // even when getToolTipText() returns null - sigh. (linux, JDK 6.0u13).
+        if (haveToolTip) {
+            Point ttloc = event.getPoint();
+            ttloc.y += 15;
+            ttloc.x -= 20;
+            return ttloc;
+        }
+        return null;
+    }
+    
+    @Override
+    public String getToolTipText(MouseEvent event)
+    {
+        // int pos = viewToModel(event.getPoint());
+        int pos = yViewToDocument(event.getPoint().y);
+        MoeSyntaxDocument document = (MoeSyntaxDocument) getDocument();
+        ParsedNode pn = document.getParser();
+        int startpos = 0;
+        while (pn != null) {
+            if (pn.getNodeType() == ParsedNode.NODETYPE_METHODDEF) {
+                haveToolTip = true;
+                return pn.getName();
+            }
+            
+            NodeAndPosition<ParsedNode> nap = pn.findNodeAtOrAfter(pos, startpos);
+            if (nap == null || nap.getPosition() > pos) {
+                break;
+            }
+            pn = nap.getNode();
+            startpos = nap.getPosition();
+        }
+        
+        haveToolTip = false;
+        return null;
+    }
+    
+    @Override
+    protected void processMouseEvent(MouseEvent e)
+    {
+        if (e.getID() == MouseEvent.MOUSE_PRESSED) {
+            int y = e.getY();
+            if (y > currentViewPos && y < currentViewPosBottom) {
+                // clicked within the current view area
+                dragOffset = y - currentViewPos;
+            }
+            else {
+                dragOffset = (currentViewPosBottom - currentViewPos) / 2;
+                moveView(e.getY());
+            }
+        }
+        else {
+            super.processMouseEvent(e);
+        }
+    }
+    
+    @Override
+    protected void processMouseMotionEvent(MouseEvent e)
+    {
+        if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
+            moveView(e.getY());
+        }
+        else {
+            super.processMouseMotionEvent(e);
+        }
+    }
+
+    @Override
+    protected void processMouseWheelEvent(MouseWheelEvent e)
+    {
+        if (e.getID() == MouseEvent.MOUSE_WHEEL) {
+            scrollBar.dispatchEvent(e);
+        }
+    }
+    
+    /**
+     * Move the view (by setting the scrollbar value), according to the given mouse coordinate
+     * within the NaviView component.
+     */
+    private void moveView(int ypos)
+    {
+        int modelPos = yViewToDocument(ypos - dragOffset);
+        int lineNum = getDocument().getDefaultRootElement().getElementIndex(modelPos);
+        lineNum = Math.max(0, lineNum);
+        
+        int totalLines = getDocument().getDefaultRootElement().getElementCount();
+        int totalAmt = scrollBar.getMaximum() - scrollBar.getMinimum();
+        
+        int pos = lineNum * totalAmt / totalLines + scrollBar.getMinimum();
+        scrollBar.setValue(pos);
+    }
+        
+    /**
+     * Paint to the backing image buffer, and then issue an appropriate
+     * repaint() so that the backing buffer is displayed.
+     * 
+     * @param top  The top line (in view co-ordinates) to paint
+     * @param bottom  The bottom line (in view co-ordinates) to paint
+     */
+    private void paintImgBuffer(int top, int bottom)
+    {
+        int myHeight = imgBuffer.getHeight();
+        View view = editorPane.getUI().getRootView(editorPane);
+
+        Color background = MoeSyntaxDocument.getBackgroundColor();
+        
+        Graphics2D g = imgBuffer.createGraphics();
+
+        if (prefViewHeight > myHeight) {
+            // scale!
+            int width = Math.max(imgBuffer.getWidth() * prefViewHeight / myHeight, 1);
+            int ytop = top * prefViewHeight / myHeight;
+            int ybtm = (bottom * prefViewHeight + myHeight - 1) / myHeight;
+            int height = ybtm - ytop;
+            
+            if (height > 400) {
+                height = 400;
+                ybtm = ytop + 400;
+                int newbottom = top + (height * myHeight / prefViewHeight);
+                if (newbottom <= top) {
+                    newbottom = top + 1;
+                    ybtm = (newbottom* prefViewHeight + myHeight - 1) / myHeight;
+                    height = ybtm - ytop; 
+                }
+                enqueueRepaint(newbottom, bottom);
+                bottom = newbottom;
+            }
+            
+            if (height < 1) {
+                height = 1;
+                ybtm = ytop + 1;
+                bottom = top + (height * myHeight / prefViewHeight);
+            }
+            
+            // Create a buffered image to use
+            BufferedImage bimage = g.getDeviceConfiguration().createCompatibleImage(width, height,Transparency.TRANSLUCENT);
+            Map<Object,Object> hints = new HashMap<Object,Object>();
+            hints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+            g.addRenderingHints(hints);
+
+            g.setColor(background);
+            g.fillRect(0, top, imgBuffer.getWidth(), bottom - top);
+            
+            Graphics2D bg = bimage.createGraphics();
+            Rectangle shape = new Rectangle(frw, frw, width, prefViewHeight);
+            bg.setClip(0, 0, width, height);
+            bg.translate(-frw, -ytop - frw);
+            view.paint(bg, shape);
+            
+            g.drawImage(bimage, 0, top,
+                    imgBuffer.getWidth(),
+                    bottom, 0, 0, width, height, null);
+            
+            bg.dispose();
+        }
+        else {
+            // Scaling not necessary
+            int w = imgBuffer.getWidth();
+            int h = myHeight;
+            
+            Rectangle rb = new Rectangle();
+            rb.x = 0;
+            rb.y = Math.max(0, top);
+            rb.width = imgBuffer.getWidth();
+            rb.height = bottom - top;
+            
+            g.setClip(rb);
+            g.setColor(background);
+            g.fillRect(rb.x, rb.y, rb.width, rb.height);
+            
+            // Draw the code on the buffer image:
+            g.translate(-frw, -frw);
+            Rectangle bufferBounds = new Rectangle (frw,frw,w,h);
+            view.paint(g, bufferBounds);
+        }
+        
+        g.dispose();
+    }
+    
+    private List<Integer> tops = new ArrayList<Integer>();
+    private List<Integer> bottoms = new ArrayList<Integer>();
+    
+    /**
+     * Enqueue a repaint of the backing buffer. The given co-ordinates
+     * (top, bottom) are view co-ordinates.
+     */
+    private void enqueueRepaint(int top, int bottom)
+    {
+        ListIterator<Integer> i = tops.listIterator();
+        ListIterator<Integer> j = bottoms.listIterator();
+        
+        if (! i.hasNext()) {
+            Insets insets = getInsets();
+            repaint(insets.left + frw, insets.top + frw + top,
+                    getWidth() - insets.left - insets.right - frw * 2,
+                    bottom - top);
+        }
+        
+        while (i.hasNext()) {
+            int etop = i.next();
+            int ebtm = j.next();
+            if (top < etop) {
+                if (bottom > ebtm) {
+                    i.remove(); j.remove();
+                }
+                else {
+                    bottom = Math.min(bottom, etop);
+                }
+            }
+            else if (bottom > ebtm) {
+                top = Math.max(top, ebtm);
+            }
+            else {
+                // fully contained
+                return;
+            }
+        }
+        
+        tops.add(top);
+        bottoms.add(bottom);
+    }
+    
+    @Override
+    protected void paintComponent(Graphics g)
+    {   
+        Rectangle clipBounds = new Rectangle(new Point(0,0), getSize());
+        Insets insets = getInsets();
+        g.getClipBounds(clipBounds);
+        
+        int myHeight = Math.max(getHeight() - insets.top - insets.bottom - frw*2, 1);
+
+        Document document = getDocument();
+        if (document == null) {
+            // Should not happen
+            return;
+        }
+
+        int docHeight = Math.min(myHeight, prefViewHeight);
+
+        // Calculate the visible portion
+        // topV = the topmost visible line (in local coordinate space)
+        // bottomV = the bottommost visible line (in local coordinate space)
+        int topV = insets.top + frw + scrollBar.getValue() * docHeight / scrollBar.getMaximum();
+        int bottomV = insets.top + frw + ((scrollBar.getValue() + scrollBar.getVisibleAmount()) * docHeight + (scrollBar.getMaximum() - 1)) / scrollBar.getMaximum();
+
+        createImgBuffer(g, prefViewHeight > myHeight);
+        
+        if (! tops.isEmpty()) {
+            int rtop = tops.remove(0);
+            int rbottom = bottoms.remove(0);
+            paintImgBuffer(rtop, rbottom);
+        }
+        
+        g.drawImage(imgBuffer, insets.left + frw, insets.top + frw, null);
+        
+        Color background = MoeSyntaxDocument.getBackgroundColor();
+        
+        int lx = insets.left;
+        int rx = getWidth() - insets.right;
+        int ty = insets.top;
+        
+        // Clear the border area (frw width)
+        g.setColor(background);
+        g.fillRect(lx, ty, rx - lx, frw);
+        g.fillRect(lx, ty, frw, docHeight + frw);
+        g.fillRect(rx - frw, ty, frw, docHeight + frw);        
+
+        g.setColor(getBackground());
+        g.fillRect(lx, docHeight + frw + insets.top, rx - lx, myHeight - docHeight + frw);
+                   
+        // Darken the area outside the viewport (above)
+        g.setColor(new Color(0, 0, 0, 0.15f));
+        if (topV > clipBounds.y) {
+            g.fillRect(clipBounds.x, clipBounds.y, clipBounds.width, topV - clipBounds.y);
+        }
+
+        // Darken the area outside the viewport (below)
+        int docBottom = docHeight + frw + insets.top;
+        if (bottomV < docBottom) {
+            g.fillRect(clipBounds.x, bottomV, clipBounds.width, docBottom - bottomV);
+        }
+        
+        // Fill the area between the document end and bottom of the component
+        if (docBottom < clipBounds.y + clipBounds.height) {
+            Color myBgColor = getBackground();
+            // This odd statement is necessary to avoid a weird Mac OS X bug
+            // (OS X 10.6.2, Java 1.6.0_17) with repaint which occurs when
+            // a tooltip is showing.
+            g.setColor(new Color(myBgColor.getRGB()));
+            g.fillRect(clipBounds.x, docBottom, clipBounds.width,
+                    clipBounds.y + clipBounds.height - docBottom);
+        }
+
+        // Draw a border around the visible area
+        int fx1 = lx;
+        int fy1 = topV - frw;
+        int fx2 = rx;
+        int fy2 = bottomV;
+        
+        int fh = frame.getHeight(null);
+        int fw = frame.getWidth(null);
+        
+        // top - left corner, straight, right corner
+        g.drawImage(frame, fx1, fy1, fx1+5, fy1+5, 0, 0, 5, 5, null);
+        g.drawImage(frame, fx1+5, fy1, fx2-5, fy1+5, 5, 0, fw - 5, 5, null);
+        g.drawImage(frame, fx2-5, fy1, fx2, fy1+5, fw-5, 0, fw, 5, null);
+        
+        // sides
+        g.drawImage(frame, fx1, fy1+5, fx1+5, fy2, 0, 5, 5, fh-5, null);
+        g.drawImage(frame, fx2-5, fy1+5, fx2, fy2, fw-5, 5, fw, fh-5, null);
+        
+        // bottom - left corner, straight, right corner
+        g.drawImage(frame, fx1, fy2, fx1+5, fy2+5, 0, fh-5, 5, fh, null);
+        g.drawImage(frame, fx1+5, fy2, fx2-5, fy2+5, 5, fh-5, fw-5, fh, null);
+        g.drawImage(frame, fx2-5, fy2, fx2, fy2+5, fw-5, fh-5, fw, fh, null);
+        
+        if (! tops.isEmpty()) {
+            int rtop = tops.get(0);
+            int rbottom = bottoms.get(0);
+            repaint(0, rtop, getWidth(), rbottom - rtop);
+        }
+    }
+    
+    public void createImgBuffer(Graphics g, boolean scaling)
+    {
+        Insets insets = getInsets();
+        int w = Math.max(getWidth() - insets.left - insets.right - 2*frw, 1);
+        int h = Math.max(getHeight() - insets.top - insets.bottom - 2*frw, 1);
+                
+        if (imgBuffer != null) {
+            if (imgBuffer.getHeight() == h && imgBuffer.getWidth() == w) {
+                return;
+            }
+        }
+        
+        BufferedImage oldImgBuffer = imgBuffer;
+        
+        if (g instanceof Graphics2D) {
+            Graphics2D g2d = (Graphics2D) g;
+            imgBuffer = g2d.getDeviceConfiguration().createCompatibleImage(w, h);
+        }
+        else {
+            imgBuffer = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
+        }
+        
+        // Create the new image buffer and paint the old one onto it if possible.
+        Graphics2D g2d = imgBuffer.createGraphics();
+        if (oldImgBuffer == null) {
+            g2d.setColor(getBackground());
+            g2d.fillRect(0, 0, imgBuffer.getWidth(), imgBuffer.getHeight());
+            paintImgBuffer(0, imgBuffer.getHeight());
+        }
+        else if (! scaling) {
+            g2d.drawImage(oldImgBuffer, 0, 0, null);
+            paintImgBuffer(oldImgBuffer.getHeight(), imgBuffer.getHeight());
+        }
+        else {
+            g2d.drawImage(oldImgBuffer, 0, 0, imgBuffer.getWidth(), imgBuffer.getHeight(),
+                    0, 0, oldImgBuffer.getWidth(), oldImgBuffer.getHeight(), null);
+            paintImgBuffer(0, imgBuffer.getHeight());
+        }
+        g2d.dispose();
+    }
+    
+    public Graphics2D getScalingImgBufferGraphics(Graphics g)
+    {
+        Insets insets = getInsets();
+        int myHeight = Math.max(getHeight() - insets.top - insets.bottom - frw*2, 1);
+        createImgBuffer(g, prefViewHeight > myHeight);
+        Graphics2D r = imgBuffer.createGraphics();
+        if (prefViewHeight > myHeight) {
+            double scaleFactor = (double)myHeight / prefViewHeight; 
+            r.scale(scaleFactor, scaleFactor);
+        }
+        r.translate(-frw, -frw);
+        return r;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NaviviewEditorKit.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NaviviewEditorKit.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec58739665936e47acd924621b2c14f105d799f5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NaviviewEditorKit.java
@@ -0,0 +1,61 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import javax.swing.text.DefaultEditorKit;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * An EditorKit implementation for the NaviView. The main purpose is to provide a NaviviewView as
+ * the default view.
+ * 
+ * @author Davin McCall
+ */
+public class NaviviewEditorKit extends DefaultEditorKit implements ViewFactory
+{
+    private NaviView naviView;
+    
+    public NaviviewEditorKit(NaviView naviView)
+    {
+        this.naviView = naviView;
+    }
+    
+    @Override
+    public ViewFactory getViewFactory()
+    {
+        return this;
+    }
+
+    public View create(Element elem)
+    {
+        return new NaviviewView(elem, naviView);
+    }
+    
+    @Override
+    public Document createDefaultDocument()
+    {
+        return new MoeSyntaxDocument();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NaviviewView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NaviviewView.java
new file mode 100644
index 0000000000000000000000000000000000000000..59279657f343ddc14263c289dc0212f2375aeafc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NaviviewView.java
@@ -0,0 +1,183 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+ 
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.Transparency;
+import java.awt.image.BufferedImage;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentEvent.ElementChange;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.Position;
+import javax.swing.text.Segment;
+import javax.swing.text.TabExpander;
+import javax.swing.text.ViewFactory;
+
+import bluej.Config;
+
+/**
+ * A view for the NaviView component.
+ * 
+ * @author Davin McCall
+ */
+public class NaviviewView extends BlueJSyntaxView
+{
+    private static final boolean SCOPE_HIGHLIGHTING = true;
+    private static final boolean HIGHLIGHT_METHODS_ONLY = true;
+    private static final boolean SYNTAX_COLOURING = false;
+    
+    // MacOS font rendering at small sizes seems to be vastly different
+    // Use 2^3 for MacOS Tiger/Leopard
+    // Use 2^2 for MacOS Snow Leopard
+    // Use 2^1 for everything else
+    private static final int DARKEN_AMOUNT = Config.isMacOS() ? (Config.isMacOSSnowLeopard() ? 2 : 3) : 1;
+    
+    private NaviView naviView;
+    
+    public NaviviewView(Element elem, NaviView naviView)
+    {
+        super(elem, 0);
+        this.naviView = naviView;
+    }
+    
+    @Override
+    protected void paintTaggedLine(Segment line, int lineIndex, Graphics g,
+            int x, int y, MoeSyntaxDocument document, Color def,
+            Element lineElement, TabExpander tx)
+    {
+        // Painting at such a small font size means the font appears very light.
+        // To get around this problem, we paint into a temporary image, then darken
+        // the text, and finally copy the temporary image to the output Graphics.
+        
+        try {
+            int lineHeight = metrics.getHeight();
+            int endPos = lineElement.getEndOffset() - 1;
+            Rectangle dummyShape = new Rectangle(0,0,0,0);
+            int endX = modelToView(endPos, dummyShape, Position.Bias.Forward).getBounds().x;
+            int beginX = modelToView(lineElement.getStartOffset(), dummyShape, Position.Bias.Forward).getBounds().x;
+            int width = endX - beginX;
+            if (width <= 0) {
+                return;
+            }
+
+            Rectangle clipBounds = g.getClipBounds();
+            width = Math.min(width, clipBounds.width);
+            BufferedImage img;
+            if (g instanceof Graphics2D) {
+                img = ((Graphics2D)g).getDeviceConfiguration()
+                .createCompatibleImage(width, lineHeight, Transparency.TRANSLUCENT);
+            }
+            else {
+                img = new BufferedImage(width, lineHeight, BufferedImage.TYPE_INT_ARGB);
+            }
+
+            Graphics2D imgG = img.createGraphics();
+            imgG.setFont(g.getFont());
+            imgG.setColor(g.getColor());
+
+            if (SYNTAX_COLOURING) {
+                if (document.getParsedNode() != null) {
+                    super.paintTaggedLine(line, lineIndex, imgG, x - clipBounds.x,
+                            metrics.getAscent(), document, def, lineElement, tx);
+                } else {
+                    paintPlainLine(lineIndex, imgG, x - clipBounds.x, metrics.getAscent());
+                }
+            } else {
+                paintPlainLine(lineIndex, imgG, x - clipBounds.x, metrics.getAscent());
+            }
+
+            // Filter the image - adjust alpha channel to darken the image.
+            for (int iy = 0; iy < img.getHeight(); iy++) {
+                for (int ix = 0; ix < img.getWidth(); ix++) {
+                    int rgb = img.getRGB(ix, iy);
+                    Color c = new Color(rgb, true);
+                    int red = c.getRed();
+                    int green = c.getGreen();
+                    int blue = c.getBlue();
+                    int alpha = c.getAlpha();
+
+                    // Make it more opaque
+                    alpha = darken(alpha);
+                    img.setRGB(ix, iy, new Color(red, green, blue, alpha).getRGB());
+                }
+            }
+
+            g.drawImage(img, clipBounds.x, y - metrics.getAscent(), null);
+        }
+        catch (BadLocationException ble) {}
+    }
+    
+    @Override
+    public void paint(Graphics g, Shape a)
+    {
+        Rectangle bounds = a.getBounds();
+        Rectangle clip = g.getClipBounds();
+        if (clip == null) {
+            clip = a.getBounds();
+        }
+        
+        if (SCOPE_HIGHLIGHTING) {
+            // Scope highlighting
+            MoeSyntaxDocument document = (MoeSyntaxDocument)getDocument();
+            if (document.getParsedNode() != null) {
+                int spos = viewToModel(bounds.x, clip.y, a, new Position.Bias[1]);
+                int epos = viewToModel(bounds.x, clip.y + clip.height - 1, a, new Position.Bias[1]);
+
+                Element map = getElement();
+                int firstLine = map.getElementIndex(spos);
+                int lastLine = map.getElementIndex(epos);
+                paintScopeMarkers(naviView.getScalingImgBufferGraphics(g), document, a, firstLine, lastLine,
+                        HIGHLIGHT_METHODS_ONLY, true);
+            }
+        }
+
+        super.paint(g, a);
+    }
+    
+    private int darken(int c)
+    {
+        c = c << DARKEN_AMOUNT;
+        if(c>255) c = 255;
+        return c;
+    }
+
+    @Override
+    protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f)
+    {
+        ElementChange ec = changes.getChange(getDocument().getDefaultRootElement());
+        if (ec != null) {
+            Element [] addedChildren = ec.getChildrenAdded();
+            Element [] removedChildren = ec.getChildrenRemoved();
+            if (addedChildren.length != removedChildren.length) {
+                naviView.documentChangedLength();
+            }
+        }
+        super.updateDamage(changes, a, f);
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NullCaret.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NullCaret.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0e00809e08c37328c3b51faf71652ed23f4833a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/NullCaret.java
@@ -0,0 +1,132 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Graphics;
+import java.awt.Point;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.event.ChangeListener;
+import javax.swing.text.Caret;
+import javax.swing.text.JTextComponent;
+
+/**
+ * A dummy Caret, for use when doing operations which move the caret a lot (e.g. which do
+ * many separate insertions/removals in the editor).
+ * 
+ * <p>The default caret implementation is relatively slow to move.
+ * 
+ * @author Davin McCall
+ */
+public class NullCaret implements Caret
+{
+    int markPos;
+    int dotPos;
+    List<ChangeListener> changeListeners = new ArrayList<ChangeListener>();
+    
+    public NullCaret(int mark, int dot)
+    {
+        markPos = mark;
+        dotPos = dot;
+    }
+    
+    public void addChangeListener(ChangeListener l)
+    {
+        changeListeners.add(l);
+    }
+
+    public void deinstall(JTextComponent c)
+    {
+    }
+
+    public int getBlinkRate()
+    {
+        return 0;
+    }
+
+    public int getDot()
+    {
+        return dotPos;
+    }
+
+    public Point getMagicCaretPosition()
+    {
+        return null;
+    }
+
+    public int getMark()
+    {
+        return markPos;
+    }
+
+    public void install(JTextComponent c)
+    {
+    }
+
+    public boolean isSelectionVisible()
+    {
+        return false;
+    }
+
+    public boolean isVisible()
+    {
+        return false;
+    }
+
+    public void moveDot(int dot)
+    {
+        dotPos = dot;
+    }
+
+    public void paint(Graphics g)
+    {
+    }
+
+    public void removeChangeListener(ChangeListener l)
+    {
+        changeListeners.remove(l);
+    }
+
+    public void setBlinkRate(int rate)
+    {
+    }
+
+    public void setDot(int dot)
+    {
+        markPos = dot;
+        dotPos = dot;
+    }
+
+    public void setMagicCaretPosition(Point p)
+    {
+    }
+
+    public void setSelectionVisible(boolean v)
+    {
+    }
+
+    public void setVisible(boolean v)
+    {
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ParseErrorNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ParseErrorNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..9802f3073612bdf6f2ee61db2e5e54455803eb41
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ParseErrorNode.java
@@ -0,0 +1,60 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import bluej.parser.nodes.RBTreeNode;
+
+/**
+ * A node in a tree representing a parse error highlight and its position.
+ * 
+ * @author Davin McCall
+ */
+public class ParseErrorNode extends RBTreeNode<ParseErrorNode>
+{
+    private Object highlightTag;
+    private String errCode;
+    
+    /**
+     * Construct a ParseErrorNode for the given highlight tag and the given error code / message.
+     */
+    public ParseErrorNode(Object highlightTag, String errCode)
+    {
+        this.highlightTag = highlightTag;
+        this.errCode = errCode;
+    }
+    
+    /**
+     * Get the highlight tag for this parse error node.
+     */
+    public Object getHighlightTag()
+    {
+        return highlightTag;
+    }
+    
+    /**
+     * Get the error code for this parse error node.
+     */
+    public String getErrCode()
+    {
+        return errCode;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ParserMessageHandler.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ParserMessageHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c61905968ddc23d9c924c80ded4b9252f1e523d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ParserMessageHandler.java
@@ -0,0 +1,53 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.io.File;
+
+import bluej.Config;
+import bluej.utility.BlueJFileReader;
+
+/**
+ * Wrapper for functionality around translating parser error codes to human-readable
+ * error messages.
+ * 
+ * @author Davin McCall
+ */
+public class ParserMessageHandler
+{
+    /**
+     * Translate an error code or message from the parser into a human-readable error message
+     * in the appropriate language.
+     */
+    public static String getMessageForCode(String code)
+    {
+        if (code.startsWith("BJ")) {
+            // This looks like a BlueJ parser error code.
+            File fileName = Config.getLanguageFile("bluejparser.help");
+            String helpText = BlueJFileReader.readHelpText(fileName, code, true);
+            if (helpText != null) {
+                return helpText;
+            }
+        }
+        return code;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/PrintDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/PrintDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ddc3873c5db66436c21463dca4f88bc1b5a28f2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/PrintDialog.java
@@ -0,0 +1,166 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+
+/**
+ * A print dialog with options specific to the editor.
+ */
+public class PrintDialog extends EscapeDialog
+{
+    private boolean ok; // result: which button?
+    private JCheckBox printLineNumbers;
+    private JCheckBox printHighlighting;
+
+    /**
+     * Creates a new ProjectPrintDialog object.
+     * 
+     * @param parent the frame that called the print dialog
+     */
+    public PrintDialog(Frame parent)
+    {
+        super(parent, Config.getString("editor.printDialog.title"), true);
+
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent E)
+            {
+                ok = false;
+                setVisible(false);
+            }
+        });
+
+        JPanel mainPanel = new JPanel();
+
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+        mainPanel.setBorder(BlueJTheme.dialogBorder);
+        mainPanel.add(Box.createVerticalStrut(
+                              BlueJTheme.dialogCommandButtonsVertical));
+
+        printLineNumbers = new JCheckBox(Config.getString("editor.printDialog.printLineNumbers"));
+        printLineNumbers.setSelected(true);
+        mainPanel.add(printLineNumbers);
+                
+        printHighlighting = new JCheckBox(Config.getString("editor.printDialog.printHighlighting"));
+        mainPanel.add(printHighlighting);
+                
+        mainPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+        buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+        JButton okButton = BlueJTheme.getOkButton();
+        okButton.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent evt) { doOK(); }
+        });
+        
+        JButton cancelButton = BlueJTheme.getCancelButton();
+        cancelButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent evt)
+            {
+                doCancel();
+            }
+        });
+
+        DialogManager.addOKCancelButtons(buttonPanel, okButton, cancelButton);
+
+        getRootPane().setDefaultButton(okButton);
+
+        mainPanel.add(buttonPanel);
+
+        getContentPane().add(mainPanel);
+        pack();
+
+        DialogManager.centreDialog(this);
+    }
+
+    /**
+     * Show this dialog and return true if "OK" was pressed, false if
+     * cancelled.
+     * 
+     * @return the status of the print job, proceed if true, cancel if false
+     */
+    public boolean display()
+    {
+        ok = false;
+        setVisible(true);
+
+        return ok;
+    }
+
+    /**
+     * Close action called when OK button is pressed.  It only sets ok boolean
+     * flag to true as long as one of the check boxes is selected
+     */
+    public void doOK()
+    {
+        ok = true;
+        setVisible(false);
+    }
+
+    /**
+     * Close action when Cancel is pressed.
+     */
+    public void doCancel()
+    {
+        ok = false;
+        setVisible(false);
+    }
+
+    /**
+     * Print line numbers selection status
+     * 
+     * @return true if radio button is selected meaning line numbers should be
+     *         printed
+     */
+    public boolean printLineNumbers()
+    {
+        return printLineNumbers.isSelected();
+    }
+
+    /**
+     * Print with syntax highlighting selection status
+     * 
+     * @return true if radio button is selected meaning source code should be
+     *         printed with syntax highlighting
+     */
+    public boolean printHighlighting()
+    {
+        return printHighlighting.isSelected();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReadmeEditorKit.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReadmeEditorKit.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf245001632f1b270ce742333801fb1f2510846c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReadmeEditorKit.java
@@ -0,0 +1,43 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import javax.swing.text.Document;
+
+/**
+ * An editor kit for the README editor.
+ * 
+ * @author Davin McCall
+ */
+public class ReadmeEditorKit extends MoeSyntaxEditorKit
+{
+    public ReadmeEditorKit()
+    {
+        super(false, null);
+    }
+    
+    @Override
+    public Document createDefaultDocument()
+    {
+        return new MoeSyntaxDocument();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReparseRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReparseRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..7996792c6a3e4d0c2dae3c599244f4d3faba311b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReparseRecord.java
@@ -0,0 +1,33 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import bluej.parser.nodes.RBTreeNode;
+
+/**
+ * Represents a queued reparse operation on a MoeSyntaxDocument.
+ * 
+ * @author Davin McCall
+ */
+public class ReparseRecord extends RBTreeNode<ReparseRecord>
+{
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReparseRunner.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReparseRunner.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c3e65311127295f3fb646abf956e97ccb7dcda7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReparseRunner.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt
+ */
+package bluej.editor.moe;
+
+import java.awt.EventQueue;
+
+/**
+ * Process the document re-parse queue.
+ * 
+ * <p>This is a Runnable which runs on the Swing/AWT event queue. It performs
+ * a small amount of re-parsing before re-queing itself, which allows input
+ * to be processed in the meantime.
+ * 
+ * @author Davin McCall
+ */
+public class ReparseRunner implements Runnable
+{
+    private MoeEditor editor;
+    
+    public ReparseRunner(MoeEditor editor)
+    {
+        this.editor = editor;
+    }
+    
+    public void run()
+    {
+        MoeSyntaxDocument document = editor.getSourceDocument();
+        long begin = System.currentTimeMillis();
+        if (document != null && document.pollReparseQueue()) {
+            // Continue processing
+            while (System.currentTimeMillis() - begin < 5) {
+                if (! document.pollReparseQueue()) {
+                    break;
+                }
+            }
+            EventQueue.invokeLater(this);
+        }
+        else {
+            // tell MoeEditor we are no longer scheduled.
+            editor.reparseRunnerFinished();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReplacePanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReplacePanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..be427e26cd0af13b7f3fd39189827b1acfc32e74
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ReplacePanel.java
@@ -0,0 +1,251 @@
+/*
+This file is part of the BlueJ program. 
+Copyright (C) 1999-2011  Michael Kolling and John Rosenberg 
+
+This program is free software; you can redistribute it and/or 
+modify it under the terms of the GNU General Public License 
+as published by the Free Software Foundation; either version 2 
+of the License, or (at your option) any later version. 
+
+This program is distributed in the hope that it will be useful, 
+but WITHOUT ANY WARRANTY; without even the implied warranty of 
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+GNU General Public License for more details. 
+
+You should have received a copy of the GNU General Public License 
+along with this program; if not, write to the Free Software 
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+This file is subject to the Classpath exception as provided in the  
+LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.DBox;
+import bluej.utility.DBoxLayout;
+
+/**
+ * ReplacePanel display and functionality for replace
+ * 
+ * @author Marion Zalk
+ * @author  Michael Kölling
+ */
+public class ReplacePanel extends JPanel implements ActionListener, DocumentListener
+{
+
+    private MoeEditor editor;
+    private FindPanel finder;
+    private Font font;
+    private JTextField replaceText;
+    private String replaceString = "";
+    private JButton replaceButton;
+    private JButton replaceAllButton;
+    private final static String REPLACE_BUTTON_NAME = "replaceBtn";
+    private final static String REPLACE_ALL_BUTTON_NAME = "replaceAllBtn";
+    private final static String REPLACE_TEXTFIELD = "replaceTextField";
+
+    public ReplacePanel(MoeEditor ed, FindPanel finder)
+    {
+        super(new BorderLayout());
+        this.finder = finder;
+        font = PrefMgr.getStandardFont();
+        addReplaceBody();
+        editor = ed;
+    }
+
+    protected JTextField getReplaceText()
+    {
+        return replaceText;
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+        JComponent src = (JComponent) e.getSource();
+        setReplaceString(replaceText.getText());
+        if (src.getName().equals(REPLACE_BUTTON_NAME)) {
+            if (getReplaceString() != null) {
+                editor.replace(getReplaceString());
+            }
+        }
+        if (src.getName().equals(REPLACE_ALL_BUTTON_NAME)) {
+            if (getReplaceString() != null) {
+                editor.replaceAll(getReplaceString());
+            }
+        }
+
+    }
+
+    /**
+     * Populates the replace string and enables the buttons if there 
+     * is selected text or the find text field is populated
+     */
+    public void replaceEvent()
+    {
+        setReplaceString(replaceText.getText());
+        enableButtons();
+    }
+
+    /**
+     * Determines whether the buttons should be enabled 
+     *  or not and enables them accordingly
+     */
+    public void enableButtons()
+    {
+        //Only enable the once and all buttons if both find and replace are populated
+        //(note: an empty replace string is a valid value)
+        //and if there is selected text which is the same as the find string.
+        //This eliminates the situation when the caret is moved and a replace in the new position 
+        //may not be the intention of the user
+        if (editor.getFindSearchString() != null && editor.getFindSearchString().length() != 0
+                && editor.getSourcePane().getSelectedText() != null
+                && editor.getSourcePane().getSelectedText().equals(editor.getFindSearchString())) {
+            enableButtons(true);
+        } else {
+            enableButtons(false);
+        }
+    }
+
+    /**
+     * Display the replace panel
+     */
+    private void addReplaceBody()
+    {
+        JComponent rBody = new DBox(DBox.X_AXIS, 0, BlueJTheme.componentSpacingLarge, 0.5f);
+        DBox replaceBody = new DBox(DBoxLayout.X_AXIS, 0, BlueJTheme.commandButtonSpacing, 0.0f);
+        DBox optionsBody = new DBox(DBoxLayout.X_AXIS, 0, BlueJTheme.commandButtonSpacing, 0.0f);
+
+        rBody.setOpaque(false);
+        replaceBody.setOpaque(false);
+        optionsBody.setOpaque(false);
+
+        JLabel replaceLabel = new JLabel(Config.getString("editor.replacePanel.replaceLabel") + " ");
+        replaceLabel.setFont(font);
+        DBox replaceLabelBox = new DBox(DBox.X_AXIS, 0.5f);
+        replaceLabelBox.setOpaque(false);
+        replaceLabelBox.add(Box.createHorizontalGlue());
+        replaceLabelBox.add(replaceLabel);
+        Dimension d = replaceLabelBox.getPreferredSize();
+        d.width = finder.getLabelBoxWidth();
+        replaceLabelBox.setPreferredSize(d);
+        replaceLabelBox.setMaximumSize(d);
+
+        replaceText = new JTextField(11);
+        replaceText.setMaximumSize(replaceText.getPreferredSize());
+        replaceText.setFont(font);
+        replaceText.setText(getReplaceString());
+        replaceText.getDocument().addDocumentListener(this);
+        replaceText.setName(REPLACE_TEXTFIELD);
+
+        replaceButton = new JButton();
+        replaceButton.setName(REPLACE_BUTTON_NAME);
+        replaceButton.setText(Config.getString("editor.replacePanel.replaceOnce"));
+        replaceButton.setFont(font);
+        replaceButton.addActionListener(this);
+        replaceButton.setEnabled(false);
+
+        replaceAllButton = new JButton();
+        replaceAllButton.setName(REPLACE_ALL_BUTTON_NAME);
+        replaceAllButton.setText(" " + Config.getString("editor.replacePanel.replaceAll") + "  ");
+        replaceAllButton.setFont(font);
+        replaceAllButton.addActionListener(this);
+        replaceAllButton.setEnabled(false);
+
+        if (Config.isMacOS()) {
+            replaceButton.putClientProperty("JButton.buttonType", "segmentedTextured");
+            replaceButton.putClientProperty("JButton.segmentPosition", "only");
+            replaceAllButton.putClientProperty("JButton.buttonType", "segmentedTextured");
+            replaceAllButton.putClientProperty("JButton.segmentPosition", "only");
+        }
+
+        replaceBody.add(replaceLabelBox);
+        replaceBody.add(replaceText);
+        optionsBody.add(replaceButton);
+        optionsBody.add(replaceAllButton);
+        rBody.add(replaceBody);
+        rBody.add(optionsBody);
+        rBody.setMaximumSize(rBody.getPreferredSize());
+
+        add(rBody, BorderLayout.WEST);
+    }
+
+    public void requestReplaceTextFocus()
+    {
+        replaceText.requestFocus();
+        replaceText.setText(getReplaceString());
+    }
+
+    protected String getReplaceString()
+    {
+        return replaceString;
+    }
+
+    protected void setReplaceString(String replaceString)
+    {
+        this.replaceString = replaceString;
+    }
+
+    /**
+     * enableButtons enable the once and all buttons
+     * @param enable
+     */
+    protected void enableButtons(boolean enable)
+    {
+        replaceAllButton.setEnabled(enable);
+        replaceButton.setEnabled(enable);
+    }
+
+    /**
+     * 
+     */
+    protected void requestReplaceFocus()
+    {
+        replaceText.requestFocus();
+    }
+
+    /**
+     * Sets the replace textfield to the replaceString passed to the method
+     * @param replaceString the new replace string
+     */
+    protected void populateReplaceField(String replaceString)
+    {
+        replaceText.setText(replaceString);
+    }
+
+    public void changedUpdate(DocumentEvent e)
+    {
+    }
+
+    /**
+     * A document change triggers a replace
+     */
+    public void insertUpdate(DocumentEvent e)
+    {
+        replaceEvent();
+    }
+
+    /**
+     * A document change triggers a replace
+     */
+    public void removeUpdate(DocumentEvent e)
+    {
+        replaceEvent();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ScopeHighlightingPrefDisplay.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ScopeHighlightingPrefDisplay.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3825f2f0305f907f2c4935474d304cf8de73874
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/ScopeHighlightingPrefDisplay.java
@@ -0,0 +1,204 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import java.awt.Color;
+import java.awt.GridLayout;
+import java.util.Hashtable;
+
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+
+/**
+ * A manager for the components used to manipulate the scope highlighting strength
+ * preference.
+ * 
+ * @author Marion Zalk
+ */
+public class ScopeHighlightingPrefDisplay implements ChangeListener
+{
+    public static final int MIN=0;
+    public static final int MAX=20;
+    JSlider slider;
+    JPanel colorPanel;
+    JPanel greenPanelArea;
+    JPanel yellowPanelArea;
+    JPanel pinkPanelArea;
+    JPanel bluePanelArea;
+    Color greenArea = BlueJSyntaxView.GREEN_BASE;
+    Color pinkArea = BlueJSyntaxView.PINK_BASE;
+    Color yellowArea = BlueJSyntaxView.YELLOW_BASE;
+    Color blueArea = BlueJSyntaxView.BLUE_BASE;
+    Color greenBorder = BlueJSyntaxView.GREEN_OUTER_BASE;
+    Color pinkBorder = BlueJSyntaxView.PINK_OUTER_BASE;
+    Color yellowBorder = BlueJSyntaxView.YELLOW_OUTER_BASE;
+    Color blueBorder = BlueJSyntaxView.BLUE_OUTER_BASE;
+    Color greenSetting, greenSettingBorder;
+    Color yellowSetting, yellowSettingBorder;
+    Color pinkSetting, pinkSettingBorder;
+    Color blueSetting, blueSettingBorder;
+    Color bg;
+
+    /**
+     * Constructor that sets up the look and feel for the scope highlighting color slider
+     * and the panel displaying the affects of changing the value of the slider
+     */
+    public ScopeHighlightingPrefDisplay()
+    {
+        MoeSyntaxDocument.getColors();
+        bg = MoeSyntaxDocument.getBackgroundColor();
+        //initialises the slider functionality
+        {
+            slider=new JSlider(MIN, MAX);
+            //set the transparency value from the prefMgr
+            slider.setValue(PrefMgr.getScopeHighlightStrength());
+            //labels
+            Hashtable<Integer, JLabel>labelTable = new Hashtable<Integer, JLabel>();
+            labelTable.put(new Integer(MIN), new JLabel(Config.getString
+                    ("prefmgr.edit.highlightLighter")));
+            labelTable.put(new Integer(MAX), new JLabel(Config.getString
+                    ("prefmgr.edit.highlightDarker")));
+            slider.setLabelTable( labelTable );
+            slider.setPaintLabels(true);
+            slider.addChangeListener(this);
+        }
+        //initialises the color palette
+        {
+            colorPanel=new JPanel(new GridLayout(4,1,0,0));     
+            colorPanel.setBorder(BorderFactory.createLineBorder(bg, 10));
+            colorPanel.setBackground(bg);
+            greenPanelArea=new JPanel();
+            yellowPanelArea=new JPanel();
+            pinkPanelArea=new JPanel();
+            bluePanelArea=new JPanel();
+            setPaletteValues();
+            colorPanel.add(greenPanelArea);
+            colorPanel.add(yellowPanelArea);
+            colorPanel.add(pinkPanelArea);  
+            colorPanel.add(bluePanelArea);
+        }
+    }
+
+    /**
+     * Returns the highlighter slider
+     */
+    protected JSlider getHighlightStrengthSlider()
+    {  
+        return slider;
+    }
+
+    /**
+     * Returns the color palette
+     */
+    protected JPanel getColourPalette()
+    {
+        return colorPanel;
+    }
+
+    /**
+     * The value of the slider
+     */
+    protected int getStrengthValue()
+    {
+        return slider.getValue();   
+    }
+
+    /**
+     * Setting the colour relative to the background colour of the document
+     * and using the value of the slider to calculate strength
+     */
+    private Color getReducedColor(Color c)
+    {
+        return BlueJSyntaxView.getReducedColor(c.getRed(), c.getGreen(),
+                c.getBlue(), getStrengthValue());
+    }
+
+    /**
+     * Sets the green palette
+     */
+    protected void setGreenPalette()
+    {
+        greenSetting= getReducedColor(greenArea);
+        greenPanelArea.setBackground(greenSetting);
+        greenSettingBorder=getReducedColor(greenBorder);
+        greenPanelArea.setBorder(BorderFactory.createLineBorder(greenSettingBorder));
+    }
+
+    /**
+     * Sets the yellow palette
+     */
+    protected void setYellowPalette()
+    {
+        yellowSetting= getReducedColor(yellowArea);
+        yellowPanelArea.setBackground(yellowSetting);
+        yellowSettingBorder=getReducedColor(yellowBorder);
+        yellowPanelArea.setBorder(BorderFactory.createLineBorder(yellowSettingBorder));
+    }
+
+    /**
+     * Sets the pink palette
+     */
+    protected void setPinkPalette()
+    {
+        pinkSetting= getReducedColor(pinkArea);
+        pinkPanelArea.setBackground(pinkSetting);
+        pinkSettingBorder=getReducedColor(pinkBorder);
+        pinkPanelArea.setBorder(BorderFactory.createLineBorder(pinkSettingBorder));
+    }
+
+    /**
+     * Sets the blue palette
+     */
+    protected void setBluePalette()
+    {
+        blueSetting = getReducedColor(blueArea);
+        bluePanelArea.setBackground(blueSetting);
+        blueSettingBorder=getReducedColor(blueBorder);
+        bluePanelArea.setBorder(BorderFactory.createLineBorder(blueSettingBorder));
+    }
+
+    /**
+     * When the slider is moved, the color palette updates immediately
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+        setPaletteValues();
+    }
+
+    /**
+     * Updates the palette with the color of the wash and border
+     */
+    private void setPaletteValues()
+    {
+        setGreenPalette();
+        setYellowPalette();
+        setBluePalette();
+        setPinkPalette();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/StatusLabel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/StatusLabel.java
new file mode 100644
index 0000000000000000000000000000000000000000..d0b06f4f2e639997c0a32c23e6bd39615eb3d8f0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/StatusLabel.java
@@ -0,0 +1,101 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+
+import java.awt.*;              // New Event model    
+import javax.swing.*;
+
+/**
+ * Status label for the Moe editor.
+ * 
+ * @author Michael Kolling
+ */
+public final class StatusLabel extends JLabel
+{
+    // ---------------- CONSTANTS -----------------
+
+    private static Font statusFont = new Font("SansSerif",
+            Font.BOLD | Font.ITALIC, PrefMgr.getEditorFontSize() - 1);
+
+    // current save state
+    static final int READONLY = 0;
+    static final int SAVED = 1;   
+    static final int CHANGED = 2; 
+
+    private final String[] stateString = { 
+        Config.getString("editor.state.readOnly"), 
+        Config.getString("editor.state.saved"),
+        Config.getString("editor.state.changed")
+    };
+
+    // ------------ INSTANCE VARIABLES ------------
+
+    private int state;
+
+    // -------------- CONSTRUCTORS ----------------
+
+    public StatusLabel(int initialState)
+    {
+        super("", JLabel.CENTER);
+        setText(stateString[initialState]);
+        setFont(statusFont);
+        setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
+        state = initialState;
+    }
+
+    // ------------- PUBLIC METHODS ---------------
+
+    public boolean isSaved() 
+    {
+        return (state != CHANGED);
+    }
+
+    public boolean isChanged() 
+    {
+        return (state == CHANGED);
+    }
+
+    public boolean isReadOnly() 
+    {
+        return (state == READONLY);
+    }
+
+    public void setState(int newState)
+    {
+        state = newState;
+        setText(stateString[state]);
+    }
+    
+    public void refresh()
+    {
+        setFont(statusFont);
+    }
+    
+    public static void resetFont()
+    {
+        int fontSize = Math.max(PrefMgr.getEditorFontSize() - 1, 1);
+        statusFont = new Font("SansSerif", Font.BOLD | Font.ITALIC, fontSize);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/TextUtilities.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/TextUtilities.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae812d866266bc234e8f88fc2c6889c176ce7781
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/TextUtilities.java
@@ -0,0 +1,193 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+/*
+ * TextUtilities.java - Utility functions used by the text area classes
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+import javax.swing.text.*;
+
+/**
+ * Class with several utility functions used by the text area component.
+ * @author Slava Pestov
+ * @version $Id: TextUtilities.java 6619 2009-09-04 02:33:09Z davmac $
+ */
+public class TextUtilities
+{
+    /**
+     * Returns the offset of the bracket matching the one at the
+     * specified offset of the document, or -1 if the bracket is
+     * unmatched (or if the character is not a bracket).
+     * @param doc The document
+     * @param offset The offset
+     * @exception BadLocationException If an out-of-bounds access
+     * was attempted on the document text
+     */
+    public static int findMatchingBracket(Document doc, int offset)
+    throws BadLocationException
+    {
+        if(doc.getLength() == 0) {
+            return -1;
+        }
+
+        char c = doc.getText(offset, 1).charAt(0);
+        char cprime; // c` - corresponding character
+        boolean direction; // true = back, false = forward
+
+        switch(c)
+        {
+        case '(': cprime = ')'; direction = false; break;
+        case ')': cprime = '('; direction = true; break;
+        case '[': cprime = ']'; direction = false; break;
+        case ']': cprime = '['; direction = true; break;
+        case '{': cprime = '}'; direction = false; break;
+        case '}': cprime = '{'; direction = true; break;
+        default: return -1;
+        }
+
+        int count = 1;
+        int step;
+        int texttOffset;
+        int len;
+        int i;
+        if (direction) {
+            // search backwards
+            step = -1;
+            texttOffset = 0;
+            len = offset;
+            i = len - 1;
+        }
+        else {
+            // search forwards
+            step = 1;
+            texttOffset = offset + 1;
+            len = doc.getLength() - texttOffset;
+            i = 0;
+        }
+        String textt = doc.getText(texttOffset, len);
+
+        while (len > 0) {
+            char x = textt.charAt(i);
+            if(x == c) {
+                count++;
+            }
+
+            // If text[i] == cprime, we have found a
+            // opening bracket, so we return i if
+            // --count == 0
+            else if(x == cprime)
+            {
+                if (--count == 0) {
+                    return i + texttOffset;
+                }
+            }
+
+            len--;
+            i += step;
+
+            if (x == '\"' || x == '\'') {
+                char quoteChar = x;
+                // A quoted string, need to find the matching quote before matching
+                // further brackets...
+                while (len > 0) {
+                    x = textt.charAt(i);
+                    if (x == quoteChar) {
+                        // Found the matching quote, as long as it is not \-quoted.
+                        if (i == 0 || textt.charAt(i - 1) != '\\') {
+                            len--;
+                            i += step;
+                            break;
+                        }
+                    }
+                    len--;
+                    i += step;
+                }
+            }
+        }
+
+        // Nothing found
+        return -1;
+    }
+
+    /**
+     * Locates the start of the word at the specified position.
+     * @param line The text
+     * @param pos The position
+     */
+    public static int findWordStart(String line, int pos, String noWordSep)
+    {
+        char ch = line.charAt(pos - 1);
+
+        if(noWordSep == null)
+            noWordSep = "";
+        boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
+                && noWordSep.indexOf(ch) == -1);
+
+        int wordStart = 0;
+        for(int i = pos - 1; i >= 0; i--)
+        {
+            ch = line.charAt(i);
+            if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
+                    noWordSep.indexOf(ch) == -1))
+            {
+                wordStart = i + 1;
+                break;
+            }
+        }
+
+        return wordStart;
+    }
+
+    /**
+     * Locates the end of the word at the specified position.
+     * @param line The text
+     * @param pos The position
+     */
+    public static int findWordEnd(String line, int pos, String noWordSep)
+    {
+        char ch = line.charAt(pos);
+
+        if(noWordSep == null)
+            noWordSep = "";
+        boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
+                && noWordSep.indexOf(ch) == -1);
+
+        int wordEnd = line.length();
+        for(int i = pos; i < line.length(); i++)
+        {
+            ch = line.charAt(i);
+            if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
+                    noWordSep.indexOf(ch) == -1))
+            {
+                wordEnd = i;
+                break;
+            }
+        }
+        return wordEnd;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/Token.java b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/Token.java
new file mode 100644
index 0000000000000000000000000000000000000000..49498bbe960301d47e591f96ff21350847ebf1f7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/editor/moe/Token.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.editor.moe;
+
+/**
+ * This is a replacement for the Token class from jedit.
+ * 
+ * @author Davin McCall
+ */
+public class Token
+{
+    public byte id;     // Token type, one of the constants declared below
+    public int length;  // Length of text represented by this token
+    public Token next;  // Next token in the chain
+    
+    public static final byte NULL = 0;
+    public static final byte COMMENT1 = 1;  // normal comment
+    public static final byte COMMENT2 = 2;  // javadoc comment
+    public static final byte COMMENT3 = 3;  // standout comment
+    public static final byte KEYWORD1 = 4;
+    public static final byte KEYWORD2 = 5;
+    public static final byte KEYWORD3 = 6;
+    public static final byte PRIMITIVE = 7;
+    public static final byte LITERAL1 = 8;
+    public static final byte LITERAL2 = 9;
+    public static final byte LABEL = 10;
+    public static final byte OPERATOR = 11;
+    public static final byte INVALID = 12;
+    
+    /* The number of token ids (above) */
+    public static final byte ID_COUNT = 13;
+    
+    public static final byte END = 100;
+    
+    public Token(int length, byte id)
+    {
+        this.id = id;
+        this.length = length;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BArray.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..8d16ded63c2035833ebf37f9b0b92b97c110d02d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BArray.java
@@ -0,0 +1,63 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import bluej.pkgmgr.*;
+import com.sun.jdi.*;
+
+/**
+ * A wrapper for an array object in BlueJ.
+ * Behaviour is similar to the Java reflection API.
+ * 
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class BArray 
+{
+  /**
+   * Given a BlueJ array object, returns the item at the given index.
+   * In the case that the array contains elements of primitive type (<code>int</code> etc.), 
+   * the return value is of the appropriate Java wrapper type (<code>Integer</code> etc.).
+   * In the case that the array is composed of BlueJ objects (including nested arrays) then 
+   * an appropriate BObject will be returned. 
+   * 
+   * @param thisArray This must be an array object of which you want the given item.
+   * @param itemIndex The index in the array where you want to peek.
+   * 
+   * @return an Object that encapsulate the specific item or null if not an array.
+   * @throws ProjectNotOpenException if the project to which this array belongs has been closed by the user.
+   * @throws PackageNotFoundException if the package to which this array belongs has been deleted by the user.
+   */
+    public static Object getValue ( BObject thisArray, int itemIndex )
+    throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ObjectReference objRef = thisArray.getObjectReference();
+
+        if ( ! ( objRef instanceof ArrayReference ) ) return null;
+
+        ArrayReference array = (ArrayReference)objRef;
+
+        Value val = array.getValue(itemIndex);
+
+        PkgMgrFrame aFrame = thisArray.getPackageFrame();
+        return BField.doGetVal(aFrame, "Array", val);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BClass.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c2371f270f608329ad2fc697822e16cc5c3a7cc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BClass.java
@@ -0,0 +1,715 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import bluej.compiler.JobQueue;
+import bluej.extensions.editor.Editor;
+import bluej.extensions.editor.EditorBridge;
+import bluej.parser.symtab.ClassInfo;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.Target;
+import bluej.utility.JavaNames;
+import bluej.views.ConstructorView;
+import bluej.views.FieldView;
+import bluej.views.MethodView;
+import bluej.views.View;
+
+/**
+ * A wrapper for a class. This is used to represent both classes which have a representation
+ * within the BlueJ project, and those that don't.
+ * 
+ * <p>From an instance of this class you can create BlueJ objects and call their methods.
+ * Behaviour is similar to the Java reflection API.
+ *
+ * @author Damiano Bolla, University of Kent at Canterbury, 2002,2003,2004
+ */
+public class BClass
+{
+    private static Map<Identifier,BClass> externalClasses = new WeakHashMap<Identifier,BClass>();
+
+    private Identifier classId;
+
+    /**
+     * Constructor for the BClass.
+     * It is duty of the caller to guarantee that it is a reasonable classId
+     */
+    BClass(Identifier thisClassId)
+    {
+        classId = thisClassId;
+    }
+    
+    /**
+     * Get a BClass for some class identifier. To be used for classes which don't have a
+     * representation (ClassTarget) in BlueJ.
+     */
+    synchronized static BClass getBClass(Identifier classId)
+    {
+        BClass r = externalClasses.get(classId);
+        if (r == null) {
+            r = new BClass(classId);
+            externalClasses.put(classId, r);
+        }
+        return r;
+    }
+    
+
+    /**
+     * Notification that the name of the class has changed.
+     * @param newName  The new class name, fully qualified.
+     */
+    void nameChanged(String newName)
+    {
+        try {
+            Project proj = classId.getBluejProject();
+            Package pkg = classId.getBluejPackage();
+            classId = new Identifier(proj, pkg, newName);
+        }
+        catch (ProjectNotOpenException pnoe) { }
+        catch (PackageNotFoundException pnfe) { }
+    }
+
+    /**
+     * Returns the name of this BClass.
+     * 
+     * @return the fully qualified name of the wrapped BlueJ class.
+     */
+    public final String getName()
+    {
+        return classId.getClassName();
+    }
+
+    /**
+     * Removes this class from BlueJ, including the underlying files.
+     *
+     * @throws  ProjectNotOpenException   if the project to which this class belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this class belongs has been deleted by the user.
+     * @throws  ClassNotFoundException    if the class has been deleted by the user, or if the class does
+     *                                    not otherwise have a representation within the project.
+     */
+    public void remove()
+             throws ProjectNotOpenException, PackageNotFoundException, ClassNotFoundException
+    {
+        ClassTarget bluejClass = classId.getClassTarget();
+        if (bluejClass == null) {
+            throw new ClassNotFoundException("Can't find class: " + classId.getClassName());
+        }
+        bluejClass.remove();
+    }
+
+
+    /**
+     * Returns the Java class being wrapped by this BClass.
+     * Use this method when you need more information about the class than
+     * is provided by the BClass interface. E.g.:
+     * 
+     * <ul>
+     * <li>What is the real class being hidden?
+     * <li>Is it an array?
+     * <li>What is the type of the array element?
+     * </ul>
+     *
+     * <p>Note that this is for information only. If you want to interact with BlueJ you must
+     * use the methods provided in BClass.
+     *
+     * @return                           The javaClass value
+     * @throws  ProjectNotOpenException  if the project to which this class belongs has been closed by the user.
+     * @throws  ClassNotFoundException   if the class has been deleted by the user.
+     */
+    public Class<?> getJavaClass()
+             throws ProjectNotOpenException, ClassNotFoundException
+    {
+        return classId.getJavaClass();
+    }
+
+
+    /**
+     * Returns the package this class belongs to.
+     * Similar to reflection API.
+     *
+     * @return                            The package value
+     * @throws  ProjectNotOpenException   if the project to which this class belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this class belongs has been deleted by the user.
+     */
+    public BPackage getPackage() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package bluejPkg = classId.getBluejPackage();
+        return bluejPkg.getBPackage();
+    }
+
+
+    /**
+     * Returns a proxy object that provide an interface to the editor for this BClass.
+     * If an editor already exists, a proxy for it is returned. Otherwise, an editor is created but not made visible.
+     *
+     * @return                            The proxy editor object or null if it cannot be created
+     * @throws  ProjectNotOpenException   if the project to which this class belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this class belongs has been deleted by the user.
+     */
+    public Editor getEditor() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget aTarget = classId.getClassTarget();
+        if (aTarget == null) {
+            return null;
+        }
+        
+        return EditorBridge.newEditor(aTarget);
+    }
+    
+    /**
+     * Finds out whether this class has source code available.
+     */
+    boolean hasSourceCode() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget aTarget = classId.getClassTarget();
+        return aTarget == null || aTarget.hasSourceCode();
+    }
+
+
+    /**
+     * Checks to see if this class has been compiled.
+     *
+     * @return                            true if it is compiled false othervise.
+     * @throws  ProjectNotOpenException   if the project to which this class belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this class belongs has been deleted by the user.
+     */
+    public boolean isCompiled()
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget aTarget = classId.getClassTarget();
+        return aTarget == null || aTarget.isCompiled();
+    }
+
+
+    /**
+     * Compile this class, and any dependents.
+     * 
+     * <p>After the compilation has finished the method isCompiled() can be used to determined the class
+     * status.
+     * 
+     * <p>A single CompileEvent will be generated with all dependent files listed.
+     * 
+     * <p>A call to this method is equivalent to: <code>compile(waitCompileEnd, false)</code>.
+     *
+     * @param  waitCompileEnd                   <code>true</code> waits for the compilation to be finished.
+     * @throws  ProjectNotOpenException         if the project to which this class belongs has been closed.
+     * @throws  PackageNotFoundException        if the package to which this class belongs has been deleted.
+     * @throws  CompilationNotStartedException  if BlueJ is currently executing Java code.
+     */
+    public void compile(boolean waitCompileEnd)
+             throws ProjectNotOpenException, PackageNotFoundException, CompilationNotStartedException
+    {
+        compile(waitCompileEnd, false);
+    }
+
+    /**
+     * Compile this class, and any dependents, optionally without showing compilation errors to the user.
+     * 
+     * <p>After the compilation has finished the method isCompiled() can be used to determined the class
+     * status.
+     * 
+     * <p>A single CompileEvent with all dependent files listed will be generated.
+     *
+     * @param  waitCompileEnd                   <code>true</code> waits for the compilation to be finished.
+     * @param  forceQuiet                       if true, compilation errors will not be shown/highlighted to the user.
+     * @throws  ProjectNotOpenException         if the project to which this class belongs has been closed.
+     * @throws  PackageNotFoundException        if the package to which this class belongs has been deleted.
+     * @throws  CompilationNotStartedException  if BlueJ is currently executing Java code.
+     */
+    public void compile(boolean waitCompileEnd, boolean forceQuiet)
+             throws ProjectNotOpenException, PackageNotFoundException, CompilationNotStartedException
+    {
+        Package bluejPkg = classId.getBluejPackage();
+        ClassTarget aTarget = classId.getClassTarget();
+        if (aTarget == null) {
+            throw new CompilationNotStartedException("Class target does not (any longer) exist");
+        }
+
+        if (!bluejPkg.isDebuggerIdle()) {
+            throw new CompilationNotStartedException("BlueJ is currently executing Java code");
+        }
+
+        // Ask for compilation of this target
+        bluejPkg.compile(aTarget, forceQuiet);
+
+        // if requested wait for the compilation to finish.
+        if (waitCompileEnd) {
+            JobQueue.getJobQueue().waitForEmptyQueue();
+        }
+
+        // We do not return aTarget.isCompiled() since it is meaningless when we do not wait
+        // for the compilation to be finished.
+    }
+
+
+    /**
+     * Utility. Finds the package name given a fully qualified name
+     * If no package exist then an empty string is returned.
+     *
+     * @param  fullyQualifiedName  Description of the Parameter
+     * @return                     Description of the Return Value
+     */
+    private String findPkgName(String fullyQualifiedName)
+    {
+        if (fullyQualifiedName == null) {
+            return "";
+        }
+
+        int dotIndex = fullyQualifiedName.lastIndexOf(".");
+        // If there is no package name to be found return an empty one.
+        if (dotIndex < 0) {
+            return "";
+        }
+
+        return fullyQualifiedName.substring(0, dotIndex);
+    }
+
+
+    /**
+     * Returns the superclass of this class.
+     * 
+     * <p>Similar to reflection API.
+     * 
+     * <p>If this class represents either the Object class, an interface,
+     * a primitive type, or void, then null is returned.
+     *
+     * @return                            The superclass value
+     * @throws  ProjectNotOpenException   if the project to which this class belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this class belongs has been deleted by the user.
+     * @throws  ClassNotFoundException    if the class has been deleted by the user.
+     */
+    public BClass getSuperclass()
+             throws ProjectNotOpenException, PackageNotFoundException, ClassNotFoundException
+    {
+        Project bluejPrj = classId.getBluejProject();
+        
+        ClassTarget ct = classId.getClassTarget();
+        if (ct != null && ! ct.isCompiled()) {
+            // Class is not compiled: we can still know the superclass!
+            ClassInfo info = ct.getSourceInfo().getInfo(getJavaFile(), ct.getPackage());
+            if (info != null) {
+                String superClass = info.getSuperclass();
+                superClass = (superClass == null) ? "" : superClass;
+                String pkgString = JavaNames.getPrefix(superClass);
+                Package bjPkg = bluejPrj.getPackage(pkgString);
+                if (bjPkg != null) {
+                    Target sct = bjPkg.getTarget(JavaNames.getBase(superClass));
+                    if (sct instanceof ClassTarget) {
+                        return ((ClassTarget) sct).getBClass();
+                    }
+                }
+                
+                // Superclass isn't in the project?
+                Identifier sid = new Identifier(bluejPrj, null, superClass);
+                return BClass.getBClass(sid);
+            }
+            
+            return null; 
+        }
+
+        View bluejView = classId.getBluejView();
+        View superView = bluejView.getSuper();
+
+        // If this <code>Class</code> represents either the Object class, an interface,
+        // a primitive type, or void, then null is returned
+        if (superView == null) {
+            return null;
+        }
+
+        // The class exists, is it part of this project ?
+        Class<?> aTest = bluejPrj.loadClass(superView.getQualifiedName());
+        // Really strange, a superclass  that is not part of this project classloader...
+        if (aTest == null) {
+            return null;
+        }
+
+        String classPkgName = findPkgName(superView.getQualifiedName());
+
+        // Now I need to find out to what package it belongs to...
+        Package bluejPkg = bluejPrj.getPackage(classPkgName);
+        if (bluejPkg != null) {
+            // I need the Target for the class I want.
+            Target aTarget = bluejPkg.getTarget (superView.getBaseName());
+
+            if (aTarget instanceof ClassTarget) {
+                ClassTarget classTarget = (ClassTarget) aTarget;
+                return classTarget.getBClass();
+            }
+        }
+
+        Identifier id = new Identifier(bluejPrj, null, superView.getQualifiedName());
+        return BClass.getBClass(id);
+    }
+
+
+    /**
+     * Returns all the constructors of this class.
+     * Similar to reflection API.
+     *
+     * @return                           The constructors value
+     * @throws  ProjectNotOpenException  if the project to which this class belongs has been closed by the user.
+     * @throws  ClassNotFoundException   if the class has been deleted by the user.
+     */
+    public BConstructor[] getConstructors()
+             throws ProjectNotOpenException, ClassNotFoundException
+    {
+        View bluejView = classId.getBluejView();
+
+        ConstructorView[] constructorViews = bluejView.getConstructors();
+        BConstructor[] result = new BConstructor[constructorViews.length];
+        for (int index = 0; index < constructorViews.length; index++) {
+            result[index] = new BConstructor(classId, constructorViews[index]);
+        }
+
+        return result;
+    }
+
+
+    /**
+     * Returns the constructor for this class which has the given signature.
+     * Similar to reflection API.
+     *
+     * @param  signature                 the signature of the required constructor.
+     * @return                           the requested constructor of this class, or null if
+     * the class has not been compiled or the constructor cannot be found.
+     * @throws  ProjectNotOpenException  if the project to which this class belongs has been closed by the user.
+     * @throws  ClassNotFoundException   if the class has been deleted by the user.
+     */
+    public BConstructor getConstructor(Class<?>[] signature)
+             throws ProjectNotOpenException, ClassNotFoundException
+    {
+        View bluejView = classId.getBluejView();
+
+        ConstructorView[] constructorViews = bluejView.getConstructors();
+        for (int index = 0; index < constructorViews.length; index++) {
+            BConstructor aConstr = new BConstructor(classId, constructorViews[index]);
+            if (aConstr.matches(signature)) {
+                return aConstr;
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * Returns the declared methods of this class.
+     * Similar to reflection API.
+     *
+     * @return                           The declaredMethods value
+     * @throws  ProjectNotOpenException  if the project to which this class belongs has been closed by the user.
+     * @throws  ClassNotFoundException   if the class has been deleted by the user.
+     */
+    public BMethod[] getDeclaredMethods()
+             throws ProjectNotOpenException, ClassNotFoundException
+    {
+        View bluejView = classId.getBluejView();
+
+        MethodView[] methodView = bluejView.getDeclaredMethods();
+        BMethod[] methods = new BMethod[methodView.length];
+
+        for (int index = 0; index < methods.length; index++) {
+            methods[index] = new BMethod(classId, methodView[index]);
+        }
+
+        return methods;
+    }
+
+
+    /**
+     * Returns the declared method of this class which has the given signature.
+     * Similar to reflection API.
+     *
+     * @param  methodName                The name of the method.
+     * @param  params                    The parameters of the method. Pass a zero length array if the method takes no arguments. 
+     * @return                           The declaredMethod value or <code>null</code> if the method is not found.
+     * @throws  ProjectNotOpenException  if the project to which this class belongs has been closed by the user.
+     * @throws  ClassNotFoundException   if the class has been deleted by the user.
+     */
+    public BMethod getDeclaredMethod(String methodName, Class<?>[] params)
+             throws ProjectNotOpenException, ClassNotFoundException
+    {
+        View bluejView = classId.getBluejView();
+        MethodView[] methodView = bluejView.getDeclaredMethods();
+
+        for (int index = 0; index < methodView.length; index++) {
+            BMethod aResul = new BMethod(classId, methodView[index]);
+            if (aResul.matches(methodName, params)) {
+                return aResul;
+            }
+        }
+
+        return null;
+    }
+
+    
+    /**
+     * Returns all methods of this class, those declared and those inherited from all ancestors. 
+     * Similar to reflection API, except that all methods, declared and inherited, are returned, and not only the public ones.
+     * That is, it returns all public, private, protected, and package-access methods, inherited or declared.
+     * The elements in the array returned are not sorted and are not in any particular order.
+     *
+     * @return                           The Methods value
+     * @throws  ProjectNotOpenException  if the project to which this class belongs has been closed by the user.
+     * @throws  ClassNotFoundException   if the class has been deleted by the user.
+     */
+    public BMethod[] getMethods()
+             throws ProjectNotOpenException, ClassNotFoundException
+    {
+        View bluejView = classId.getBluejView();
+
+        MethodView[] methodView = bluejView.getAllMethods();
+        BMethod[] methods = new BMethod[methodView.length];
+
+        for (int index = 0; index < methods.length; index++) {
+            methods[index] = new BMethod(classId, methodView[index]);
+        }
+
+        return methods;
+    }
+
+    
+    /**
+     * Returns the method of this class with the given signature.
+     * Similar to reflection API, except that all methods, declared and inherited, are searched, and not only the public ones.
+     * That is, it searches all public, private, protected, and package-access methods, declared or inherited from all ancestors.
+     * If the searched method has been redefined, the returned method is chosen arbitrarily from the list of inherited and declared methods.
+     *
+     * @param  methodName                The name of the method
+     * @param  params                    The parameters of the method. Pass a zero length array if the method takes no arguments. 
+     * @return                           The Method value or <code>null</code> if the method is not found.
+     * @throws  ProjectNotOpenException  If the project to which this class belongs has been closed by the user
+     * @throws  ClassNotFoundException   If the class has been deleted by the user
+     */
+    public BMethod getMethod(String methodName, Class<?>[] params)
+             throws ProjectNotOpenException, ClassNotFoundException
+    {
+        View bluejView = classId.getBluejView();
+        MethodView[] methodView = bluejView.getAllMethods();
+ 
+        for (int index = 0; index < methodView.length; index++) {
+            BMethod aResul = new BMethod(classId, methodView[index]);
+            if (aResul.matches(methodName, params)) {
+                return aResul;
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Returns all the fields of this class.
+     * Similar to reflection API.
+     *
+     * @return                           The fields value
+     * @throws  ProjectNotOpenException  if the project to which this class belongs has been closed by the user.
+     * @throws  ClassNotFoundException   if the class has been deleted by the user.
+     */
+    public BField[] getFields()
+             throws ProjectNotOpenException, ClassNotFoundException
+    {
+        View bluejView = classId.getBluejView();
+
+        FieldView[] fieldView = bluejView.getAllFields();
+        BField[] bFields = new BField[fieldView.length];
+        for (int index = 0; index < fieldView.length; index++) {
+            bFields[index] = new BField(classId, fieldView[index]);
+        }
+
+        return bFields;
+    }
+
+
+    /**
+     * Returns the field of this class which has the given name.
+     * Similar to Reflection API.
+     *
+     * @param  fieldName                 Description of the Parameter
+     * @return                           The field value
+     * @throws  ProjectNotOpenException  if the project to which this class belongs has been closed by the user.
+     * @throws  ClassNotFoundException   if the class has been deleted by the user.
+     */
+    public BField getField(String fieldName)
+             throws ProjectNotOpenException, ClassNotFoundException
+    {
+        if (fieldName == null) {
+            return null;
+        }
+
+        View bluejView = classId.getBluejView();
+
+        FieldView[] fieldView = bluejView.getAllFields();
+        for (int index = 0; index < fieldView.length; index++) {
+            BField result = new BField(classId, fieldView[index]);
+            if (result.getName().equals(fieldName)) {
+                return result;
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Returns the class target of this class. May return <code>null</code> if
+     * the class target is no longer valid.
+     * 
+     * @return The class target of this class or <code>null</code> if there is
+     *         no such class target.
+     * @throws ProjectNotOpenException
+     *             if the project to which this class belongs has been closed by
+     *             the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class belongs has been deleted
+     *             by the user.
+     */
+    public BClassTarget getClassTarget() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget classTarget = classId.getClassTarget();
+        return (classTarget != null) ? classTarget.getBClassTarget() : null;
+    }
+
+    /**
+     * Returns this class's .class file (or null, if the class no longer exists in the project).
+     *
+     * @return                            the class .class file.
+     * @throws  ProjectNotOpenException   if the project to which this class belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this class belongs has been deleted by the user.
+     */
+    public File getClassFile()
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget aTarget = classId.getClassTarget();
+        if (aTarget == null) {
+            return null;
+        }
+
+        return aTarget.getClassFile();
+    }
+
+
+    /**
+     * Returns this class's .java file.
+     * If the file is currently being edited, calling this method will cause it to be saved.
+     *
+     * @return                            the class .java file.
+     * @throws  ProjectNotOpenException   if the project to which this class belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this class belongs has been deleted by the user.
+     */
+    public File getJavaFile()
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget aTarget = classId.getClassTarget();
+        if (aTarget == null) {
+            return null;
+        }
+        if(aTarget.editorOpen()) {
+            bluej.editor.Editor anEditor = aTarget.getEditor();
+            if (anEditor != null) {
+                try {
+                    anEditor.save();
+                }
+                catch (IOException ioe) {}
+            }
+        }
+
+        return aTarget.getSourceFile();
+    }
+
+
+    /**
+     * Signal to BlueJ that an extension is about to begin changing the source file of this class.
+     * The file containing the source for this class can be found using getJavaFile();
+     * If the file is currently being edited it will be saved and the editor will be set read-only.
+     *
+     * @throws  ProjectNotOpenException   if the project to which this class belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this class belongs has been deleted by the user.
+     * @deprecated As of BlueJ 2.0, replaced by {@link Editor#setReadOnly(boolean readOnly)}
+     */
+    public void beginChangeSource()
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget aTarget = classId.getClassTarget();
+        if (aTarget == null) {
+            return;
+        }
+        bluej.editor.Editor anEditor = aTarget.getEditor();
+        if (anEditor == null) {
+            return;
+        }
+
+        try {
+            anEditor.save();
+        }
+        catch (IOException ioe) {}
+        anEditor.setReadOnly(true);
+    }
+
+
+    /**
+     * Signal to BlueJ that an extension has finished changing the source file of this class.
+     * If the file is currently being edited, this will cause it to be re-loaded and the editor to be set read/write.
+     *
+     * @throws  ProjectNotOpenException   if the project to which this class belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this class belongs has been deleted by the user.
+     * @deprecated As of BlueJ 2.0, replaced by {@link Editor#setReadOnly(boolean readOnly)}
+     */
+    public void endChangeSource()
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget aTarget = classId.getClassTarget();
+        if (aTarget == null) {
+            return;
+        }
+        bluej.editor.Editor anEditor = aTarget.getEditor();
+        if (anEditor == null) {
+            return;
+        }
+
+        anEditor.reloadFile();
+        anEditor.setReadOnly(false);
+    }
+
+
+
+    /**
+     * Returns a string representation of the Object
+     *
+     * @return    Description of the Return Value
+     */
+    public String toString()
+    {
+        try {
+            Class<?> javaClass = classId.getJavaClass();
+            return "BClass: " + javaClass.getName();
+        }
+        catch (ExtensionException exc) {
+            return "BClass: INVALID";
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BClassTarget.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BClassTarget.java
new file mode 100644
index 0000000000000000000000000000000000000000..a401637764050d8938e53144bb3fd4dbd49f2349
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BClassTarget.java
@@ -0,0 +1,340 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.DependentTarget;
+
+/**
+ * A wrapper for a class target (vertex) in the class diagram of BlueJ.
+ * 
+ * @author Simon Gerlach
+ */
+public class BClassTarget
+{
+    private Identifier targetId;
+
+    /**
+     * Constructor. Creates a new {@link BClassTarget}.
+     * 
+     * @param targetId
+     *            The {@link Identifier} which represents the corresponding
+     *            class target. It is duty of the caller to guarantee that this
+     *            <code>targetId</code> is reasonable.
+     */
+    BClassTarget(Identifier targetId)
+    {
+        this.targetId = targetId;
+    }
+
+    /**
+     * Returns the wrapped {@link ClassTarget} or <code>null</code> if no such
+     * class target exist.
+     * 
+     * @return The wrapped {@link ClassTarget}.
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    ClassTarget getClassTarget() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        return targetId.getClassTarget();
+    }
+
+    /**
+     * Notification that the name of the underlying class has changed.
+     * 
+     * @param newName
+     *            The new class name, fully qualified.
+     */
+    void nameChanged(String newName)
+    {
+        try {
+            Project bluejProject = targetId.getBluejProject();
+            Package bluejPackage = targetId.getBluejPackage();
+
+            targetId = new Identifier(bluejProject, bluejPackage, newName);
+        } catch (ProjectNotOpenException e) {
+            // cannot happen: the renaming of a class requires an open project
+            // and package
+        } catch (PackageNotFoundException e) {
+            // cannot happen: the renaming of a class requires an open project
+            // and package
+        }
+    }
+
+    /**
+     * Recalculates the dependency arrows associated with this class target.
+     * This may be necessary if the user has moved or resized the class target.
+     * 
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    public void recalcDependentPositions() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget classTarget = getClassTarget();
+        
+        if (classTarget != null) {
+            classTarget.recalcDependentPositions();
+        }
+    }
+
+    /**
+     * Revalidates the editor the wrapped class target is part of.
+     * 
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    public void revalidate() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget classTarget = getClassTarget();
+
+        if (classTarget != null) {
+            classTarget.getPackage().getEditor().revalidate();
+        }
+    }
+
+    /**
+     * Returns the class of this class target. Similar to Reflection API. Note
+     * the naming inconsistency, which avoids a clash with
+     * {@link java.lang.Object#getClass()}. May return <code>null</code> if this
+     * class target is no longer valid.
+     * 
+     * @return The class of this class target or <code>null</code> if there is
+     *         no such class.
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    public BClass getBClass() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget classTarget = getClassTarget();
+        return (classTarget != null) ? classTarget.getBClass() : null;
+    }
+
+    /**
+     * Indicates whether this class target represents an interface.
+     * 
+     * @return <code>true</code> if this target represents an interface,
+     *         <code>false</code> otherwise.
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    public boolean isInterface() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget classTarget = getClassTarget();
+        return (classTarget != null) ? classTarget.isInterface() : false;
+    }
+
+    /**
+     * Indicates whether this class target represents a JUnit test.
+     * 
+     * @return <code>true</code> if this target represents a JUnit test,
+     *         <code>false</code> otherwise.
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    public boolean isUnitTest() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget classTarget = getClassTarget();
+        return (classTarget != null) ? classTarget.isUnitTest() : false;
+    }
+
+    /**
+     * Indicates whether this class target shall be visible in the graph.
+     * 
+     * @return <code>true</code> if this class target is visible,
+     *         <code>false</code> otherwise.
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    public boolean isVisible() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget classTarget = getClassTarget();
+        return (classTarget != null) ? classTarget.isVisible() : false;
+    }
+
+    /**
+     * Sets the visible setting of this class target.
+     * 
+     * @param visible
+     *            The new visible setting.
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    public void setVisible(boolean visible) throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget classTarget = getClassTarget();
+
+        if (classTarget != null) {
+            classTarget.setVisible(visible);
+        }
+    }
+
+    /**
+     * Returns the associated target of this class target or <code>null</code>
+     * if there is no associated target. For example, this can be the the class
+     * target of the corresponding test class of the class represented by this
+     * class target.
+     * 
+     * @return The associated target of this class target or <code>null</code>
+     *         if there is no associated target.
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    public BClassTarget getAssociation() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget classTarget = getClassTarget();
+        if (classTarget != null) {
+            DependentTarget association = classTarget.getAssociation();
+
+            if (association instanceof ClassTarget) {
+                return ((ClassTarget) association).getBClassTarget();
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a {@link List} containing all dependencies that have this class
+     * target as their origin.
+     * 
+     * @return A {@link List} containing all outgoing dependencies.
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    public List<BDependency> getOutgoingDependencies() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        List<BDependency> result = new ArrayList<BDependency>();
+        ClassTarget classTarget = getClassTarget();
+
+        if (classTarget != null) {
+            result.addAll(getBDependencies(classTarget.dependencies()));
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a {@link List} containing all dependencies that have this class
+     * target as their destination.
+     * 
+     * @return A {@link List} containing all incoming dependencies.
+     * @throws ProjectNotOpenException
+     *             if the project to which this class target belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this class target belongs has been
+     *             deleted by the user.
+     */
+    public List<BDependency> getIncomingDependencies() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        List<BDependency> result = new ArrayList<BDependency>();
+        ClassTarget classTarget = getClassTarget();
+
+        if (classTarget != null) {
+            result.addAll(getBDependencies(classTarget.dependents()));
+        }
+
+        return result;
+    }
+
+    /**
+     * Takes an {@link Iterator} of type {@link Dependency} and returns a
+     * {@link List} of corresponding {@link BDependency} objects.
+     * 
+     * @param dependencies
+     *            An {@link Iterator} of type {@link Dependency}.
+     * @return A {@link List} of corresponding {@link BDependency} objects.
+     */
+    private List<BDependency> getBDependencies(Iterator<? extends Dependency> dependencies)
+    {
+        List<BDependency> result = new ArrayList<BDependency>();
+
+        while (dependencies.hasNext()) {
+            Dependency dependency = dependencies.next();
+            result.add(dependency.getBDependency());
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a {@link String} representation of this object.
+     */
+    @Override
+    public String toString()
+    {
+        try {
+            ClassTarget classTarget = getClassTarget();
+            return "BClassTarget: " + classTarget.getIdentifierName();
+        } catch (ExtensionException e) {
+            return "BClassTarget: INVALID";
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BConstructor.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BConstructor.java
new file mode 100644
index 0000000000000000000000000000000000000000..c41ac7ab6d4ce055a549e9090d631db688c7298d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BConstructor.java
@@ -0,0 +1,196 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+
+import bluej.debugger.*;
+import bluej.debugmgr.objectbench.*;
+import bluej.pkgmgr.*;
+import bluej.views.*;
+
+/**
+ * A wrapper for a constructor of a BlueJ class.
+ * Behaviour is similar to reflection API.
+ *
+ *
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003,2004
+ */
+public class BConstructor
+{
+    // The problem of consistency here is quite subtle.....
+    // I could try to get a kind of id for a ConstructorView and then try to get it back
+    // when I need it, but really, the gain is almost nil.
+    // What I will do is to have an Identifier with Project,Package,Class given and before doing
+    // anything I will check with it. If everything is still there it should be OK.
+    // In any case, it it goes wrong we will get an invoker exception !
+    
+    
+    private Identifier parentId;
+    private ConstructorView bluej_view;
+
+
+    /**
+     * Constructor.
+     * It is duty of the caller to make shure that the parent is valid.
+     *
+     * @param  aParentId  Description of the Parameter
+     * @param  i_view     Description of the Parameter
+     */
+    BConstructor(Identifier aParentId, ConstructorView i_view)
+    {
+        parentId = aParentId;
+        bluej_view = i_view;
+    }
+
+
+    /**
+     * Tests if this constructor matches the given signature.
+     *
+     * @param  parameter  Description of the Parameter
+     * @return            true if it does, false otherwise.
+     */
+    public boolean matches(Class<?>[] parameter)
+    {
+        Class<?>[] thisArgs = bluej_view.getParameters();
+
+        // An empty array is equivalent to a null array
+        if (thisArgs != null && thisArgs.length <= 0) {
+            thisArgs = null;
+        }
+        if (parameter != null && parameter.length <= 0) {
+            parameter = null;
+        }
+
+        // If both are null the we are OK
+        if (thisArgs == null && parameter == null) {
+            return true;
+        }
+
+        // If ANY of them is null we are in trouble now. (They MUST be both NOT null)
+        if (thisArgs == null || parameter == null) {
+            return false;
+        }
+
+        // Now I know that BOTH are NOT empty. They MUST be the same length
+        if (thisArgs.length != parameter.length) {
+            return false;
+        }
+
+        for (int index = 0; index < thisArgs.length; index++) {
+            if (!thisArgs[index].isAssignableFrom(parameter[index])) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Returns the parameters of this constructor.
+     * Similar to reflection API.
+     *
+     * @return    The parameterTypes value
+     */
+    public Class<?>[] getParameterTypes()
+    {
+        return bluej_view.getParameters();
+    }
+
+
+    /**
+     * Creates a new instance of the object described by this constructor.
+     * Similar to reflection API. Note that this method should not be called
+     * from the AWT/Swing event-dispatching thread.
+     * 
+     * <p>The arguments passed in the initargs array may have any type,
+     * but the type will determine exactly what is passed to the
+     * constructor:
+     * 
+     * <ul>
+     * <li>String - the String will be passed directly to the constructor
+     * <li>BObject - the object will be passed directly to the constructor,
+     *               though it must be on the object bench for this to work
+     * <li>Anything else - toString() is called on the object and the
+     *               result is treated as a Java expression, which is
+     *               evaluated and passed to the constructor.
+     * </ul>
+     * 
+     * <p>An attempt is made to ensure that the argument types are suitable
+     * for the constructor. InvocationArgumentException will be thrown if
+     * the arguments are clearly unsuitable, however some cases will
+     * generate an InvocationErrorException instead. In such cases no
+     * expression arguments will be evaluated.
+     *
+     * @param  initargs                      Description of the Parameter
+     * @return                               Description of the Return Value
+     * @throws  ProjectNotOpenException      if the project to which this constructor belongs has been closed by the user.
+     * @throws  PackageNotFoundException     if the package to which this constructor belongs has been deleted by the user.
+     * @throws  InvocationArgumentException  if the <code>initargs</code> don't match the constructor's arguments.
+     * @throws  InvocationErrorException     if an error occurs during the invocation.
+     */
+    public BObject newInstance(Object[] initargs)
+             throws ProjectNotOpenException, PackageNotFoundException,
+            InvocationArgumentException, InvocationErrorException
+    {
+        PkgMgrFrame pkgFrame = parentId.getPackageFrame();
+
+        DirectInvoker invoker = new DirectInvoker(pkgFrame);
+        DebuggerObject result = invoker.invokeConstructor(bluej_view, initargs);
+
+        if (result == null) {
+            return null;
+        }
+
+        String resultName = invoker.getResultName();
+        PkgMgrFrame pmf = parentId.getPackageFrame();
+
+        ObjectWrapper wrapper = ObjectWrapper.getWrapper(pmf, pmf.getObjectBench(), result, result.getGenType(), resultName);
+
+        return new BObject(wrapper);
+    }
+
+    /**
+     * Returns the modifier of this constructor. The
+     * {@link java.lang.reflect.Modifier} class can be used to decode the
+     * modifiers.
+     */
+    public int getModifiers()
+    {
+        return bluej_view.getModifiers();
+    }
+
+    /**
+     *  Description of the Method
+     *
+     * @return    Description of the Return Value
+     */
+    public String toString()
+    {
+        if (bluej_view != null) {
+            return "BConstructor: " + bluej_view.getLongDesc();
+        }
+        else {
+            return "BConstructor: ";
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BDependency.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BDependency.java
new file mode 100644
index 0000000000000000000000000000000000000000..24c0eff1e5abb236e44143a5d8cdd859ff979e1c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BDependency.java
@@ -0,0 +1,268 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.target.ClassTarget;
+
+/**
+ * A wrapper for a dependency (edge) in the class diagram of BlueJ.
+ * 
+ * @author Simon Gerlach
+ */
+public class BDependency
+{
+    /**
+     * This enumeration contains constants which describe the nature of a
+     * dependency.
+     * 
+     * @author Simon Gerlach
+     */
+    public enum Type
+    {
+        /**
+         * The type of the dependency could not be determined. This usually
+         * happens if the represented dependency does not exists anymore.
+         */
+        UNKNOWN,
+
+        /** Represents a uses-dependency */
+        USES,
+
+        /** Represents an extends-dependency */
+        EXTENDS,
+
+        /** Represents an implements-dependency */
+        IMPLEMENTS;
+    }
+
+    private Identifier originId;
+    private Identifier targetId;
+    private Type type;
+
+    /**
+     * Constructor. Creates a new {@link BDependency} from the given origin and
+     * target IDs.
+     * 
+     * @param originId
+     *            The {@link Identifier} which represents the origin of this
+     *            dependency. It is duty of the caller to guarantee that this
+     *            <code>originId</code> is reasonable.
+     * @param targetId
+     *            The {@link Identifier} which represents the target of this
+     *            dependency. It is duty of the caller to guarantee that this
+     *            <code>targetId</code> is reasonable.
+     * @param type
+     *            The type of the dependency (one of the constants in
+     *            {@link BDependency.Type}).
+     * @throws IllegalArgumentException
+     *             if the specified {@link Identifier}s represent classes from
+     *             different projects and/or packages.
+     */
+    BDependency(Identifier originId, Identifier targetId, Type type) throws IllegalArgumentException
+    {
+        if (!originId.equalsIgnoreClass(targetId)) {
+            throw new IllegalArgumentException(
+                    "The origin and target of a dependency must be in the same project in the same package");
+        }
+
+        this.originId = originId;
+        this.targetId = targetId;
+        this.type = type;
+    }
+
+    /**
+     * Notification that the name of the underlying class of the origin of this
+     * dependency has changed.
+     * 
+     * @param newOriginName
+     *            The new class name, fully qualified.
+     */
+    void originNameChanged(String newOriginName)
+    {
+        try {
+            Project bluejProject = originId.getBluejProject();
+            Package bluejPackage = originId.getBluejPackage();
+
+            originId = new Identifier(bluejProject, bluejPackage, newOriginName);
+        } catch (ProjectNotOpenException e) {
+            // cannot happen: the renaming of a class requires an open project
+            // and package
+        } catch (PackageNotFoundException e) {
+            // cannot happen: the renaming of a class requires an open project
+            // and package
+        }
+    }
+
+    /**
+     * Notification that the name of the underlying class of the target of this
+     * dependency has changed.
+     * 
+     * @param newTargetName
+     *            The new class name, fully qualified.
+     */
+    void targetNameChanged(String newTargetName)
+    {
+        try {
+            Project bluejProject = targetId.getBluejProject();
+            Package bluejPackage = targetId.getBluejPackage();
+
+            targetId = new Identifier(bluejProject, bluejPackage, newTargetName);
+        } catch (ProjectNotOpenException e) {
+            // cannot happen: the renaming of a class requires an open project
+            // and package
+        } catch (PackageNotFoundException e) {
+            // cannot happen: the renaming of a class requires an open project
+            // and package
+        }
+    }
+
+    /**
+     * Returns the type of this dependency (one of the constants in
+     * {@link BDependency.Type}). May be used by extensions to determine the art
+     * of the dependency represented by this proxy object.
+     * 
+     * @return The type of this dependency. If the dependency represented by
+     *         this proxy object is no longer valid,
+     *         {@link BDependency.Type#UNKNOWN} is returned.
+     * @throws ProjectNotOpenException
+     *             if the project to which this dependency belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this dependency belongs has been
+     *             deleted by the user.
+     */
+    public Type getType() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        // Although we know the type we don't just return it. The dependency may
+        // not exist anymore which means this BDependency object is invalid. A
+        // client should be notified about this fact by returning
+        // BDependency.Type.UNKNOWN.
+        Type result = Type.UNKNOWN;
+        Dependency dependency = originId.getDependency(targetId, type);
+
+        if (dependency != null) {
+            result = dependency.getType();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns the origin of this dependency.
+     * 
+     * @return The origin of this dependency or <code>null</code> if the origin
+     *         does not exist anymore.
+     * @throws ProjectNotOpenException
+     *             if the project to which the origin of this dependency belongs
+     *             has been closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which the origin of this dependency belongs
+     *             has been deleted by the user.
+     */
+    public BClassTarget getFrom() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget origin = originId.getClassTarget();
+        return (origin != null) ? origin.getBClassTarget() : null;
+    }
+
+    /**
+     * Returns the target of this dependency.
+     * 
+     * @return The target of this dependency or <code>null</code> if the target
+     *         does not exist anymore.
+     * @throws ProjectNotOpenException
+     *             if the project to which the target of this dependency belongs
+     *             has been closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which the target of this dependency belongs
+     *             has been deleted by the user.
+     */
+    public BClassTarget getTo() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        ClassTarget target = targetId.getClassTarget();
+        return (target != null) ? target.getBClassTarget() : null;
+    }
+    
+    /**
+     * Indicates whether this dependency shall be visible in the graph.
+     * 
+     * @return <code>true</code> if this dependency is visible,
+     *         <code>false</code> otherwise.
+     * @throws ProjectNotOpenException
+     *             if the project to which this dependency belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this dependency belongs has been
+     *             deleted by the user.
+     */
+    public boolean isVisible() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Dependency dependency = originId.getDependency(targetId, type);
+        return (dependency != null) ? dependency.isVisible() : false;
+    }
+
+    /**
+     * Sets the visible setting of this dependency.
+     * 
+     * @param visible
+     *            The new visible setting.
+     * @throws ProjectNotOpenException
+     *             if the project to which this dependency belongs has been
+     *             closed by the user.
+     * @throws PackageNotFoundException
+     *             if the package to which this dependency belongs has been
+     *             deleted by the user.
+     */
+    public void setVisible(boolean visible, boolean recalc) throws ProjectNotOpenException,
+            PackageNotFoundException
+    {
+        Dependency dependency = originId.getDependency(targetId, type);
+
+        if (dependency != null) {
+            dependency.setVisible(visible);                
+        
+            if (recalc) {
+                dependency.getFrom().recalcOutUses();
+                dependency.getTo().recalcInUses();
+            }
+        }
+    }
+    
+    /**
+     * Returns a {@link String} representation of this object. 
+     */
+    @Override
+    public String toString()
+    {
+        try {
+            ClassTarget origin = originId.getClassTarget();
+            ClassTarget target = targetId.getClassTarget();
+
+            return "BDependency (" + type + "): " + origin.getIdentifierName() + " --> " + target.getIdentifierName();
+        } catch (ExtensionException e) {
+            return "BDependency: INVALID";
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BField.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BField.java
new file mode 100644
index 0000000000000000000000000000000000000000..40f7c230d73a7149eb0aaad4c939e6ee8eef4475
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BField.java
@@ -0,0 +1,293 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import java.util.List;
+
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.jdi.JdiObject;
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.utility.Debug;
+import bluej.views.FieldView;
+import bluej.views.View;
+
+import com.sun.jdi.BooleanValue;
+import com.sun.jdi.ByteValue;
+import com.sun.jdi.CharValue;
+import com.sun.jdi.DoubleValue;
+import com.sun.jdi.Field;
+import com.sun.jdi.FloatValue;
+import com.sun.jdi.IntegerValue;
+import com.sun.jdi.LongValue;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.ShortValue;
+import com.sun.jdi.StringReference;
+import com.sun.jdi.Value;
+
+/**
+ * A wrapper for a field of a BlueJ class.
+ * Behaviour is similar to the Reflection API.
+ * 
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003
+ * @author Clive Miller, University of Kent at Canterbury, 2002
+ */
+public class BField
+{
+    private final FieldView bluej_view;
+    private final Identifier parentId;
+
+
+    /**
+     *Constructor for the BField object
+     *
+     * @param  aParentId     Description of the Parameter
+     * @param  i_bluej_view  Description of the Parameter
+     */
+    BField(Identifier aParentId, FieldView i_bluej_view)
+    {
+        parentId = aParentId;
+        bluej_view = i_bluej_view;
+    }
+
+
+    /**
+     * Check to see if the field name matches the given one.
+     * 
+     * <p>This method is deprecated. Use "getName().equals(fieldName)" instead.
+     *
+     * @param  fieldName  the field name to compare with
+     * @return            true if it does, false otherwise
+     */
+    @Deprecated
+    public boolean matches(String fieldName)
+    {
+        return getName().equals(fieldName);
+    }
+
+
+    /**
+     * Return the name of the field.
+     * Similar to reflection API.
+     *
+     * @return    The name value
+     */
+    public String getName()
+    {
+        return bluej_view.getName();
+    }
+
+
+    /**
+     * Return the type of the field.
+     * Similar to Reflection API.
+     *
+     * @return    The type value
+     */
+    public Class<?> getType()
+    {
+        return bluej_view.getType().getViewClass();
+    }
+
+
+    /**
+     * Returns the java Field for inspection.
+     * Use this method when you need more information about the Field than
+     * is provided by the BField interface. E.g.:
+     * What is the declaring class of this Field?
+     *
+     * Note that this is for information only. If you want to interact with BlueJ you must
+     * use the methods provided in BField.
+     * 
+     * @return    The java.lang.reflect.Field providing extra information about this BField.
+     */
+    public java.lang.reflect.Field getJavaField()
+    {
+        return bluej_view.getField();
+    }
+    
+    /**
+     * Returns the modifiers of this field.
+     * The <code>java.lang.reflect.Modifier</code> class can be used to decode the modifiers.
+     * Similar to reflection API
+     *
+     * @return    The modifiers value
+     */
+    public int getModifiers()
+    {
+        return bluej_view.getModifiers();
+    }
+
+    /**
+     * When you are inspecting a static field use this one.
+     *
+     * @return                            The staticField value
+     * @throws  ProjectNotOpenException   if the project to which this field belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this field belongs has been deleted by the user.
+     */
+    private Object getStaticField() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package bluejPkg = parentId.getBluejPackage();
+        PkgMgrFrame aFrame = parentId.getPackageFrame();
+        String wantFieldName = getName();
+
+        // I need to get the view of the parent of this Field
+        // That must be the Class that I want to look after....
+        View parentView = bluej_view.getDeclaringView();
+        String className = parentView.getQualifiedName();
+
+        DebuggerClass debuggerClass;
+        try {
+            debuggerClass = bluejPkg.getDebugger().getClass(className, true);
+        }
+        catch (java.lang.ClassNotFoundException cnfe) {
+            // This may not be an error, the class name may be wrong...
+            Debug.message("BField.getStaticField: Class=" + className + " Field=" + wantFieldName + " WARNING: cannod get debuggerClass");
+            return null;
+        }
+
+        // Now I want the Debugger object of that field.
+        // I do it this way since there is no way to get it by name...
+        DebuggerObject debugObj = null;
+        List<DebuggerField> staticFields = debuggerClass.getStaticFields();
+        for (DebuggerField field : staticFields) {
+            if (wantFieldName.equals(field.getName())) {
+                debugObj = field.getValueObject(null);
+                break;
+            }
+        }
+
+        if (debugObj == null) {
+            // No need to complain about it it may not be a static field...
+            return null;
+        }
+
+        ObjectReference objRef = debugObj.getObjectReference();
+        if (objRef == null) {
+            // Without JDI this cannot work.
+            return null;
+        }
+
+        return doGetVal(aFrame, wantFieldName, objRef);
+    }
+
+
+    /**
+     * Return the value of this field of the given object.
+     * This is similar to Reflection API.
+     *
+     * In the case that the field is of primitive type (<code>int</code> etc.),
+     * the return value is of the appropriate Java wrapper type (<code>Integer</code> etc.).
+     * In the case that the field contains an object then
+     * an appropriate BObject will be returned.
+     *
+     * The main reason that this method is on a field (derived from a class),
+     * rather than directly on an object, is to allow for the retrieval of
+     * static field values without having to create an object of the appropriate type.
+     *
+     * As in the Relection API, in order to get the value of a static field pass
+     * null as the parameter to this method.
+     *
+     * @param  onThis                     Description of the Parameter
+     * @return                            The value value
+     * @throws  ProjectNotOpenException   if the project to which the field belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which the field belongs has been deleted by the user.
+     */
+    public Object getValue(BObject onThis)
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        // If someone gives me a null it means that he wants a static field
+        if (onThis == null) {
+            return getStaticField();
+        }
+
+        ObjectReference objRef = onThis.getObjectReference();
+
+        ReferenceType type = objRef.referenceType();
+
+        Field thisField = type.fieldByName(bluej_view.getName());
+        if (thisField == null) {
+            return null;
+        }
+
+        PkgMgrFrame aFrame = onThis.getPackageFrame();
+        return doGetVal(aFrame, bluej_view.getName(), objRef.getValue(thisField));
+    }
+
+
+    /**
+     * Given a Value that comes from the remote debugger machine, converts it into somethig
+     * that is usable. The real important thing here is to return a BObject for objects
+     * that can be put into the bench.
+     *
+     * @param  packageFrame  Description of the Parameter
+     * @param  instanceName  Description of the Parameter
+     * @param  val           Description of the Parameter
+     * @return               Description of the Return Value
+     */
+    static Object doGetVal(PkgMgrFrame packageFrame, String instanceName, Value val)
+    {
+        if (val == null) {
+            return null;
+        }
+
+        if (val instanceof StringReference) {
+            return ((StringReference) val).value();
+        }
+        if (val instanceof BooleanValue) {
+            return new Boolean(((BooleanValue) val).value());
+        }
+        if (val instanceof ByteValue) {
+            return new Byte(((ByteValue) val).value());
+        }
+        if (val instanceof CharValue) {
+            return new Character(((CharValue) val).value());
+        }
+        if (val instanceof DoubleValue) {
+            return new Double(((DoubleValue) val).value());
+        }
+        if (val instanceof FloatValue) {
+            return new Float(((FloatValue) val).value());
+        }
+        if (val instanceof IntegerValue) {
+            return new Integer(((IntegerValue) val).value());
+        }
+        if (val instanceof LongValue) {
+            return new Long(((LongValue) val).value());
+        }
+        if (val instanceof ShortValue) {
+            return new Short(((ShortValue) val).value());
+        }
+
+        if (val instanceof ObjectReference) {
+            JdiObject obj = JdiObject.getDebuggerObject((ObjectReference) val);
+            ObjectWrapper objWrap = ObjectWrapper.getWrapper(packageFrame, packageFrame.getObjectBench(), obj, obj.getGenType(), instanceName);
+            return objWrap.getBObject();
+        }
+
+        return val.toString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BMethod.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BMethod.java
new file mode 100644
index 0000000000000000000000000000000000000000..77dfe613fc8bdb78c0197cb18b45528d9d5df466
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BMethod.java
@@ -0,0 +1,224 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.views.MethodView;
+import bluej.views.View;
+import com.sun.jdi.Field;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+import java.lang.reflect.Modifier;
+
+/**
+ * A wrapper for a method of a BlueJ class.
+ * Allows an extension to invoke a method on an object that is on the BlueJ object bench.
+ * When values representing types are returned, there are two cases:
+ * In the case that the returned value is of primitive type (<code>int</code> etc.), 
+ * it is represented in the appropriate Java wrapper type (<code>Integer</code> etc.).
+ * In the case that the returned value is an object type then an appropriate BObject will 
+ * be returned, allowing the returned object itself to be placed on the BlueJ object bench.
+ *
+ * @author Clive Miller, University of Kent at Canterbury, 2002
+ * @author Damiano Bolla, University of Kent at Canterbury 2003
+ */
+public class BMethod
+{
+    // The same reasoning as of BConstructor applies here.
+    
+    private Identifier parentId;
+    private MethodView bluej_view;
+    
+    /**
+     * Constructor.
+     */
+    BMethod ( Identifier aParentId, MethodView i_bluej_view )
+    {
+        parentId   = aParentId;
+        bluej_view = i_bluej_view;
+    }
+
+    /**
+     * Tests if this method matches against the given signature.
+     * Returns true if there is a match, false otherwise.
+     * Pass a zero length parameter array if the method takes no arguments.
+     */
+    public boolean matches ( String methodName, Class<?>[] parameter )
+    {
+        // If someone is crazy enough to do this he deserves it :-)
+        if ( methodName == null ) return false;
+
+        // Let me se if the named method is OK
+        if ( ! methodName.equals(bluej_view.getName() ) ) return false;
+     
+        Class<?>[] thisArgs = bluej_view.getParameters();
+
+        // An empty array is equivalent to a null array
+        if (thisArgs  != null && thisArgs.length  <= 0)  thisArgs  = null;
+        if (parameter != null && parameter.length <= 0 ) parameter = null;
+
+        // If both are null the we are OK
+        if ( thisArgs == null && parameter == null ) return true;
+
+        // If ANY of them is null we are in trouble now. (They MUST be both NOT null)
+        if ( thisArgs == null || parameter == null ) return false;
+
+        // Now I know that BOTH are NOT empty. They MUST be the same length
+        if ( thisArgs.length != parameter.length ) return false;
+    
+        for ( int index=0; index<thisArgs.length; index++ ) {
+            if ( ! thisArgs[index].isAssignableFrom(parameter[index]) ) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+     /**
+     * Returns the class that declares this method.
+     * Similar to Reflection API
+     */
+    public String getDeclaringClass()
+    {
+        return bluej_view.getClassName();
+    }
+    
+    /**
+     * Returns the types of the parameters of this method.
+     * Similar to Reflection API
+     */
+    public Class<?>[] getParameterTypes()
+    {
+        return bluej_view.getParameters();
+    }
+      
+    /**
+     * Returns the name of this method.
+     * Similar to Reflection API
+     */
+    public String getName()
+    {
+        return bluej_view.getName();
+    }
+    
+    /**
+     * Returns the return type of this method
+     * Similar to Reflection API
+     */
+    public Class<?> getReturnType()
+    {
+        View aView = bluej_view.getReturnType();
+        return aView.getViewClass();
+    }
+    
+    /**
+     * Returns the modifiers for this method.
+     * The <code>java.lang.reflect.Modifier</code> class can be used to decode the modifiers.
+     */
+    public int getModifiers()
+    {
+        return bluej_view.getModifiers();
+    }
+
+    /**
+     * Invoke this method on the given object. Note that this method should
+     * not be called from the AWT/Swing event-dispatching thread.
+     * 
+     * <p>The arguments passed in the initargs array may have any type,
+     * but the type will determine exactly what is passed to the
+     * method:
+     * 
+     * <ul>
+     * <li>String - the String will be passed directly to the method
+     * <li>BObject - the object will be passed directly to the method,
+     *               though it must be on the object bench for this to work
+     * <li>Anything else - toString() is called on the object and the
+     *               result is treated as a Java expression, which is
+     *               evaluated and passed to the method.
+     * </ul>
+     * 
+     * <p>An attempt is made to ensure that the argument types are suitable
+     * for the method. InvocationArgumentException will be thrown if
+     * the arguments are clearly unsuitable, however some cases will
+     * generate an InvocationErrorException instead. In such cases no
+     * expression arguments will be evaluated.
+     * 
+     * <p>If the method invoked is <code>public static void main(String [] args)</code>, then the invocation will,
+     * as a side-effect, reset the VM used by BlueJ to run user code in this project, and clear the object bench. This
+     * behaviour matches the effect of invoking a main method through the BlueJ GUI.
+     * 
+     * @param onThis The BObject to which the method call should be applied, null if a static method.
+     * @param params an array containing the arguments, or null if there are none
+     * @return the resulting Object. It can be a wrapper for a primitive type or a BObject
+     * @throws ProjectNotOpenException if the project to which this object belongs has been closed by the user.
+     * @throws PackageNotFoundException if the package to which this object belongs has been deleted by the user.
+     * @throws InvocationArgumentException if the <code>params</code> don't match the object's arguments.
+     * @throws InvocationErrorException if an error occurs during the invocation.
+     */
+    public Object invoke (BObject onThis, Object[] params) 
+        throws ProjectNotOpenException, PackageNotFoundException, 
+               InvocationArgumentException, InvocationErrorException
+    {
+        ObjectWrapper instanceWrapper=null;
+        // If it is a method call on a live object get the identifier for it.
+        if ( onThis != null ) instanceWrapper = onThis.getObjectWrapper();
+        
+        PkgMgrFrame  pkgFrame = parentId.getPackageFrame();
+        DirectInvoker invoker = new DirectInvoker (pkgFrame);
+        DebuggerObject result = invoker.invokeMethod (instanceWrapper, bluej_view, params);
+
+        // We return null if the method is void (as per Reflection), which might 
+        // either be a null result object, or a valid result object representing null
+        if (result == null || result.isNullObject()) return null;
+
+        String resultName = invoker.getResultName();
+
+        ObjectReference objRef = result.getObjectReference();
+        ReferenceType type = objRef.referenceType();
+
+        // It happens that the REAL result is in the result field of this Object...
+        Field thisField = type.fieldByName ("result");
+        if ( thisField == null ) return null;
+
+        // DOing this is the correct way of returning the right object. Tested 080303, Damiano
+        return BField.doGetVal(pkgFrame, resultName, objRef.getValue(thisField));
+    }
+    
+  
+    /**
+     * Returns a string representing the return type, name and signature of this method
+     */
+    public String toString()
+    {
+        Class<?>[] signature = getParameterTypes();
+        String sig = "";
+        for (int i=0; i<signature.length; i++) {
+            sig += signature[i].getName() + (i==signature.length-1?"":", ");
+        }
+        String mod = Modifier.toString (getModifiers());
+        if (mod.length() > 0) mod += " ";
+        return mod+getReturnType()+" "+getName()+"("+sig+")";
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BObject.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..441bfac3d75d93e7a0b73ffa00d92daabb22d867
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BObject.java
@@ -0,0 +1,306 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import bluej.debugger.*;
+import bluej.debugmgr.objectbench.*;
+import bluej.pkgmgr.*;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.target.ClassTarget;
+import com.sun.jdi.*;
+import java.util.*;
+
+/**
+ * A wrapper for an object on the BlueJ object bench.
+ * This wraps an object so you can add and remove it from the bench.
+ *
+ * @see        BConstructor
+ * @see        BMethod
+ * @see        BField
+ *
+ * @author Clive Miller, University of Kent at Canterbury, 2002
+ * @author Damiano Bolla, University of Kent at Canterbury 2003,2004
+ */
+public class BObject
+{
+    private ObjectWrapper objectWrapper;
+    
+    /** An identifier for the class of this object */
+    private Identifier wrapperId;
+
+
+    /**
+     * Constructor for BObject.
+     *
+     * @param  aWrapper  Description of the Parameter
+     */
+    BObject(ObjectWrapper aWrapper)
+    {
+        objectWrapper = aWrapper;
+
+        Package bluejPkg = objectWrapper.getPackage();
+        Project bluejProj = bluejPkg.getProject();
+
+        // It really seems that the translation between Java naming and Class is needed.
+        // Also tryng to get the Class instead of just the name is a mess...
+        String className = transJavaToClass(objectWrapper.getClassName());
+
+        wrapperId = new Identifier(bluejProj, bluejPkg, className);
+    }
+
+
+    /**
+     * Returns the package this object belongs to.
+     *
+     * @return                            The package value
+     * @throws  ProjectNotOpenException   if the project to which this object belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this object belongs has been deleted by the user.
+     */
+    public BPackage getPackage()
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package bluejPkg = wrapperId.getBluejPackage();
+
+        return bluejPkg.getBPackage();
+    }
+
+
+    /**
+     * Removes this object from the object bench.
+     * This will also remove it from the view of the object bench.
+     * Once the object is removed from the bench it will not be available again.
+     *
+     * @throws  ProjectNotOpenException   if the project to which this object belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this object belongs has been deleted by the user.
+     */
+    public void removeFromBench()
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package aPackage = wrapperId.getBluejPackage();
+        PkgMgrFrame aFrame = wrapperId.getPackageFrame();
+
+        ObjectBench aBench = aFrame.getObjectBench();
+        aBench.removeObject(objectWrapper, aPackage.getId());
+
+        objectWrapper = null;
+    }
+
+
+    /**
+     * Adds this object on the object bench.
+     * If you pass null as instanceName the object will have a predefined name.
+     * If the object is not a valid one nothing will happen.
+     *
+     *
+     * @param  instanceName               The name you want this object to have on the bench.
+     * @throws  ProjectNotOpenException   if the project to which this object belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this object belongs has been deleted by the user.
+     */
+    public void addToBench(String instanceName)
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        if (objectWrapper == null) {
+            return;
+        }
+
+        // Not rational to add a null object, is it ?
+        if (objectWrapper.getObject().isNullObject()) {
+            return;
+        }
+
+        // If you want you may set the instance name here. Otherwise accept default
+        if (instanceName != null) {
+            objectWrapper.setName(instanceName);
+        }
+
+        // This should really always exists, no need to check
+        Package aPackage = wrapperId.getBluejPackage();
+        PkgMgrFrame aFrame = wrapperId.getPackageFrame();
+
+        ObjectBench aBench = aFrame.getObjectBench();
+        aBench.addObject(objectWrapper);
+
+        // load the object into runtime scope
+        aPackage.getDebugger().addObject(aPackage.getId(), objectWrapper.getName(), objectWrapper.getObject());
+    }
+
+
+    /**
+     * Return the name of this object on the object bench.
+     *
+     * @return    The instance name if the object can be put into bench, null othervise
+     */
+    public String getInstanceName()
+    {
+        if (objectWrapper == null) {
+            return null;
+        }
+
+        return objectWrapper.getName();
+    }
+
+
+    /**
+     * Return the class of this object.
+     * Similar to Reflection API. Note the naming inconsistency, which
+     * avoids a clash with <code>java.lang.Object.getClass()</code>
+     *
+     * @return                           The bClass value
+     * @throws  ProjectNotOpenException  if the project to which this object belongs has been closed by the user.
+     * @throws  ClassNotFoundException   if the class has been deleted by the user.
+     * @throws  PackageNotFoundException if the Package has been deleted by the user.
+     */
+    public BClass getBClass()
+             throws ProjectNotOpenException, PackageNotFoundException, ClassNotFoundException
+    {
+        // BClasses are retrieved from the BlueJ classTarget
+        ClassTarget classTarget = wrapperId.getClassTarget();
+        
+        if (classTarget == null) {
+            // Not a project class; exists in a library or the Java runtime
+            wrapperId.getJavaClass(); // will throw ClassNotFoundException if not loadable
+            return BClass.getBClass(wrapperId);
+        }
+        
+        // There is only one instance of BClass for each ClassTarget
+        return classTarget.getBClass();
+    }
+
+
+    /**
+     * Returns the underlying BlueJ package.
+     * Should remain visible only to package members.
+     *
+     * @return                            The packageFrame value
+     * @throws  ProjectNotOpenException   if the project to which this object belongs has been closed by the user.
+     * @throws  PackageNotFoundException  if the package to which this object belongs has been deleted by the user.
+     */
+    PkgMgrFrame getPackageFrame()
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        return wrapperId.getPackageFrame();
+    }
+
+
+    /**
+     * Returns the object wrapper to be used by the invoke on methods
+     *
+     * @return    The objectWrapper value
+     */
+    ObjectWrapper getObjectWrapper()
+    {
+        return objectWrapper;
+    }
+
+
+    /**
+     * Used by BField to get hold of the real Object
+     *
+     * @return    The objectReference value
+     */
+    ObjectReference getObjectReference()
+    {
+        if (objectWrapper == null) {
+            return null;
+        }
+        DebuggerObject obj = objectWrapper.getObject();
+
+        if (obj == null) {
+            return null;
+        }
+        return obj.getObjectReference();
+    }
+
+
+    /**
+     * Returns a string representation of the Object
+     *
+     * @return    Description of the Return Value
+     */
+    public String toString()
+    {
+        String className = "";
+        if (objectWrapper != null) {
+            className = objectWrapper.getClassName();
+        }
+
+        return "BObject instanceName=" + getInstanceName() + " Class Name=" + className;
+    }
+
+
+    private static HashMap<String,String> primiMap;
+
+    static {
+        // This will be executed once when this class is loaded
+        primiMap = new HashMap<String,String>();
+        primiMap.put("boolean", "Z");
+        primiMap.put("byte", "B");
+        primiMap.put("short", "S");
+        primiMap.put("char", "C");
+        primiMap.put("int", "I");
+        primiMap.put("long", "J");
+        primiMap.put("float", "F");
+        primiMap.put("double", "D");
+    }
+
+
+    /**
+     * Needed to convert java style class names to classloaded class names.
+     * From: java.lang.String[]
+     * To:   [Ljava.lang.String;
+     *
+     * @param  javaStyle  Description of the Parameter
+     * @return            Description of the Return Value
+     */
+    private String transJavaToClass(String javaStyle)
+    {
+        String className = javaStyle;
+
+        int arrayCount = 0;
+        while (className.endsWith("[]")) {
+            // Counts how may arrays are in this class name
+            arrayCount++;
+            className = className.substring(0, className.length() - 2);
+        }
+
+        // No array around, nothing to do.
+        if (arrayCount <= 0) {
+            return className;
+        }
+
+        String replace = (String) primiMap.get(className);
+
+        // If I can substitute the name I will do it
+        if (replace != null) {
+            className = replace;
+        }
+        else {
+            className = "L" + className + ";";
+        }
+
+        while (arrayCount-- > 0) {
+            className = "[" + className;
+        }
+
+        return className;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BPackage.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BPackage.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c9a83f2a05e13710a572dc065ed0a24796eb27b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BPackage.java
@@ -0,0 +1,401 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import bluej.compiler.*;
+import bluej.debugmgr.objectbench.*;
+import bluej.extensions.BDependency.Type;
+import bluej.pkgmgr.*;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.target.*;
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import java.util.List;
+
+
+/**
+ * A wrapper for a single package of a BlueJ project.
+ * This represents an open package, and functions relating to that package.
+ *
+ * @author Clive Miller, University of Kent at Canterbury, 2002
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class BPackage
+{
+    private Identifier packageId;
+
+    /**
+     * Constructor for a BPackage.
+     */
+    BPackage (Identifier aPackageId)
+    {
+        packageId=aPackageId;
+    }
+
+    /**
+     * Removes this package from BlueJ, including the underlying files.
+     *
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public void remove() 
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package bluejPkg  = packageId.getBluejPackage();
+        Package parentPkg = bluejPkg.getParent();
+
+        PackageTarget pkgTarget=(PackageTarget)parentPkg.getTarget(bluejPkg.getBaseName());
+        pkgTarget.removeImmediate();
+    }
+
+    /**
+     * Returns the package's project.
+     * @throws ProjectNotOpenException if the project has been closed by the user.
+     */
+    public BProject getProject() throws ProjectNotOpenException
+    {
+        Project bluejProject = packageId.getBluejProject();
+
+        return bluejProject.getBProject();
+    }
+
+    /**
+     * Returns the name of the package. 
+     * Returns an empty string if no package name has been set.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public String getName() 
+    throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package bluejPkg = packageId.getBluejPackage();
+
+        return bluejPkg.getQualifiedName();
+    }
+
+
+    /**
+     * Reloads the entire package.
+     * This is used (e.g.) when a new <code>.java</code> file has been added to the package.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public void reload() 
+    throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package bluejPkg = packageId.getBluejPackage();
+
+        bluejPkg.reload();
+    }
+
+    /**
+     * Creates a new Class with the given name.
+     * The class name must not be a fully qualified name, and the .java file must already exist.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     * @throws MissingJavaFileException if the .java file for the new class does not exist.
+     */
+    public BClass newClass ( String className )
+    throws ProjectNotOpenException, PackageNotFoundException, MissingJavaFileException
+    {
+        Package bluejPkg = packageId.getBluejPackage();
+        PkgMgrFrame bluejFrame = packageId.getPackageFrame();
+
+        File classJavaFile = new File (bluejPkg.getPath(),className+".java");
+        if ( ! classJavaFile.canWrite() ) 
+            throw new MissingJavaFileException (classJavaFile.toString());
+
+        bluejFrame.createNewClass(className,null,true);
+        return getBClass ( className );
+    }
+    
+    /**
+     * Returns the package frame.
+     * This can be used (e.g.) as the "parent" frame for positioning modal dialogues.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public Frame getFrame() 
+    throws ProjectNotOpenException, PackageNotFoundException
+    {
+        return packageId.getPackageFrame();
+    }
+    
+    /**
+     * Returns the class with the given name in this package.
+     * Returns null if the class name does not exist. Note the naming
+     * inconsistency, which avoids a clash with
+     * <code>java.lang.Object.getClass()</code>
+     * 
+     * @param name the simple name of the required class.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public BClass getBClass (String name)   
+    throws ProjectNotOpenException, PackageNotFoundException
+    {
+        packageId.getBluejProject();
+        Package bluejPkg = packageId.getBluejPackage();
+
+        Target aTarget = bluejPkg.getTarget (name);
+
+        // We may consider reporting this as a not found
+        if ( aTarget == null ) return null;
+
+        // And this in a different way
+        if ( !(aTarget instanceof ClassTarget)) return null;
+
+        ClassTarget classTarget = (ClassTarget)aTarget;
+
+        return classTarget.getBClass();
+    }
+    
+    /**
+     * Returns an array containing all the classes in this package.
+     * If there are no classes an empty array will be returned.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public BClass[] getClasses() 
+    throws ProjectNotOpenException, PackageNotFoundException
+    {
+        packageId.getBluejProject();
+        Package bluejPkg = packageId.getBluejPackage();
+
+        ArrayList<ClassTarget> classTargets = bluejPkg.getClassTargets();
+
+        BClass[] classes = new BClass [classTargets.size()];
+        for (int index=0; index<classTargets.size(); index++) {
+            ClassTarget target = classTargets.get(index);
+            classes [index] = target.getBClass();
+        }
+
+        return classes;
+    }
+    
+    /**
+     * Returns a wrapper for the object with the given name on BlueJ's object bench.
+     * @param instanceName the name of the object as shown on the object bench
+     * @return the object, or null if no such object exists.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public BObject getObject (String instanceName) 
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        // The usual check to avoid silly stack trace
+        if(instanceName == null) {
+            return null;
+        }
+
+        packageId.getBluejPackage();
+        PkgMgrFrame pmf = packageId.getPackageFrame();
+        
+        List<ObjectWrapper> objects = pmf.getObjectBench().getObjects();
+        for(Iterator<ObjectWrapper> i=objects.iterator(); i.hasNext(); ) {
+            ObjectWrapper wrapper = i.next();
+            if (instanceName.equals(wrapper.getName())) {
+                return wrapper.getBObject();
+            }
+        }
+        return null;
+    }    
+
+    /**
+     * Returns an array of all the Objects on the object bench.
+     * The array will be empty if no objects are on the bench.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public BObject[] getObjects() 
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        packageId.getBluejPackage();
+        PkgMgrFrame pmf = packageId.getPackageFrame();
+   
+        List<ObjectWrapper> objectWrappers = pmf.getObjectBench().getObjects();
+        BObject[] objects = new BObject [objectWrappers.size()];
+        int index = 0;
+        for(Iterator<ObjectWrapper> i=objectWrappers.iterator(); i.hasNext(); ) {
+            ObjectWrapper wrapper = i.next();
+            objects[index] = wrapper.getBObject();
+            index++;
+        }
+        return objects;
+    }
+    
+
+    /**
+     * Compile all modified files of this package.
+     * A single CompileEvent with all modified files listed will be generated.
+     * @param  waitCompileEnd <code>true</code> waits for the compilation to be finished.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     * @throws CompilationNotStartedException if BlueJ is currently executing Java code.
+     */
+    public void compile ( boolean waitCompileEnd ) 
+    throws ProjectNotOpenException, PackageNotFoundException, CompilationNotStartedException
+    {
+        Package bluejPkg = packageId.getBluejPackage();
+
+        if ( ! bluejPkg.isDebuggerIdle() )
+            throw new CompilationNotStartedException ("BlueJ is currently executing Java code");
+
+        // Start compilation
+        bluejPkg.compile();
+
+        // if requested wait for the compilation to finish.
+        if ( waitCompileEnd ) JobQueue.getJobQueue().waitForEmptyQueue();
+    }
+    
+
+    /**
+     * Compile all files of this package.
+     * A single CompileEvent with all compiled files listed will be generated.
+     * @param  waitCompileEnd <code>true</code> waits for the compilation to be finished.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     * @throws CompilationNotStartedException if BlueJ is currently executing Java code.
+     */
+    public void compileAll ( boolean waitCompileEnd ) 
+    throws ProjectNotOpenException, PackageNotFoundException, CompilationNotStartedException
+    {
+        Package bluejPkg = packageId.getBluejPackage();
+
+        if ( ! bluejPkg.isDebuggerIdle() )
+            throw new CompilationNotStartedException ("BlueJ is currently executing Java code");
+
+        // Request for ALL files to be compiled
+        bluejPkg.rebuild(); 
+
+        // if requested wait for the compilation to finish.
+        if ( waitCompileEnd ) JobQueue.getJobQueue().waitForEmptyQueue();
+    }
+
+    /** 
+     * Returns the currently selected classes in this Package.
+     * If no class is selected an empty array is returned.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public BClass [] getCurrentClasses ()
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package bluejPkg = packageId.getBluejPackage();    
+        Target [] targets = bluejPkg.getSelectedTargets();
+        ArrayList<BClass> aList  = new ArrayList<BClass>();
+        
+        for(int index=0; index<targets.length; index++) 
+        {
+            if ( !(targets[index] instanceof ClassTarget )) continue; 
+
+            ClassTarget target = (ClassTarget)targets[index];
+            aList.add(target.getBClass());
+        }
+
+        return aList.toArray(new BClass[aList.size()]);
+    }
+
+    /** 
+     * Returns the currently selected objects in the Object Bench.
+     * If no object is selected an empty array is returned.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public BObject[] getCurrentObjects ()
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        PkgMgrFrame bluejFrame = packageId.getPackageFrame();
+        ObjectBench aBench = bluejFrame.getObjectBench();
+        if ( aBench == null ) return new BObject[0];
+
+        ArrayList<BObject> aList  = new ArrayList<BObject>();
+        // In the future we will really return more than one element
+        ObjectWrapper aWrapper = aBench.getSelectedObject();
+        if (aWrapper != null) {
+            aList.add(aWrapper.getBObject());
+        }
+
+        return aList.toArray(new BObject[aList.size()]);
+    }
+
+    /**
+     * Returns the directory where this package is stored.
+     * @throws ProjectNotOpenException if the project this package is part of has been closed by the user.
+     * @throws PackageNotFoundException if the package has been deleted by the user.
+     */
+    public File getDir ()
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package aPkg = packageId.getBluejPackage();
+
+        return aPkg.getPath();
+    }
+
+    /**
+     * Returns the dependency with the given <code>origin</code>,
+     * <code>target</code> and <code>type</code>.
+     * 
+     * @param from
+     *            The origin of the dependency.
+     * @param to
+     *            The target of the dependency.
+     * @param type
+     *            The type of the dependency (there may be more than one
+     *            dependencies with the same origin and target but different
+     *            types).
+     * @return The dependency with the given <code>origin</code> and
+     *         <code>target</code> or <code>null</code> if there is no such
+     *         dependency.
+     * @throws ProjectNotOpenException
+     *             if the project this package is part of has been closed by the
+     *             user.
+     * @throws PackageNotFoundException
+     *             if the package has been deleted by the user.
+     */
+    public BDependency getDependency(BClassTarget from, BClassTarget to, Type type)
+            throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package bluejPackage = packageId.getBluejPackage();
+        Dependency dependency = bluejPackage.getDependency(from.getClassTarget(), to.getClassTarget(), type);
+        
+        return (dependency != null) ? dependency.getBDependency() : null;
+    }
+
+    /**
+     * Returns a string representation of the package object
+     */
+    public String toString () 
+    {
+        try 
+        {
+            Package bluejPkg = packageId.getBluejPackage();
+            return "BPackage: "+bluejPkg.getQualifiedName();
+        }
+        catch ( ExtensionException exc )
+        {
+            return "BPackage: INVALID";  
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BProject.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BProject.java
new file mode 100644
index 0000000000000000000000000000000000000000..f8fe109217c65967d3d59ebe825bd5f9c5c86988
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BProject.java
@@ -0,0 +1,227 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import java.io.File;
+import java.net.URLClassLoader;
+import java.util.List;
+import java.util.ListIterator;
+
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+
+/**
+ * A wrapper for a BlueJ project.
+ *
+ * @author Clive Mille, Univeristy of Kent at Canterbury, 2002
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003,2004,2005
+ */
+public class BProject
+{
+    private Identifier projectId;
+  
+    /**
+     * Constructor for a BProject.
+     */
+    BProject (Identifier i_projectId)
+    {
+        projectId = i_projectId;
+    }
+
+    /**
+     * Returns the name of this project. 
+     * This is what is displayed in the title bar of the frame after 'BlueJ'.
+     * @throws ProjectNotOpenException if the project has been closed by the user.
+     */
+    public String getName() throws ProjectNotOpenException
+    {
+        Project thisProject = projectId.getBluejProject();
+        
+        return thisProject.getProjectName();
+    }
+    
+    /**
+     * Returns the directory in which this project is stored. 
+     * @throws ProjectNotOpenException if the project has been closed by the user.
+     */
+    public File getDir() throws ProjectNotOpenException
+    {
+        Project thisProject = projectId.getBluejProject();
+
+        return thisProject.getProjectDir();
+    }
+    
+    /**
+     * Requests a "save" of all open files in this project. 
+     * @throws ProjectNotOpenException if the project has been closed by the user.
+     */
+    public void save() throws ProjectNotOpenException
+    {
+        Project thisProject = projectId.getBluejProject();
+
+        thisProject.saveAll();
+    }
+    
+    /**
+     * Saves any open files, then closes all frames belonging to this project.
+     * @throws ProjectNotOpenException if the project has been closed by the user.
+     */
+    public void close() throws ProjectNotOpenException
+    {
+        Project thisProject = projectId.getBluejProject();
+
+        thisProject.saveAll();
+        PkgMgrFrame.closeProject (thisProject);
+    }
+    
+    /**
+     * Restarts the VM used to run user code for this project.
+     * As a side-effect, removes all objects from the object bench.
+     * @throws ProjectNotOpenException if the project has been closed by the user.
+     */
+    public void restartVM() throws ProjectNotOpenException
+    {
+        projectId.getBluejProject().restartVM();
+    }
+    
+    /**
+     * Create and return a new package with the given fully qualified name.
+     * The necessary directories and files will be created.
+     * 
+     * @return the requested package, or null if it wasn't found
+     * @throws ProjectNotOpenException if the project has been closed by the user.
+     * @throws PackageAlreadyExistsException if the named package already exists in the project.
+     */
+    public BPackage newPackage( String fullyQualifiedName )
+        throws ProjectNotOpenException, PackageAlreadyExistsException
+    {
+        Project bluejProject = projectId.getBluejProject();
+
+        int result = bluejProject.newPackage(fullyQualifiedName);
+
+        if ( result == Project.NEW_PACKAGE_BAD_NAME ) {
+            throw new IllegalArgumentException("newPackage: Bad package name '"+fullyQualifiedName+"'");
+        }
+            
+        if ( result == Project.NEW_PACKAGE_EXIST ) {
+            throw new PackageAlreadyExistsException("newPackage: Package '"+fullyQualifiedName+"' already exists");
+        }
+
+        if ( result == Project.NEW_PACKAGE_NO_PARENT ) {
+            throw new IllegalStateException("newPackage: Package '"+fullyQualifiedName+"' has no parent package");
+        }
+
+        if ( result != Project.NEW_PACKAGE_DONE ) {
+            throw new IllegalStateException("newPackage: Unknown result code="+result);
+        }
+
+        Package pkg = bluejProject.getPackage(fullyQualifiedName);
+
+        if ( pkg == null ) {
+            throw new Error("newPackage: getPackage '"+fullyQualifiedName+"' returned null");
+        }
+
+        Package reloadPkg = pkg;
+        for(int index=0; index<10 && reloadPkg != null; index++) {
+            // This is needed since the GUI is not sync with the state
+            // It would be better is core BlueJ did fix this..
+            reloadPkg.reload();
+            reloadPkg = reloadPkg.getParent();
+        }
+
+        return pkg.getBPackage();
+    }
+    
+    /**
+     * Get a package belonging to this project.
+     * 
+     * @param name the fully-qualified name of the package
+     * @return the requested package, or null if it wasn't found
+    * 
+     * @throws ProjectNotOpenException if the project has been closed by the user.
+     */
+    public BPackage getPackage (String name) throws ProjectNotOpenException
+    {
+        Project bluejProject = projectId.getBluejProject();
+        Package pkg = bluejProject.getPackage (name);
+        if (pkg == null) {
+            return null;
+        }
+        return pkg.getBPackage();
+    }
+    
+    /**
+     * Returns all packages belonging to this project.
+     * @return The array of this project's packages, if none exist an empty array is returned.
+     * @throws ProjectNotOpenException if the project has been closed by the user.
+     */
+    public BPackage[] getPackages() throws ProjectNotOpenException
+    {
+        Project thisProject = projectId.getBluejProject();
+
+        List<String> names = thisProject.getPackageNames();
+        BPackage[] packages = new BPackage [names.size()];
+        for (ListIterator<String> li = names.listIterator(); li.hasNext();) {
+            int i=li.nextIndex();
+            String name = li.next();
+            packages [i] = getPackage (name);
+        }
+        return packages;
+    }
+
+
+    /**
+     * Returns a URLClassLoader that should be used to load project classes.
+     * Every time a project is compiled, even when the compilation is started from the GUI, 
+     * a new URLClassLoader is created and if the Extension currently have a copy of the old one it should discard it
+     * and use getClassLoader() to acquire the new one.
+     * @return A class loader that should be used to load project classes.
+     * @throws ProjectNotOpenException if the project has been closed by the user.
+     */
+    public URLClassLoader getClassLoader() throws ProjectNotOpenException
+    {
+        Project thisProject = projectId.getBluejProject();
+
+        return thisProject.getClassLoader();
+    }
+    
+    /**
+     * Returns a string representation of this package object
+     */
+    public String toString ()
+    {
+        try {
+            Project thisProject = projectId.getBluejProject();
+            return "BProject: "+thisProject.getProjectName();
+        }
+        catch(ExtensionException exc) {
+            return "BProject: INVALID";  
+        }
+    }
+    
+    void clearObjectBench() throws ProjectNotOpenException
+    {
+        Project thisProject = projectId.getBluejProject();
+        thisProject.clearObjectBenches();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BlueJ.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BlueJ.java
new file mode 100644
index 0000000000000000000000000000000000000000..db2c947bef7418ce096101ca3bf648baac7443eb
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/BlueJ.java
@@ -0,0 +1,976 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import bluej.*;
+import bluej.extensions.event.*;
+import bluej.extensions.painter.ExtensionClassTargetPainter;
+import bluej.extmgr.*;
+import bluej.pkgmgr.*;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.graphPainter.ClassTargetPainter.Layer;
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import java.util.List;
+import javax.swing.*;
+
+/**
+ * A proxy object which provides services to BlueJ extensions.
+ * From this class
+ * an extension can obtain the projects and packages which BlueJ is currently displayng
+ * and the classes and objects they contain. Fields and methods of these objects
+ * can be inspected and invoked using an API based on Java's reflection API.
+ *
+ * Every effort has been made to retain the logic of the Reflection API and to provide
+ * methods that behave in a very similar way.
+ *
+ * <PRE>
+ * BlueJ
+ *   |
+ *   +---- BProject
+ *             |
+ *             +---- BPackage
+ *                      |
+ *                      +--------- BClass
+ *                      |            |
+ *                      +- BObject   + BConstructor
+ *                                   |      |
+ *                                   |      +- BObject
+ *                                   |
+ *                                   +---- BMethod
+ *                                   |      |
+ *                                   |      +- BObject
+ *                                   |
+ *                                   +---- BField
+ *
+ * </PRE>
+ * Attempts to invoke methods on a BlueJ object made by an extension
+ * after its <code>terminate()</code> method has been called will result
+ * in an (unchecked) <code>ExtensionUnloadedException</code> being thrown.
+ *
+ * @version    $Id: BlueJ.java 10207 2013-01-14 17:36:41Z davmac $
+ */
+
+/*
+ * Author Clive Miller, University of Kent at Canterbury, 2002
+ * Author Damiano Bolla, University of Kent at Canterbury, 2003, 2004, 2005
+ */
+public final class BlueJ
+{
+    public static final int SE_PROJECT = 0;
+    public static final int ME_PROJECT = 1;
+    
+    private final ExtensionWrapper myWrapper;
+    private final ExtensionPrefManager prefManager;
+
+    private PreferenceGenerator currentPrefGen = null;
+    private MenuGenerator currentMenuGen = null;
+    private ExtensionClassTargetPainter currentClassTargetPainter;
+    private Properties localLabels;
+
+    private ArrayList<ExtensionEventListener> eventListeners;
+    // This is the queue for the whole of them
+    private ArrayList<ApplicationListener> applicationListeners;
+    private ArrayList<PackageListener> packageListeners;
+    private ArrayList<CompileListener> compileListeners;
+    private ArrayList<InvocationListener> invocationListeners;
+    private ArrayList<ClassListener> classListeners;
+    private List<DependencyListener> dependencyListeners;
+    private List<ClassTargetListener> classTargetListeners;
+
+
+    /**
+     * Constructor for a BlueJ proxy object.
+     * See the ExtensionBridge class.
+     *
+     * @param  aWrapper      Description of the Parameter
+     * @param  aPrefManager  Description of the Parameter
+     */
+    BlueJ(ExtensionWrapper aWrapper, ExtensionPrefManager aPrefManager)
+    {
+        myWrapper = aWrapper;
+        prefManager = aPrefManager;
+
+        eventListeners = new ArrayList<ExtensionEventListener>();
+        applicationListeners = new ArrayList<ApplicationListener>();
+        packageListeners = new ArrayList<PackageListener>();
+        compileListeners = new ArrayList<CompileListener>();
+        invocationListeners = new ArrayList<InvocationListener>();
+        classListeners = new ArrayList<ClassListener>();
+        dependencyListeners = new ArrayList<DependencyListener>();
+        classTargetListeners = new ArrayList<ClassTargetListener>();
+
+        // Don't use lazy initialisation here, to avoid multiple reloads
+        localLabels = myWrapper.getLabelProperties();
+    }
+
+    /**
+     * Opens a project.
+     *
+     * @param  directory  Where the project is stored.
+     * @return            the BProject that describes the newly opened project,
+     *                    or null if it cannot be opened.
+     */
+    public final BProject openProject(File directory)
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        // Yes somebody may just call it with null, for fun..
+        if (directory == null)
+            return null;
+
+        Project openProj = Project.openProject(directory.getAbsolutePath(), null);
+        if (openProj == null)
+            return null;
+
+        // a hack, since bluej does not handle "opening" of projects correctly.
+        // this code should really be into openProject or it should not be possible to open
+        // a project is the initial package name is not there.
+        Package pkg = openProj.getCachedPackage(openProj.getInitialPackageName());
+        if (pkg == null)
+            return null;
+
+        // I make a new identifier out of this
+        Identifier aProject = new Identifier(openProj, pkg);
+
+        // This will make the frame if not already there. should not be needed...
+        try {
+            aProject.getPackageFrame();
+        } catch (ExtensionException exc) {}
+
+        // Note: the previous Identifier is not used here.
+        return openProj.getBProject();
+    }
+
+
+    /**
+     * Creates a new BlueJ project.
+     *
+     * @param  directory    where you want the project be placed, it must be writable.
+     * @param  projectType  the type of project, such as ME or SE.
+     * @return              the newly created BProject if successful, null otherwise.
+     */
+    public BProject newProject(File directory, int projectType )
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        String pathString = directory.getAbsolutePath();
+        if (!pathString.endsWith(File.separator))
+            pathString += File.separator;
+            
+        if (!Project.createNewProject(pathString, projectType == ME_PROJECT))
+            return null;
+            
+        return openProject(directory);
+    }
+
+
+    /**
+     * Creates a new BlueJ project.
+     *
+     * @param  directory  where you want the project be placed, it must be writable.
+     * @return            the newly created BProject if successful, null otherwise.
+     */
+    public BProject newProject(File directory)
+    {
+        return newProject( directory, SE_PROJECT );
+    }
+
+    
+    /**
+     * Returns all currently open projects.
+     * Returns an empty array if no projects are open.
+     *
+     * @return    The openProjects value
+     */
+    public BProject[] getOpenProjects()
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        Collection<Project> projects = Project.getProjects();
+        BProject[] result = new BProject[projects.size()];
+
+        Iterator<Project> iter; int index;
+        for (iter = projects.iterator(), index = 0; iter.hasNext(); index++) {
+            Project prj = iter.next();
+            result[index] = prj.getBProject();
+        }
+
+        return result;
+    }
+
+
+    /**
+     * Returns the currently selected package.
+     * The current package is the one that is currently selected by the
+     * user interface.
+     * It can return null if there is no currently open package.
+     *
+     * @return    The currentPackage value
+     */
+    public BPackage getCurrentPackage()
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        // This is here and NOT into a BProject since it depends on user interface.
+
+        PkgMgrFrame pmf = PkgMgrFrame.getMostRecent();
+        // If there is nothing at all open there is no Frame open...
+        if (pmf == null)
+            return null;
+
+        Package pkg = pmf.getPackage();
+        // The frame may be there BUT have no package.
+        if (pkg == null)
+            return null;
+
+        return pkg.getBPackage();
+    }
+
+
+    /**
+     * Returns the current frame being displayed.
+     * Can be used (e.g.) as a "parent" frame for positioning modal dialogs.
+     * If there is a package currently open, it's probably better to use its <code>getFrame()</code>
+     * method to provide better placement.
+     *
+     * @return    The currentFrame value
+     */
+    public Frame getCurrentFrame()
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        return PkgMgrFrame.getMostRecent();
+    }
+
+
+    /**
+     * Install a new menu generator for this extension.
+     * If you want to delete a previously installed menu, then set it to null
+     *
+     *
+     * @param  menuGen        The new menuGenerator value
+     */
+    public void setMenuGenerator(MenuGenerator menuGen)
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        currentMenuGen = menuGen;
+    }
+
+
+    /**
+     * Returns the currently registered menu generator
+     *
+     * @return    The menuGenerator value
+     */
+    public MenuGenerator getMenuGenerator()
+    {
+        return currentMenuGen;
+    }
+
+
+    /**
+     * Install a new preference panel for this extension.
+     * If you want to delete a previously installed preference panel, then set it to null
+     *
+     * @param  prefGen  a class instance that implements the PreferenceGenerator interface.
+     */
+    public void setPreferenceGenerator(PreferenceGenerator prefGen)
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        currentPrefGen = prefGen;
+        prefManager.panelRevalidate();
+    }
+
+
+    /**
+     * Returns the currently registered preference generator.
+     *
+     * @return    The preferenceGenerator value
+     */
+    public PreferenceGenerator getPreferenceGenerator()
+    {
+        return currentPrefGen;
+    }
+
+
+    /**
+     * Installs a new custom class target painter for this extension. If you
+     * want to delete a previously installed custom class target painter, then
+     * set it to <code>null</code>.
+     * 
+     * @param classTargetPainter
+     *            The {@link ExtensionClassTargetPainter} to set.
+     */
+    public void setClassTargetPainter(ExtensionClassTargetPainter classTargetPainter)
+    {
+        if (!myWrapper.isValid()) {
+            throw new ExtensionUnloadedException();
+        }
+
+        currentClassTargetPainter = classTargetPainter;
+    }
+
+    /**
+     * Returns the currently registered custom class target painter.
+     * 
+     * @return The currently registered custom class target painter.
+     */
+    public ExtensionClassTargetPainter getClassTargetPainter()
+    {
+        return currentClassTargetPainter;
+    }
+
+    /**
+     * Returns the path of the <code>&lt;BLUEJ_HOME&gt;/lib</code> system directory.
+     * This can be used to locate systemwide configuration files.
+     * Having the directory you can then locate a file within it.
+     *
+     * @return    The systemLibDir value
+     */
+    public File getSystemLibDir()
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        return Config.getBlueJLibDir();
+    }
+
+
+    /**
+     * Returns the path of the user configuration directory.
+     * This can be used to locate user dependent information.
+     * Having the directory you can then locate a file within it.
+     *
+     * @return    The userConfigDir value
+     */
+    public File getUserConfigDir()
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        return Config.getUserConfigDir();
+    }
+    
+
+    /**
+     * Returns a property from BlueJ's properties,
+     * or the given default value if the property is not currently set.
+     *
+     * @param  property  The name of the required global property
+     * @param  def       The default value to use if the property cannot be found.
+     * @return           the value of the property.
+     */
+    public String getBlueJPropertyString(String property, String def)
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        return Config.getPropString(property, def);
+    }
+
+
+    /**
+     * Return a property associated with this extension from the standard BlueJ property repository.
+     * You must use the setExtensionPropertyString to write any property that you want stored.
+     * You can then come back and retrieve it using this function.
+     *
+     * @param  property  The name of the required global property.
+     * @param  def       The default value to use if the property cannot be found.
+     * @return           the value of that property.
+     */
+    public String getExtensionPropertyString(String property, String def)
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        String thisKey = myWrapper.getSettingsString(property);
+        return Config.getPropString(thisKey, def);
+    }
+
+
+    /**
+     * Sets a property associated with this extension into the standard BlueJ property repository.
+     * The property name does not need to be fully qualified since a prefix will be prepended to it.
+     *
+     *
+     * @param  property  The name of the required global property
+     * @param  value     the required value of that property (or null to remove the property)
+     */
+    public void setExtensionPropertyString(String property, String value)
+    {
+        if (!myWrapper.isValid()) {
+            throw new ExtensionUnloadedException();
+        }
+
+        String thisKey = myWrapper.getSettingsString(property);
+        if (value != null) {
+            Config.putPropString(thisKey, value);
+        }
+        else {
+            Config.removeProperty(thisKey);
+        }
+    }
+
+
+    /**
+     * Returns the language-dependent label with the given key.
+     * The search order is to look first in the extension's <code>label</code> files and
+     * if the requested label is not found in the BlueJ system <code>label</code> files.
+     * Extensions' labels are stored in a Property format and must be jarred together
+     * with the extension. The path searched is equivalent to the bluej/lib/[language]
+     * style used for the BlueJ system labels. E.g. to create a set of labels which can be used
+     * by English, Italian and German users of an extension, the following files would need to
+     * be present in the extension's Jar file:
+     * <pre>
+     * lib/english/label
+     * lib/italian/label
+     * lib/german/label
+     * </pre>
+     * The files named <code>label</code> would contain the actual label key/value pairs.
+     *
+     * @param  key  Description of the Parameter
+     * @return      The label value
+     */
+    public String getLabel(String key)
+    {
+        if (!myWrapper.isValid())
+            throw new ExtensionUnloadedException();
+
+        // If there are no label for this extension I can only return the system ones.
+        if (localLabels == null)
+            return Config.getString(key, key);
+
+        // In theory there are label for this extension let me try to get them
+        String aLabel = localLabels.getProperty(key, null);
+
+        // Found what I wanted, job done.
+        if (aLabel != null)
+            return aLabel;
+
+        // ok, the only hope is to get it from the system
+        return Config.getString(key, key);
+    }
+
+
+
+    /**
+     * Registers a listener for all the events generated by BlueJ.
+     */
+    public void addExtensionEventListener(ExtensionEventListener listener)
+    {
+        if (listener != null) {
+            synchronized (eventListeners) {
+                eventListeners.add(listener);
+            }
+        }
+    }
+
+
+    /**
+     * Removes the specified listener so that it no longer receives events.
+     */
+    public void removeExtensionEventListener(ExtensionEventListener listener)
+    {
+        if (listener != null) {
+            synchronized (eventListeners) {
+                eventListeners.remove(listener);
+            }
+        }
+    }
+
+
+    /**
+     * Registers a listener for application events.
+     */
+    public void addApplicationListener(ApplicationListener listener)
+    {
+        if (listener != null) {
+            synchronized (applicationListeners) {
+                applicationListeners.add(listener);
+            }
+        }
+    }
+
+
+    /**
+     * Removes the specified listener so that it no longer receives events.
+     */
+    public void removeApplicationListener(ApplicationListener listener)
+    {
+        if (listener != null) {
+            synchronized (applicationListeners) {
+                applicationListeners.remove(listener);
+            }
+        }
+    }
+
+
+    /**
+     * Registers a listener for package events.
+     */
+    public void addPackageListener(PackageListener listener)
+    {
+        if (listener != null) {
+            synchronized (packageListeners) {
+                packageListeners.add(listener);
+            }
+        }
+    }
+
+
+    /**
+     * Removes the specified listener so that it no longer receives events.
+     */
+    public void removePackageListener(PackageListener listener)
+    {
+        if (listener != null) {
+            synchronized (packageListeners) {
+                packageListeners.remove(listener);
+            }
+        }
+    }
+
+
+    /**
+     * Registers a listener for compile events.
+     */
+    public void addCompileListener(CompileListener listener)
+    {
+        if (listener != null) {
+            synchronized (compileListeners) {
+                compileListeners.add(listener);
+            }
+        }
+    }
+
+
+    /**
+     * Removes the specified listener so that it no longer receives events.
+     */
+    public void removeCompileListener(CompileListener listener)
+    {
+        if (listener != null) {
+            synchronized (compileListeners) {
+                compileListeners.remove(listener);
+            }
+        }
+    }
+
+
+    /**
+     * Registers a listener for invocation events.
+     */
+    public void addInvocationListener(InvocationListener listener)
+    {
+        if (listener != null) {
+            synchronized (invocationListeners) {
+                invocationListeners.add(listener);
+            }
+        }
+    }
+
+
+    /**
+     * Removes the specified listener so no that it no longer receives events.
+     */
+    public void removeInvocationListener(InvocationListener listener)
+    {
+        if (listener != null) {
+            synchronized (invocationListeners) {
+                invocationListeners.remove(listener);
+            }
+        }
+    }
+
+
+    /**
+     * Register a listener for class events.
+     * 
+     * @param listener
+     */
+    public void addClassListener(ClassListener listener)
+    {
+        if (listener != null) {
+            synchronized (classListeners) {
+                classListeners.add(listener);
+            }
+        }
+    }
+    
+    /**
+     * Removes the specified class listener so no that it no longer receives
+     * class events.
+     */
+    public void removeClassListener(ClassListener listener)
+    {
+        if (listener != null) {
+            synchronized (classListeners) {
+                classListeners.remove(listener);
+            }
+        }
+    }
+    
+    /**
+     * Register a listener for dependency events.
+     * 
+     * @param listener
+     *            The listener to register.
+     */
+    public void addDependencyListener(DependencyListener listener)
+    {
+        if (listener != null) {
+            synchronized (dependencyListeners) {
+                dependencyListeners.add(listener);
+            }
+        }
+    }
+
+    /**
+     * Removes the specified dependency listener so it no longer receives
+     * dependency events.
+     */
+    public void removeDependencyListener(DependencyListener listener)
+    {
+        if (listener != null) {
+            synchronized (dependencyListeners) {
+                dependencyListeners.remove(listener);
+            }
+        }
+    }
+    
+    /**
+     * Register a listener for class target events.
+     * 
+     * @param listener
+     *            The listener to register.
+     */
+    public void addClassTargetListener(ClassTargetListener listener)
+    {
+        if (listener != null) {
+            synchronized (classTargetListeners) {
+                classTargetListeners.add(listener);
+            }
+        }
+    }
+
+    /**
+     * Removes the specified class target listener so it no longer receives
+     * class target events.
+     */
+    public void removeClassTargetListener(ClassTargetListener listener)
+    {
+        if (listener != null) {
+            synchronized (classTargetListeners) {
+                classTargetListeners.remove(listener);
+            }
+        }
+    }
+
+    /**
+     * Dispatch this event to the listeners for the ALL events.
+     *
+     * @param  event  Description of the Parameter
+     */
+    private void delegateExtensionEvent(ExtensionEvent event)
+    {
+        ExtensionEventListener [] listeners;
+        
+        synchronized (eventListeners) {
+            listeners = (ExtensionEventListener []) eventListeners.toArray(new ExtensionEventListener [eventListeners.size()]);
+        }
+        
+        for (int i = 0; i < listeners.length; i++) {
+            ExtensionEventListener eventListener = listeners[i];
+            eventListener.eventOccurred(event);
+        }
+    }
+
+
+    /**
+     * Dispatch this event to the listeners for the Application events.
+     *
+     * @param  event  Description of the Parameter
+     */
+    private void delegateApplicationEvent(ApplicationEvent event)
+    {
+        ApplicationListener [] listeners;
+        
+        synchronized (applicationListeners) {
+            listeners = (ApplicationListener []) applicationListeners.toArray(new ApplicationListener[applicationListeners.size()]);
+        }
+        
+        for (int i = 0; i < listeners.length; i++) {
+            ApplicationListener eventListener = listeners[i];
+            // Just this for the time being.
+            eventListener.blueJReady(event);
+        }
+    }
+
+
+    /**
+     * Dispatch this event to the listeners for the Package events.
+     *
+     * @param  event  Description of the Parameter
+     */
+    private void delegatePackageEvent(PackageEvent event)
+    {
+        PackageListener [] listeners;
+        
+        synchronized (packageListeners) {
+            listeners = (PackageListener []) packageListeners.toArray(new PackageListener[packageListeners.size()]);
+        }
+        
+        int thisEvent = event.getEvent();
+
+        for (int i = 0; i < listeners.length; i++) {
+            PackageListener eventListener = listeners[i];
+            if (thisEvent == PackageEvent.PACKAGE_OPENED)
+                eventListener.packageOpened(event);
+            if (thisEvent == PackageEvent.PACKAGE_CLOSING)
+                eventListener.packageClosing(event);
+        }
+    }
+
+
+    /**
+     * Dispatch this event to the listeners for the Compile events.
+     *
+     * @param  event  Description of the Parameter
+     */
+    private void delegateCompileEvent(CompileEvent event)
+    {
+        CompileListener [] listeners;
+        
+        synchronized (compileListeners) {
+            listeners = (CompileListener []) compileListeners.toArray(new CompileListener[compileListeners.size()]);
+        }
+        
+        int thisEvent = event.getEvent();
+
+        for (int i = 0; i < listeners.length; i++) {
+            CompileListener eventListener = listeners[i];
+            if (thisEvent == CompileEvent.COMPILE_START_EVENT)
+                eventListener.compileStarted(event);
+            if (thisEvent == CompileEvent.COMPILE_ERROR_EVENT)
+                eventListener.compileError(event);
+            if (thisEvent == CompileEvent.COMPILE_WARNING_EVENT)
+                eventListener.compileWarning(event);
+            if (thisEvent == CompileEvent.COMPILE_FAILED_EVENT)
+                eventListener.compileFailed(event);
+            if (thisEvent == CompileEvent.COMPILE_DONE_EVENT)
+                eventListener.compileSucceeded(event);
+        }
+    }
+
+
+    /**
+     * Dispatch this event to the listeners for the Invocation events.
+     *
+     * @param  event  The event to dispatch
+     */
+    private void delegateInvocationEvent(InvocationEvent event)
+    {
+        InvocationListener [] listeners;
+        
+        synchronized (invocationListeners) {
+            listeners = (InvocationListener []) invocationListeners.toArray(new InvocationListener[invocationListeners.size()]);
+        }
+        
+        for (int i = 0; i < listeners.length; i++) {
+            listeners[i].invocationFinished(event);
+        }
+    }
+
+    /**
+     * Dispatch a class event to the appropriate listeners.
+     * 
+     * @param event  The event to dispatch
+     */
+    private void delegateClassEvent(ClassEvent event)
+    {
+        // We'll make a copy of the current list to prevent
+        // ConcurrentModification problems.
+        ClassListener [] listeners;
+        
+        synchronized (classListeners) {
+            listeners = (ClassListener []) classListeners.toArray(new ClassListener[classListeners.size()]);
+        }
+        
+        for (int i = 0; i < listeners.length; i++) {
+            if (event.getEventId() == ClassEvent.REMOVED) {
+                if (listeners[i] instanceof ClassListener2) {
+                    ((ClassListener2) listeners[i]).classRemoved(event);
+                }
+            } else {
+                listeners[i].classStateChanged(event);
+            }
+        }
+    }
+
+    /**
+     * Dispatch this event to the listeners for the Dependency events.
+     * 
+     * @param event
+     *            The event to dispatch
+     */
+    private void delegateDependencyEvent(DependencyEvent event)
+    {
+        List<DependencyListener> listeners = new ArrayList<DependencyListener>();
+        synchronized (dependencyListeners) {
+            listeners.addAll(dependencyListeners);
+        }
+        
+        for (DependencyListener dependencyListener : listeners) {
+            switch (event.getEventType()) {
+                case DEPENDENCY_ADDED:
+                    dependencyListener.dependencyAdded(event);
+                    break;
+                case DEPENDENCY_REMOVED:
+                    dependencyListener.dependencyRemoved(event);
+                    break;
+                case DEPENDENCY_HIDDEN:
+                case DEPENDENCY_SHOWN:
+                    dependencyListener.dependencyVisibilityChanged(event);
+                    break;
+            }
+        }
+    }
+    
+    /**
+     * Dispatch this event to the listeners for the class target events.
+     * 
+     * @param event
+     *            The event to dispatch
+     */
+    private void delegateClassTargetEvent(ClassTargetEvent event)
+    {
+        List<ClassTargetListener> listeners = new ArrayList<ClassTargetListener>();
+        synchronized (classTargetListeners) {
+            listeners.addAll(classTargetListeners);
+        }
+        
+        for (ClassTargetListener classTargetListener : listeners) {
+            classTargetListener.classTargetVisibilityChanged(event);
+        }
+    }
+
+    /**
+     * Informs any registered listeners that an event has occurred.
+     * This will call the various dispatcher as needed.
+     * Errors will be trapped by the caller.
+     */
+    void delegateEvent(ExtensionEvent event)
+    {
+        delegateExtensionEvent(event);
+        if (event instanceof ApplicationEvent)
+            delegateApplicationEvent((ApplicationEvent) event);
+        else if (event instanceof PackageEvent)
+            delegatePackageEvent((PackageEvent) event);
+        else if (event instanceof CompileEvent)
+            delegateCompileEvent((CompileEvent) event);
+        else if (event instanceof InvocationEvent)
+            delegateInvocationEvent((InvocationEvent) event);
+        else if (event instanceof ClassEvent)
+            delegateClassEvent((ClassEvent) event);
+        else if (event instanceof DependencyEvent) {
+            delegateDependencyEvent((DependencyEvent) event);
+        } else if (event instanceof ClassTargetEvent) {
+            delegateClassTargetEvent((ClassTargetEvent) event);
+        }
+    }
+
+
+
+    /**
+     * Calls the extension to get the right menu item.
+     * This is already wrapped for errors in the caller.
+     * It is right for it to create a new wrapped object each time.
+     * We do not want extensions to share objects.
+     * It is here since it can access all constructors directly.
+     *
+     * @param  attachedObject  Description of the Parameter
+     * @return                 The menuItem value
+     */
+    JMenuItem getMenuItem(ExtensionMenuObject attachedObject)
+    {
+        if ((currentMenuGen == null) || (attachedObject == null)) {
+            return null;
+        }
+
+        return attachedObject.getMenuItem(currentMenuGen);
+    }
+
+
+    /**
+     * Post a notification of a menu going to be displayed
+     */
+    void postMenuItem(ExtensionMenuObject attachedObject, JMenuItem onThisItem)
+    {
+        if ((currentMenuGen != null) && (attachedObject != null)) {
+            attachedObject.postMenuItem(currentMenuGen, onThisItem);
+        }
+    }
+
+    /**
+     * Calls the extension to draw its representation of a class target.
+     * 
+     * @param layer
+     *            The layer of the drawing which causes the different methods of
+     *            the {@link ExtensionClassTargetPainter} instance to be called.
+     * @param bClassTarget
+     *            The {@link BClassTarget} which represents the class target
+     *            that will be painted.
+     * @param graphics
+     *            The {@link Graphics2D} instance to draw on.
+     * @param width
+     *            The width of the area to paint.
+     * @param height
+     *            The height of the area to paint.
+     */
+    void drawExtensionClassTarget(Layer layer, BClassTarget bClassTarget, Graphics2D graphics,
+            int width, int height)
+    {
+        if (currentClassTargetPainter != null) {
+            switch (layer) {
+                case BACKGROUND :
+                    currentClassTargetPainter.drawClassTargetBackground(bClassTarget, graphics,
+                        width, height);
+                    break;
+                case FOREGROUND :
+                    currentClassTargetPainter.drawClassTargetForeground(bClassTarget, graphics,
+                        width, height);
+                    break;
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ClassNotFoundException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ClassNotFoundException.java
new file mode 100644
index 0000000000000000000000000000000000000000..366f9d1fc4ec528fb552f298380f8c2f1153f6b2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ClassNotFoundException.java
@@ -0,0 +1,40 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+/**
+ * This exception will be thrown when a reference to a class is no longer valid. 
+ * The most likely reason is that the user has deleted the class
+ * using the GUI.
+ * 
+ * @version $Id: ClassNotFoundException.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+/*
+ * Author: Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class ClassNotFoundException extends ExtensionException 
+{
+  ClassNotFoundException (String reason) {
+      super (reason);
+  }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/CompilationNotStartedException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/CompilationNotStartedException.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ddd3527404b2428064708c9561063c3af809383
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/CompilationNotStartedException.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+/**
+ * This exception will be thrown when a compile request cannot be started.
+ * The most likely reason for a compilation to abort is that BlueJ is currently
+ * executing some class code.
+ *
+ * @version $Id: CompilationNotStartedException.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+/*
+ * Author: Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class CompilationNotStartedException extends ExtensionException 
+{
+  CompilationNotStartedException (String reason) {
+      super (reason);
+  }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/DirectInvoker.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/DirectInvoker.java
new file mode 100644
index 0000000000000000000000000000000000000000..597dea7bad31f0dbddf932460af63d33751b22a5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/DirectInvoker.java
@@ -0,0 +1,503 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import bluej.BlueJEvent;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugmgr.ExecutionEvent;
+import bluej.debugmgr.Invoker;
+import bluej.debugmgr.ResultWatcher;
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.Utility;
+import bluej.views.CallableView;
+import bluej.views.ConstructorView;
+import bluej.views.MethodView;
+
+/**
+ * Provides a gateway to invoke methods on objects using a specified set of parameters.
+ *
+ * @author     Damiano Bolla, University of Kent at Canterbury, 2003,2004
+ * @author     Clive Miller, University of Kent at Canterbury, 2002
+ */
+class DirectInvoker
+{
+    private final PkgMgrFrame pkgFrame;
+    private String resultName;
+
+
+    /**
+     * For use by the bluej.extensions
+     *
+     * @param  i_pkgFrame  Description of the Parameter
+     * @param  i_callable  Description of the Parameter
+     */
+    DirectInvoker(PkgMgrFrame i_pkgFrame)
+    {
+        pkgFrame = i_pkgFrame;
+    }
+
+
+    /**
+     * Call this if you want to call a constructor
+     *
+     * <p>The arguments passed in the args array may have any type,
+     * but the type will determine exactly what is passed to the
+     * constructor:
+     * 
+     * <ul>
+     * <li>String - the String will be passed directly to the constructor
+     * <li>BObject - the object will be passed directly to the constructor,
+     *               though it must be on the object bench for this to work
+     * <li>Anything else - toString() is called on the object and the
+     *               result is treated as a Java expression, which is
+     *               evaluated and passed to the constructor.
+     * </ul>
+     * 
+     * <p>An attempt is made to ensure that the argument types are suitable
+     * for the constructor. InvocationArgumentException will be thrown if
+     * the arguments are clearly unsuitable, however some cases will
+     * generate an InvocationErrorException instead. In such cases no
+     * expression arguments will be evaluated.
+     *
+     * @param  callable         The constructor to call
+     * @param  args             Arguments to the constructor
+     * @return                                  The newly created object
+     * @throws  InvocationArgumentException   if the argument list is not consistent with the signature
+     * @throws  InvocationErrorException      if there is a system error
+     */
+    DebuggerObject invokeConstructor(ConstructorView callable, Object[] args)
+             throws InvocationArgumentException, InvocationErrorException
+    {
+        if (!paramsAlmostMatch(args, callable.getParameters())) {
+            throw new InvocationArgumentException("invokeConstructor: bad arglist");
+        }
+
+        DirectResultWatcher watcher = new DirectResultWatcher();
+        Invoker invoker = new Invoker(pkgFrame, callable, watcher);
+        String [] argStrings = convObjToString(args);
+        invoker.invokeDirect(argStrings);
+
+        // this will wait() on the invoke to finish
+        DebuggerObject result = watcher.getResult();
+        
+        String resultType = watcher.getResultType();
+        if (resultType != null) {
+            ExecutionEvent ee = new ExecutionEvent(pkgFrame.getPackage(), callable.getClassName(), null);
+            raiseEvent(ee, callable, argStrings, watcher);
+        }
+
+        if (watcher.isFailed()) {
+            throw new InvocationErrorException("invokeConstructor: Error=" + watcher.getError());
+        }
+
+        if (result == null) {
+            // This is most likely an error, but not of the sort above. Unlikely to happen
+            throw new InvocationErrorException("invokeConstructor: ERROR: result==null");
+        }
+
+        resultName = watcher.getResultName();
+        return result;
+    }
+
+
+    /**
+     * Call a method on an object.
+     * You need to pass the object where you want it applied.
+     * 
+     * <p>The arguments passed in the args array may have any type,
+     * but the type will determine exactly what is passed to the
+     * method:
+     * 
+     * <ul>
+     * <li>String - the String will be passed directly to the method
+     * <li>BObject - the object will be passed directly to the method,
+     *               though it must be on the object bench for this to work
+     * <li>Anything else - toString() is called on the object and the
+     *               result is treated as a Java expression, which is
+     *               evaluated and passed to the method.
+     * </ul>
+     * 
+     * <p>An attempt is made to ensure that the argument types are suitable
+     * for the method. InvocationArgumentException will be thrown if
+     * the arguments are clearly unsuitable, however some cases will
+     * generate an InvocationErrorException instead. In such cases no
+     * expression arguments will be evaluated.
+     *
+     * @param  onThisObjectInstance             the method is called on this object
+     * @param  args                             The arguments for the method
+     * @return                                  The result object; for a constructor call this is the
+     *                                          constructed object; for any other invocation this will be
+     *                                          an object with a 'result' field containing the actual result,
+     *                                          or the null object (i.e. isNullObject() == true) if the result
+     *                                          type is void.
+     * @exception  InvocationArgumentException  Thrown if the arglist is not consistent with the signature
+     * @exception  InvocationErrorException     Thrown if there is a system error
+     */
+    DebuggerObject invokeMethod(ObjectWrapper onThisObjectInstance, MethodView callable, Object[] args)
+             throws InvocationArgumentException, InvocationErrorException
+    {
+        if (!paramsAlmostMatch(args, callable.getParameters())) {
+            throw new InvocationArgumentException("invokeMethod: bad arglist");
+        }
+
+        DirectResultWatcher watcher = new DirectResultWatcher();
+        Invoker invoker;
+        if (callable.isStatic()) {
+            invoker = new Invoker(pkgFrame, callable, watcher);
+        }
+        else {
+            invoker = new Invoker(pkgFrame, (MethodView) callable, onThisObjectInstance, watcher);
+        }
+        String [] argStrings = convObjToString(args);
+        invoker.invokeDirect(convObjToString(args));
+
+        // this will wait() on the invoke to finish
+        DebuggerObject result = watcher.getResult();
+
+        String resultType = watcher.getResultType();
+        if (resultType != null) {
+            ExecutionEvent ee = new ExecutionEvent(pkgFrame.getPackage(), callable.getClassName(),
+                    (onThisObjectInstance==null)?null:onThisObjectInstance.getName());
+            ee.setMethodName(callable.getName());
+            raiseEvent(ee, callable, argStrings, watcher);
+        }
+
+        if (watcher.isFailed()) {
+            throw new InvocationErrorException("invokeMethod: Error=" + watcher.getError());
+        }
+
+        // The "real" object is the first Field in this object.. BUT it is not always
+        // an Object, it may be a primitive one...
+        resultName = watcher.getResultName();
+        return result;
+    }
+
+    /**
+     * Raise an appropriate execution event, after a result has been received.
+     */
+    private static void raiseEvent(ExecutionEvent event, CallableView callable, String [] argStrings, 
+            DirectResultWatcher watcher)
+    {
+        DebuggerObject result = watcher.getResult();
+        String resultType = watcher.getResultType();
+        
+        event.setParameters(callable.getParamTypes(false), argStrings);
+        event.setResult(resultType);
+        if (resultType == ExecutionEvent.NORMAL_EXIT) {
+            event.setResultObject(result);
+            event.setObjectName(watcher.getResultName());
+        }
+        else if (resultType == ExecutionEvent.EXCEPTION_EXIT) {
+            event.setException(watcher.getException());
+        }
+        
+        BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, event);
+    }
+
+    /**
+     * Returns the result object name of an invocation
+     *
+     * @return    The resultName value
+     */
+    String getResultName()
+    {
+        return resultName;
+    }
+
+
+    /**
+     * Converts an array of Object into an array of String with java
+     * expressions representing the objects, as per the convOneObj method.
+     *
+     * @param  i_array  Input object values
+     * @return          Objects transformed into an array of strings
+     */
+    private String[] convObjToString(Object[] i_array)
+    {
+        if (i_array == null) {
+            return null;
+        }
+        if (i_array.length <= 0) {
+            return new String[0];
+        }
+
+        String[] o_array = new String[i_array.length];
+        for (int index = 0; index < i_array.length; index++) {
+            o_array[index] = convOneObj(i_array[index]);
+        }
+
+        return o_array;
+    }
+
+
+    /**
+     * Does one conversion of a supplied object to a java expression
+     * representing that object, according to the following rules:
+     * 
+     * <ul>
+     * <li>String - the String will be quoted according to Java quoting
+     *              rules, and enclosed in quotes
+     * <li>BObject - the name of the BObject on the object bench will be
+     *               returned 
+     * <li>Anything else - toString() is called on the object and the
+     *               result is treated as a Java expression, which is
+     *               returned.
+     * </ul>
+     *
+     * @param  i_obj  Input object to convert
+     * @return        The resulting string representation
+     */
+    private String convOneObj(Object i_obj)
+    {
+        if (i_obj == null) {
+            return null;
+        }
+        // A string should be quoted by a couple of "".
+        if (i_obj instanceof String) {
+            return "\"" + Utility.quoteString(i_obj.toString()) + "\"";
+        }
+        // An object reference is just the object instance name
+        if (i_obj instanceof BObject) {
+            return ((BObject) i_obj).getInstanceName();
+        }
+        // All the rest should be done by standard conversion...
+        return i_obj.toString();
+    }
+
+
+    /**
+     * Simple utility to decide when two params list do not match.
+     * The test is done on params length but not on the type.
+     *
+     * @param  params      The params given
+     * @param  paramClass  The reference params array
+     * @return             true if they match, false othervise
+     */
+    private boolean paramsAlmostMatch(Object[] params, Class<?>[] paramClass)
+    {
+        // A zero len param or a null one are the same !
+        if (params != null && params.length < 1) {
+            params = null;
+        }
+        if (paramClass != null && paramClass.length < 1) {
+            paramClass = null;
+        }
+
+        if (params == null && paramClass == null) {
+            return true;
+        }
+
+        // If ANY of them is null we are in trouble now. (They MUST be both NOT null)
+        if (params == null || paramClass == null) {
+            return false;
+        }
+
+        // Now I know that BOTH are NOT empty. They MUST be the same length
+        if (params.length != paramClass.length) {
+            return false;
+        }
+
+        // Yes, they are almost the same, the actual type is missing :-)
+        return true;
+    }
+
+
+
+    /**
+     * This is used to interface with the core BlueJ
+     * This new version does return when there is an INTERRUPT
+     */
+    class DirectResultWatcher implements ResultWatcher
+    {
+        private boolean resultReady;
+        private boolean isFailed;
+        private String resultType;
+
+        private DebuggerObject result;
+        private ExceptionDescription exception;
+        private String errorMsg;
+        // When there is a fail this is the reason.
+        private String resultName;
+
+
+        /**
+         * Constructor for the DirectResultWatcher object
+         */
+        public DirectResultWatcher()
+        {
+            resultReady = false;
+            isFailed = false;
+            result = null;
+            errorMsg = null;
+        }
+
+
+        /**
+         * This will try to get the result of an invocation.
+         * null can be returned if the thread is interrupted !!!
+         *
+         * @return    The result value
+         */
+        public synchronized DebuggerObject getResult()
+        {
+            while (!resultReady) {
+                try {
+                    wait();
+                }
+                catch (InterruptedException exc) {
+                    // This is correct, if someone wants to get me out of this I should
+                    // obey to the oreder !
+                    isFailed = true;
+                    errorMsg = "getResult: Interrupt: Exception=" + exc.getMessage();
+                    return null;
+                }
+            }
+
+            return result;
+        }
+
+
+        /**
+         * I need a way to reliably detect if there is an error or not.
+         * Careful... should I look for resultReady too ?
+         *
+         * @return    The failed value
+         */
+        public synchronized boolean isFailed()
+        {
+            return isFailed;
+        }
+
+        /*
+         * @see bluej.debugmgr.ResultWatcher#beginExecution()
+         */
+        public void beginCompile()
+        {
+            // Nothing needs doing.
+        }
+        
+        /*
+         * @see bluej.debugmgr.ResultWatcher#beginExecution()
+         */
+        public void beginExecution(InvokerRecord ir)
+        {
+            // Nothing needs doing.
+        }
+        
+        /**
+         * Used to return a result. We know that it is a good one.
+         *
+         * @param  aResult       The actual result object
+         * @param  anObjectName  The object name in the object bench
+         * @param  ir            Further parameter, see ResultWatcher
+         */
+        public synchronized void putResult(DebuggerObject aResult, String anObjectName, InvokerRecord ir)
+        {
+            result = aResult;
+            resultType = ExecutionEvent.NORMAL_EXIT;
+            resultName = anObjectName;
+            resultReady = true;
+            notifyAll();
+        }
+
+
+        /**
+         * This is used to return an error.
+         * @param  error  The error message
+         */
+        public synchronized void putError(String error, InvokerRecord ir)
+        {
+            errorMsg = "Invocation: Error=" + error;
+            isFailed = true;
+            resultReady = true;
+            notifyAll();
+        }
+        
+
+        /**
+         * Treat run-time error the same as compile-time error.
+         * @param  msg  The exception message
+         */
+        public synchronized void putException(ExceptionDescription exception, InvokerRecord ir)
+        {
+            this.exception = exception;
+            resultType = ExecutionEvent.EXCEPTION_EXIT;
+            putError(exception.getText(), ir);
+        }
+        
+        
+        /**
+         * Treat termination as an error
+         */
+        public void putVMTerminated(InvokerRecord ir)
+        {
+            resultType = ExecutionEvent.TERMINATED_EXIT;
+            putError("Terminated", ir);
+        }
+
+
+        /**
+         *  Gets the error attribute of the DirectResultWatcher object
+         *
+         * @return    The error value
+         */
+        public String getError()
+        {
+            return errorMsg;
+        }
+
+
+        /**
+         *  Gets the resultName attribute of the DirectResultWatcher object
+         *
+         * @return    The resultName value
+         */
+        public String getResultName()
+        {
+            return resultName;
+        }
+        
+        /**
+         * Returns the result type:<br>
+         * ExecutionEvent.NORMAL_EXIT if execution completed normally;<br>
+         * ExecutionEvent.EXCEPTION_EXIT if an exception occurred in user code;<br>
+         * ExecutionEvent.TERMINATED_EXIT if the user VM exited for any reason;<br>
+         * null if compilation failure occurred.
+         */
+        public String getResultType()
+        {
+            return resultType;
+        }
+        
+        /**
+         * Get the exception which occurred (if result type == EXCEPTION_EXIT).
+         */
+        public ExceptionDescription getException()
+        {
+            return exception;
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/Extension.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/Extension.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2a6ec7fea8bf3c110d7a4e27c855e095e0b8383
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/Extension.java
@@ -0,0 +1,125 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import java.net.URL;
+import bluej.Config;
+
+/**
+ * Defines the interface between BlueJ and an extension. All extensions must extend this class.
+ * A concrete extension class must also have a no-arguments constructor.
+ * 
+ * @author Clive Miller, University of Kent at Canterbury, 2002
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003,2004
+ */
+public abstract class Extension
+{
+    /* Version number variables -
+     * 
+     * Do not make them final otherwise the compiler can compile it into the extension.
+     * Do not make them static, to prevent an extension from messing with the value
+     * available to other extensions.
+     */
+    
+    /**
+     * The major version number of the Extension API.
+     * Provided so that extensions can check for compatibility.
+     */
+    public int VERSION_MAJOR = 2;
+
+    /**
+     * The minor version number of the Extension API.
+     * Provided so that extensions can check for compatibility.
+     */
+    public int VERSION_MINOR = 9;
+
+    /**
+     * Determine whether this extension is compatible with a particular version
+     * of the extensions API. This method is called before the startup() method.
+     * An extension can use VERSION_MAJOR and VERSION_MINOR as an aid to determine
+     * whether it is compatible with the current BlueJ release.
+     */
+    public abstract boolean isCompatible();
+
+    /**
+     * Called when the extension can start its activity.
+     * This is not called on a separate thread. Extensions should return as quick as 
+     * possible from this method after creating their own thread if necessary.
+     *
+     * @param  bluej  The starting point for interactions with BlueJ
+     */
+    public abstract void startup(BlueJ bluej);
+
+    /**
+     * Called when the extension should tidy up and terminate.
+     * When BlueJ decides that this extension is no longer needed it will call this 
+     * method before removing it from the system. Note that an extension may
+     * be reloaded after having been terminated.
+     *
+     * <p>Any attempt by an extension to call methods on its
+     * <code>BlueJ</code> object after this method has been called will
+     * result in an (unchecked) <code>ExtensionUnloadedException</code>
+     * being thrown by the <code>BlueJ</code> object.
+     */
+    public void terminate()
+    {
+    }
+
+    /**
+     * Should return a name for this extension. This will be displayed in the Help->Installed Extensions
+     * dialog.
+     * 
+     * <p>Please limit the name to between 5 and 10 characters, and bear in mind the possibility of name
+     * conflicts.
+     */
+    public abstract String getName();
+
+    /**
+     * Should return the version of the extension.
+     * Please limit the string to between 5 and 10 characters.
+     * This will be displayed in the Help->Installed Extensions dialog
+     */
+    public abstract String getVersion();
+
+    /**
+     * Should return a description of the extension's function.
+     * It should be a brief statement of the extension's purpose.
+     * This will be displayed in the Help->Installed Extensions dialog
+     */
+    public String getDescription()
+    {
+        return Config.getString("extensions.nodescription");
+    }
+
+    /**
+     * Should return a URL where more information about the extension is available.
+     * This will be displayed in the Help->Installed Extensions dialog.
+     * If no information is available then null may be returned.
+     * 
+     * <p>Ideally the information provided at the URL includes a complete manual, possible
+     * upgrades and configuration details.
+     */
+    public URL getURL()
+    {
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ExtensionBridge.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ExtensionBridge.java
new file mode 100644
index 0000000000000000000000000000000000000000..cb2d2e5f15ba8122c3f48a74cf86f5d21c11f27c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ExtensionBridge.java
@@ -0,0 +1,157 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import java.awt.Graphics2D;
+
+import javax.swing.JMenuItem;
+
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.extensions.BDependency.Type;
+import bluej.extensions.event.ExtensionEvent;
+import bluej.extmgr.ExtensionMenuObject;
+import bluej.extmgr.ExtensionPrefManager;
+import bluej.extmgr.ExtensionWrapper;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.graphPainter.ClassTargetPainter.Layer;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.DependentTarget;
+
+import com.sun.jdi.Value;
+
+
+/**
+ * This class acts as a bridge between the extensions package and other
+ * BlueJ-internal packages (extmgr) to provide access to methods which
+ * shouldn't be documented in the Extensions API Javadoc. By using this class,
+ * those methods can be made package-local.
+ *
+ * This class should be excluded when the Javadoc API documentation is generated.
+ */
+public final class ExtensionBridge
+{
+    public static void delegateEvent(BlueJ thisBluej, ExtensionEvent anEvent)
+    {
+        thisBluej.delegateEvent(anEvent);
+    }
+
+    public static Object getVal(PkgMgrFrame aFrame, String instanceName, Value val)
+    {
+        return BField.doGetVal(aFrame, instanceName, val);
+    }
+
+    public static BlueJ newBluej(ExtensionWrapper aWrapper,
+        ExtensionPrefManager aPrefManager) {
+        return new BlueJ(aWrapper, aPrefManager);
+    }
+
+    public static BObject newBObject(ObjectWrapper aWrapper) {
+        return new BObject(aWrapper);
+    }
+
+    public static BProject newBProject(Project bluejPrj) {
+        return new BProject(new Identifier(bluejPrj));
+    }
+
+    public static BPackage newBPackage(Package bluejPkg) {
+        return new BPackage(new Identifier(bluejPkg.getProject(), bluejPkg));
+    }
+
+    public static BClass newBClass(ClassTarget classTarget) {
+        Package bluejPkg = classTarget.getPackage();
+        Project bluejPrj = bluejPkg.getProject();
+
+        return new BClass(new Identifier(bluejPrj, bluejPkg,
+                classTarget.getQualifiedName()));
+    }
+
+    public static BClassTarget newBClassTarget(ClassTarget classTarget) {
+        Package bluejPackage = classTarget.getPackage();
+        Project bluejProject = bluejPackage.getProject();
+
+        return new BClassTarget(new Identifier(bluejProject, bluejPackage,
+                classTarget.getQualifiedName()));
+    }
+
+    public static BDependency newBDependency(Dependency dependency, Type type)
+    {
+        DependentTarget from = dependency.getFrom();
+        DependentTarget to = dependency.getTo();
+        Package bluejPackage = from.getPackage();
+        Project bluejProject = bluejPackage.getProject();
+        String qualifiedNameFrom = bluejPackage.getQualifiedName(from.getIdentifierName());
+        String qualifiedNameTo = bluejPackage.getQualifiedName(to.getIdentifierName());
+
+        return new BDependency(new Identifier(bluejProject, bluejPackage, qualifiedNameFrom),
+                new Identifier(bluejProject, bluejPackage, qualifiedNameTo), type);
+    }
+
+    public static void ChangeBClassName(BClass bClass, String newName)
+    {
+        bClass.nameChanged(newName);
+    }
+    
+    public static void changeBClassTargetName(BClassTarget bClassTarget, String newName)
+    {
+        bClassTarget.nameChanged(newName);
+    }
+
+    public static void changeBDependencyOriginName(BDependency bDependency, String newOriginName)
+    {
+        bDependency.originNameChanged(newOriginName);
+    }
+
+    public static void changeBDependencyTargetName(BDependency bDependency, String newTargetName)
+    {
+        bDependency.targetNameChanged(newTargetName);
+    }
+
+    public static JMenuItem getMenuItem(BlueJ aBluej, ExtensionMenuObject attachedObject)
+    {
+        return aBluej.getMenuItem(attachedObject);
+    }
+
+    public static void postMenuItem(BlueJ aBluej, ExtensionMenuObject attachedObject,
+        JMenuItem onThisItem)
+    {
+        aBluej.postMenuItem(attachedObject, onThisItem);
+    }
+    
+    public static boolean hasSourceCode(BClass bClass) throws ProjectNotOpenException, PackageNotFoundException
+    {
+        return bClass.hasSourceCode();
+    }
+
+    public static void clearObjectBench(BProject project) throws ProjectNotOpenException
+    {
+        project.clearObjectBench();
+    }
+
+    public static void drawExtensionClassTarget(BlueJ bluej, Layer layer,
+            BClassTarget bClassTarget, Graphics2D graphics, int width, int height)
+    {
+        bluej.drawExtensionClassTarget(layer, bClassTarget, graphics, width, height);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ExtensionException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ExtensionException.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a8ee010b29a93a29cab34d5add4ffbcef1ee98e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ExtensionException.java
@@ -0,0 +1,33 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+/**
+ * Base class for the different Exception event generated by BlueJ for extensions.
+ */
+public class ExtensionException extends Exception 
+{
+    ExtensionException ( String reason )
+    {
+        super (reason);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ExtensionUnloadedException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ExtensionUnloadedException.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f56f3d1f0a76770923176a89993e75af5da265b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ExtensionUnloadedException.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+/**
+ * This exception will be thrown when an Extension that has been unloaded
+ * from BlueJ still tries to access methods of the BlueJ class.
+ * If the Extension terminates its activities when the Extension.terminate() 
+ * method is called then this exception will never be thrown.
+ * 
+ * @version $Id: ExtensionUnloadedException.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+/*
+ * Author: Damiano Bolla, University of kent at Canterbury, 2003
+ */
+
+public class ExtensionUnloadedException extends RuntimeException 
+{
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/Identifier.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/Identifier.java
new file mode 100644
index 0000000000000000000000000000000000000000..d90f5309773506b56d6afeb5d4cf596aa82aff93
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/Identifier.java
@@ -0,0 +1,332 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+
+import java.awt.EventQueue;
+import java.io.File;
+
+import bluej.extensions.BDependency.Type;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.Target;
+import bluej.views.View;
+
+/**
+ * The problem I am trying to solve is to have a uniform and simple way to deal with
+ * objects validity. An extension may be holding BProject  but this BProject may not be valid
+ * since the gui has closed it. Or may be holding aBPackage and this not being valid
+ * The same apply to a BClass or a BOBject.
+ *
+ * To solve it I need to store the ID of the above objects and check if it is still valid
+ * before doing anything.
+ * Again, the problem is that for a BClass I need not only to check if the Class is valid
+ * but also the Project and the Package !
+ * So the ID if a BClass is really all of the above...
+ *
+ * Then, the solution is to put all that is needed in here and have this class only deal with
+ * checking the mess of it...
+ *
+ * NOTE on class Names: Most of the time we would like the qualified form of the class name
+ * however there are cases when we need the short form, it seems reasonable to store the
+ * long form and derive the short one.
+ *
+ * @author Damiano Bolla 2003,2004
+ */
+class Identifier
+{
+    private File projectId;
+    private String packageId;
+    private String qualifiedClassName;
+
+
+    /**
+     * Constructor for the Identifier object
+     */
+    Identifier(Project bluejProject)
+    {
+        this(bluejProject, null, null);
+    }
+
+
+    /**
+     * Constructor for the Identifier object
+     */
+    Identifier(Project bluejProject, Package bluejPackage)
+    {
+        this(bluejProject, bluejPackage, null);
+    }
+
+
+    /**
+     * Constructor for the Identifier object
+     */
+    Identifier(Project bluejProject, Package bluejPackage, String aQualifiedClassName)
+    {
+        projectId = bluejProject.getProjectDir();
+        if (bluejPackage != null) packageId = bluejPackage.getQualifiedName();
+        qualifiedClassName = aQualifiedClassName;
+    }
+
+
+    /**
+     * Returns the blueJProject and also checks its existence
+     */
+    Project getBluejProject() throws ProjectNotOpenException
+    {
+        Project aProject = Project.getProject(projectId);
+
+        if (aProject == null)
+            throw new ProjectNotOpenException("Project " + projectId + " is closed");
+
+        return aProject;
+    }
+
+
+    /**
+     * Returns the inner BlueJ package given the current identifier.
+     * @throws ProjectNotOpenException
+     * @throws PackageNotFoundException
+     */
+    Package getBluejPackage() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Project bluejProject = getBluejProject();
+
+        Package bluejPkg = bluejProject.getCachedPackage(packageId);
+        if (bluejPkg == null)
+            throw new PackageNotFoundException("Package '" + packageId + "' is deleted");
+
+        return bluejPkg;
+    }
+
+    /**
+     * Returns the name of the class. No checks are made for validity of 
+     * the name, to avoid having to compile the class in order to get 
+     * its name.
+     * This means that the name may not be valid, if the class has 
+     * been renamed or deleted.
+     * 
+     * @return    The qualified name of the class represented by this identifier,
+     *            or null if it doesn't represent a class
+     */
+    String getClassName()
+    {
+        return qualifiedClassName;
+    }
+
+    /**
+     * Returns the Frame associated with this Package.
+     * The nice thing about this one is that it WILL open a frame if it was not already open.
+     * This gets rid of one possible exception regarding a packageFrame not open...
+     *
+     * @return                               The packageFrame value
+     * @exception  ProjectNotOpenException
+     * @exception  PackageNotFoundException
+     */
+    PkgMgrFrame getPackageFrame()
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package thisPkg = getBluejPackage();
+
+        // Get a frame for the package.
+        final PkgMgrFrame pmf = PkgMgrFrame.createFrame(thisPkg);
+
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                // Check if it's already visible first, as calling
+                // setVisible(true) causes frame to grab focus on
+                // Windows
+                if(!pmf.isVisible()) {
+                    pmf.setVisible(true);
+                }
+            }
+        });
+        return pmf;
+    }
+
+    /**
+     * Returns the Java class that is associated with this name in this package
+     *
+     * @return      The java Class object
+     * 
+     * @exception  ProjectNotOpenException
+     * @exception  ClassNotFoundException
+     */
+    Class<?> getJavaClass() throws ProjectNotOpenException, ClassNotFoundException
+    {
+        Project bluejPrj = getBluejProject();
+
+        Class<?> aClass = bluejPrj.loadClass(qualifiedClassName);
+        if (aClass == null)
+            throw new ClassNotFoundException("Class " + qualifiedClassName + " Not Found");
+
+        return aClass;
+    }
+
+
+    /**
+     * Returns the class target of this java class by checking its existence
+     *
+     * @return      The classTarget value
+     * 
+     * @exception  ProjectNotOpenException
+     * @exception  PackageNotFoundException
+     */
+    ClassTarget getClassTarget()
+             throws ProjectNotOpenException, PackageNotFoundException
+    {
+        Package bluejPkg = getBluejPackage();
+
+        String className = qualifiedClassName;
+        int dotpos = qualifiedClassName.lastIndexOf(".");
+        if (dotpos > 0) {
+            className = qualifiedClassName.substring(dotpos + 1);
+        }
+        
+        Target aTarget = bluejPkg.getTarget(className);
+
+        if (aTarget == null) {
+            return null;
+        }
+
+        if (!(aTarget instanceof ClassTarget)) {
+            return null;
+        }
+
+        return (ClassTarget) aTarget;
+    }
+
+    /**
+     * Returns the {@link Dependency} with the origin represented by this
+     * {@link Identifier} and the target represented by the specified
+     * {@link Identifier}.
+     * 
+     * @param targetId
+     *            The {@link Identifier} representing the target of the
+     *            dependency.
+     * @param type
+     *            The type of the dependency (there may be more than one
+     *            dependencies with the same origin and target but different
+     *            types).
+     * @return The {@link Dependency} with the origin represented by this
+     *         {@link Identifier} and the target represented by the specified
+     *         {@link Identifier} or <code>null</code> if there is no such
+     *         dependency.
+     * @throws ProjectNotOpenException
+     * @throws PackageNotFoundException
+     */
+    Dependency getDependency(Identifier targetId, Type type) throws ProjectNotOpenException,
+            PackageNotFoundException
+    {
+        ClassTarget origin = getClassTarget();
+        ClassTarget target = targetId.getClassTarget();
+
+        if ((origin != null) && (target != null)) {
+            Package bluejPackage = getBluejPackage();
+            return bluejPackage.getDependency(origin, target, type);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the view associated with this Class
+     *
+     * @return        The bluejView value
+     * @exception  ProjectNotOpenException
+     * @exception  ClassNotFoundException
+     */
+    View getBluejView()
+             throws ProjectNotOpenException, ClassNotFoundException
+    {
+        Class<?> aClass = getJavaClass();
+
+        // View.getView does not fail, if the class does not exist it will be created.
+        return View.getView(aClass);
+    }
+    
+    /*
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+        int total = 0;
+        if (projectId != null) {
+            total += projectId.hashCode();
+        }
+        if (packageId != null) {
+            total += packageId.hashCode();
+        }
+        if (qualifiedClassName != null) {
+            total += qualifiedClassName.hashCode();
+        }
+        return total;
+    }
+    
+    /*
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (! (obj instanceof Identifier)) {
+            return false;
+        }
+        
+        Identifier other = (Identifier) obj;
+        if (equalsIgnoreClass(other)
+                && !(qualifiedClassName != null ? qualifiedClassName.equals(other.qualifiedClassName)
+                : other.qualifiedClassName == null)) {
+            return false;
+        }
+        
+        return true;
+    }
+
+    /**
+     * Compares the given {@link Identifier} with this one, ignoring the
+     * represented class.
+     * 
+     * @param other
+     *            The {@link Identifier} to compare.
+     * @return <code>true</code> if the specified {@link Identifier} has the
+     *         same project and package as this one, <code>false</code>
+     *         otherwise.
+     */
+    boolean equalsIgnoreClass(Identifier other)
+    {
+        if (!(projectId != null ? projectId.equals(other.projectId) : other.projectId == null)) {
+            return false;
+        }
+
+        if (!(packageId != null ? packageId.equals(other.packageId) : other.packageId == null)) {
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/InvocationArgumentException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/InvocationArgumentException.java
new file mode 100644
index 0000000000000000000000000000000000000000..1596bebb2a97606935977f41dabb7684ac4ab865
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/InvocationArgumentException.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+/**
+ * This exception will be thrown when the parameters passed to an invocation
+ * do not match the list of arguments of the invocation.
+ * 
+ * @version $Id: InvocationArgumentException.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+/*
+ * Author: Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class InvocationArgumentException extends ExtensionException 
+{
+  InvocationArgumentException (String reason) {
+      super (reason);
+  }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/InvocationErrorException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/InvocationErrorException.java
new file mode 100644
index 0000000000000000000000000000000000000000..b96f0987c23b79b2f1777397bf9263ecd5027a15
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/InvocationErrorException.java
@@ -0,0 +1,40 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+/**
+ * This exception will be thrown when an exception occurs during a method or constructor 
+ * invocation. The most likely cause of this exception is the user cancelling a 
+ * long-running object construction or method invocation from the GUI.
+ * 
+ * @version $Id: InvocationErrorException.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+/*
+ * Author: Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class InvocationErrorException extends ExtensionException 
+{
+  InvocationErrorException (String reason) {
+      super (reason);
+  }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/MenuGenerator.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/MenuGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..29f50b4535a9c537866f3dff398dacf4f71485b6
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/MenuGenerator.java
@@ -0,0 +1,282 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import javax.swing.JMenuItem;
+
+/**
+ * Extensions which wish to add a menu item to BlueJ's menus should register an
+ * instance of MenuGenerator with the BlueJ proxy object.  
+ * <p>
+ * A MenuGenerator provides a set of functions which can be called back
+ * by BlueJ to request the actual menu items which will be displayed, and
+ * to indicate that a particular menu item is about to be displayed, so
+ * that an extension can (e.g.) enable or disable appropriate items.
+ * <p>
+ * Note that the JMenuItem which is returned by the extension can itself
+ * be a JMenu, allowing extensions to build more complex menu structures, but
+ * that the "notify" methods below will only be called for the item which has
+ * actually been added, and not any subsidiary items.
+ * <p>
+ * Below is a simple example which creates menus for Tools, Classes and Objects. 
+ * <p>
+ * To activate the menus you instantiate an object of the MenuGenerator class
+ * and then register it with the BlueJ proxy object, e.g.:
+ * <pre>
+ *        MenuBuilder myMenus = new MenuBuilder();
+ *        bluej.setMenuGenerator(myMenus);
+ * </pre>
+ * Note that the MenuGenerator's <code>get*MenuItem()</code> methods:<ol>
+ * <li>may be called more than 
+ * once during a BlueJ session, they should return a new set of MenuItems for each 
+ * invocation. This is a restriction required by the Swing implementation, which 
+ * does not allow sharing of MenuItems between menus. You can, of course, share 
+ * MenuActions between all of the appropriate MenuItems.
+ * <li>may not be called between the registration of a new <code>MenuGenerator</code>
+ * and the display of a menu. That is to say old menu items may still be active for previously
+ * registered menus, despite the registration of a new <code>MenuGenerator</code>.
+ * <li>will be called at least once for every menu which is displayed.
+ * </ol>
+ *
+ * The code for the example MenuBuilder class is:
+ * <PRE>
+ * import bluej.extensions.*;
+ * import javax.swing.*;
+ * import java.awt.event.*;
+ *
+ * class MenuBuilder extends MenuGenerator {
+ *     private BPackage curPackage;
+ *     private BClass curClass;
+ *     private BObject curObject;
+ * 
+ *     public JMenuItem getToolsMenuItem(BPackage aPackage) {
+ *         return new JMenuItem(new SimpleAction("Click Tools", "Tools menu:"));
+ *     }
+ * 
+ *     public JMenuItem getClassMenuItem(BClass aClass) {
+ *         return new JMenuItem(new SimpleAction("Click Class", "Class menu:"));
+ *     }
+ * 
+ *     public JMenuItem getObjectMenuItem(BObject anObject) {
+ *         return new JMenuItem(new SimpleAction("Click Object", "Object menu:"));
+ *     }
+ *     
+ *     // These methods will be called when
+ *     // each of the different menus are about to be invoked.
+ *     public void notifyPostToolsMenu(BPackage bp, JMenuItem jmi) {
+ *         System.out.println("Post on Tools menu");
+ *         curPackage = bp ; curClass = null ; curObject = null;
+ *     }
+ *     
+ *     public void notifyPostClassMenu(BClass bc, JMenuItem jmi) {
+ *         System.out.println("Post on Class menu");
+ *         curPackage = null ; curClass = bc ; curObject = null;
+ *     }
+ *     
+ *     public void notifyPostObjectMenu(BObject bo, JMenuItem jmi) {
+ *         System.out.println("Post on Object menu");
+ *         curPackage = null ; curClass = null ; curObject = bo;
+ *     }
+ *     
+ *     // A utility method which pops up a dialog detailing the objects 
+ *     // involved in the current (SimpleAction) menu invocation.
+ *     private void showCurrentStatus(String header) {
+ *         try {
+ *             if (curObject != null)
+ *                 curClass = curObject.getBClass();
+ *             if (curClass != null)
+ *                 curPackage = curClass.getPackage();
+ *                 
+ *             String msg = header;
+ *             if (curPackage != null)
+ *                 msg += "\nCurrent Package = " + curPackage;
+ *             if (curClass != null)
+ *                 msg += "\nCurrent Class = " + curClass;
+ *             if (curObject != null)
+ *                 msg += "\nCurrent Object = " + curObject;
+ *             JOptionPane.showMessageDialog(null, msg);
+ *         } catch (Exception exc) { }
+ *     }
+ *     
+ *     // The nested class that instantiates the different (simple) menus.
+ *     class SimpleAction extends AbstractAction {
+ *         private String msgHeader;
+ *         
+ *         public SimpleAction(String menuName, String msg) {
+ *             putValue(AbstractAction.NAME, menuName);
+ *             msgHeader = msg;
+ *         }
+ *         public void actionPerformed(ActionEvent anEvent) {
+ *             showCurrentStatus(msgHeader);
+ *         }
+ *     }
+ * }
+ * </PRE>
+ *
+ * @author Damiano Bolla, University of Kent at Canterbury. January 2003
+ */
+public class MenuGenerator
+{
+    /**
+     * Returns the JMenuItem to be added to the BlueJ Tools menu.
+     * Extensions should not retain references to the menu items created.
+     * @deprecated As of BlueJ 1.3.5, replaced by {@link #getToolsMenuItem(BPackage bp)}
+     */
+    public JMenuItem getMenuItem( )
+    {
+        return null;
+    }
+
+    /**
+     * Returns the JMenuItem to be added to the BlueJ Tools menu.
+     * Extensions should not retain references to the menu items created.
+     * @param bp the BlueJ package with which this menu item will be associated.
+     */
+    public JMenuItem getToolsMenuItem(BPackage bp)
+    {
+        return null;
+    }
+
+    /**
+     * Returns the JMenuItem to be added to the BlueJ View menu. Extensions
+     * should not retain references to the menu items created.
+     * 
+     * @param bPackage
+     *            The BlueJ package with which this menu item will be
+     *            associated.
+     * @return The JMenuItem to be added to the BlueJ View menu.
+     */
+    public JMenuItem getViewMenuItem(BPackage bPackage)
+    {
+        return null;
+    }
+
+    /**
+     * Returns the JMenuItem to be added to the BlueJ Package menu. Extensions
+     * should not retain references to the menu items created.
+     * 
+     * @param bPackage
+     *            The BlueJ package with which this menu item will be
+     *            associated.
+     * @return The JMenuItem to be added to the BlueJ Package menu.
+     */
+    public JMenuItem getPackageMenuItem(BPackage bPackage)
+    {
+        return null;
+    }
+  
+    /**
+     * Returns the JMenuItem to be added to the BlueJ Class menu
+     * Extensions should not retain references to the menu items created.
+     * @param bc the BlueJ class with which this menu item will be associated.
+     */
+    public JMenuItem getClassMenuItem(BClass bc)
+    {
+        return null;
+    }
+
+    /**
+     * Returns the JMenuItem to be added to the BlueJ Object menu.
+     * Extensions should not retain references to the menu items created.
+     * @param bo the BlueJ object with which this menu item will be associated.
+     */
+    public JMenuItem getObjectMenuItem(BObject bo)
+    {
+        return null;
+    }
+
+    /**
+     * Called by BlueJ when a tools menu added by an extension is about to
+     * be displayed. An extension can use this notification to decide whether
+     * to enable/disable menu items and so on. <em>Note:</em> Due to a bug in
+     * Apple's current Java implementation, this method will not be called when
+     * is running on a Mac. It will start working as soon as there's a fix.
+     * @param bp the BlueJ package for which the menu is to be displayed
+     * @param jmi the menu item which will be displayed (as provided by the
+     * extension in a previous call to getToolsMenuItem)
+     */
+    public void notifyPostToolsMenu(BPackage bp, JMenuItem jmi) 
+    {
+        return;
+    }
+
+    /**
+     * Called by BlueJ when a view menu added by an extension is about to be
+     * displayed. An extension can use this notification to decide whether to
+     * enable/disable menu items and so on.
+     * 
+     * @param bPackage
+     *            The BlueJ package for which the menu is to be displayed.
+     * @param menuItem
+     *            The menu item which will be displayed (as provided by the
+     *            extension in a previous call to
+     *            {@link #getViewMenuItem(BPackage)}).
+     */
+    public void notifyPostViewMenu(BPackage bPackage, JMenuItem menuItem)
+    {
+        return;
+    }
+
+    /**
+     * Called by BlueJ when a package menu added by an extension is about to be
+     * displayed. An extension can use this notification to decide whether to
+     * enable/disable menu items and so on.
+     * 
+     * @param bPackage
+     *            The BlueJ package for which the menu is to be displayed.
+     * @param menuItem
+     *            The menu item which will be displayed (as provided by the
+     *            extension in a previous call to
+     *            {@link #getPackageMenuItem(BPackage)}).
+     */
+    public void notifyPostPackageMenu(BPackage bPackage, JMenuItem menuItem)
+    {
+        return;
+    }
+
+    /**
+     * Called by BlueJ when a class menu added by an extension is about to
+     * be displayed. An extension can use this notification to decide whether
+     * to enable/disable menu items and so on.
+     * @param bc the BlueJ class for which the menu is to be displayed
+     * @param jmi the menu item which will be displayed (as provided by the
+     * extension in a previous call to getToolsMenuItem)
+     */
+    public void notifyPostClassMenu(BClass bc, JMenuItem jmi) 
+    {
+        return;
+    }
+
+    /**
+     * Called by BlueJ when an object menu added by an extension is about to
+     * be displayed. An extension can use this notification to decide whether
+     * to enable/disable menu items and so on.
+     * @param bo the BlueJ object for which the menu is to be displayed
+     * @param jmi the menu item which will be displayed (as provided by the
+     * extension in a previous call to getToolsMenuItem)
+     */
+    public void notifyPostObjectMenu(BObject bo, JMenuItem jmi) 
+    {
+        return;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/MissingJavaFileException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/MissingJavaFileException.java
new file mode 100644
index 0000000000000000000000000000000000000000..d37bbf02458e57d57df1b5f26fb2519a8445490f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/MissingJavaFileException.java
@@ -0,0 +1,38 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+/**
+ * This exception will be thrown when a new class is created and not java source file is provided.
+ * 
+ * @version $Id: MissingJavaFileException.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+/*
+ * Author: Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class MissingJavaFileException extends ExtensionException 
+{
+  MissingJavaFileException (String reason) {
+      super (reason);
+  }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/PackageAlreadyExistsException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/PackageAlreadyExistsException.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a9855e010710eb5f3c7deb7d24969e1d7871305
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/PackageAlreadyExistsException.java
@@ -0,0 +1,40 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+/**
+ * This exception is thrown when there is a request to create a new Package
+ * but the package already exists in BlueJ.
+ * 
+ * @version $Id: PackageAlreadyExistsException.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+/*
+ * Author: Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class PackageAlreadyExistsException extends ExtensionException 
+{
+    PackageAlreadyExistsException (String reason) {
+        super (reason);
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/PackageNotFoundException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/PackageNotFoundException.java
new file mode 100644
index 0000000000000000000000000000000000000000..602e72cd96b5b0a50731bc6a83044d4f02a4c328
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/PackageNotFoundException.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+
+/**
+ * This exception will be thrown when a reference to a package
+ * is no longer valid. The most likely reason is that the 
+ * user has deleted the package from the GUI.
+ * 
+ * @version $Id: PackageNotFoundException.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+/*
+ * Author: Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class PackageNotFoundException extends ExtensionException 
+{
+    PackageNotFoundException (String reason) {
+        super (reason);
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/PreferenceGenerator.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/PreferenceGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..df204f1b9555148fc66f35e92392698aec4758d9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/PreferenceGenerator.java
@@ -0,0 +1,108 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+import javax.swing.JPanel;
+
+/**
+ * Extensions which wish to add preference items to BlueJ's Tools/Preferences/Extensions 
+ * panel should register an instance of PreferenceGenerator with the BlueJ proxy object.
+ *
+ * The PreferenceGenerator allows the creation of a Panel to contain
+ * preference data, and the loading and saving of that data.
+ *
+ * Below is a simple example to create a preference panel with a single
+ * text item to record a user's favourite colour.
+ *
+ * To activate the preference panel you instantiate an object of the Preferences class
+ * and then register it with the BlueJ proxy object, e.g.:
+ * <pre>
+ *        Preferences myPreferences = new Preferences(bluej);
+ *        bluej.setPreferenceGenerator(myPreferences);
+ * </pre>
+ * The code for the Preferences class is:
+ * <PRE>
+ * public class Preferences implements PreferenceGenerator
+ * {
+ * private JPanel myPanel;
+ * private JTextField color;
+ * private BlueJ bluej;
+ * public static final String PROFILE_LABEL="Favourite-Colour";
+ *
+ * public Preferences(BlueJ bluej) {
+ *   this.bluej = bluej;
+ *   myPanel = new JPanel();
+ *   myPanel.add (new JLabel ("Favourite Colour"));
+ *   color = new JTextField (40);
+ *   myPanel.add (color);
+ *   // Load the default value
+ *   loadValues();
+ *   }
+ *
+ * public JPanel getPanel ()  { return myPanel; }
+ *
+ * public void saveValues () {
+ *   // Save the preference value in the BlueJ properties file
+ *   bluej.setExtensionPropertyString(PROFILE_LABEL, color.getText());
+ *   }
+ *
+ * public void loadValues () {
+ *   // Load the property value from the BlueJ proerties file, default to an empty string
+ *   color.setText(bluej.getExtensionPropertyString(PROFILE_LABEL,""));
+ *   }
+ * }
+ * </pre>
+ *
+ * @version $Id: PreferenceGenerator.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+/*
+ * AUthor Damiano Bolla, University of Kent at Canterbuty, January 2003
+ */
+ 
+public interface PreferenceGenerator
+{
+    /**
+     * Bluej will call this method to get the panel where preferences for this
+     * extension are. Preferences can be laid out as desired.
+     *
+     * @return    The JPanel to contain preference data.
+     */
+    public JPanel getPanel();
+
+
+    /**
+     * When this method is called the Extension should load its current values into
+     * its preference panel.
+     * This is called from a swing thread, so be quick.
+     */
+    public void loadValues();
+
+
+    /**
+     * When this method is called the Extension should save values from the preference panel into 
+     * its internal state. Value checking can be performed at this point.
+     * This is called from a swing thread, so be quick.
+     */
+    public void saveValues();
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ProjectNotOpenException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ProjectNotOpenException.java
new file mode 100644
index 0000000000000000000000000000000000000000..07646859ee65e7399ad8903bb64edae360a62ed0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/ProjectNotOpenException.java
@@ -0,0 +1,36 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions;
+
+/**
+ * This exception will be thrown when a reference to a project
+ * is no longer valid. The most likely reason is that the 
+ * user has closed the project from the GUI.
+ * 
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class ProjectNotOpenException extends ExtensionException 
+{
+    ProjectNotOpenException (String reason) {
+        super (reason);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/editor/Editor.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/editor/Editor.java
new file mode 100644
index 0000000000000000000000000000000000000000..00edfd0f80e9ba1d0c6be116f4b067750f4c3b42
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/editor/Editor.java
@@ -0,0 +1,356 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.editor;
+
+import java.io.IOException;
+
+import javax.swing.text.BadLocationException;
+
+import bluej.parser.SourceLocation;
+
+/**
+ * Proxy object that allows interaction with the BlueJ Editor for a
+ * particular class.
+ * Except as marked, methods of this class must be called from a swing compatible thread.
+ *
+ * @author Damiano Bolla, University of Kent at Canterbury, 2004
+ * @version    $Id: Editor.java 7337 2010-04-14 14:52:24Z nccb $
+ */
+
+public class Editor
+{
+    private bluej.editor.Editor bjEditor;
+
+
+    /**
+     * Constructor must not be public.
+     * You get an Editor object by calling BClass.getEditor(), which
+     * will create a (non-visible) editor if one does not already exist.
+     *
+     * @param  bjEditor  Description of the Parameter
+     */
+    Editor(bluej.editor.Editor bjEditor)
+    {
+        this.bjEditor = bjEditor;
+    }
+    
+    bluej.editor.Editor getEditor()
+    {
+        return bjEditor;
+    }
+
+
+    /**
+     * Request the editor to save the file currently opened.
+     */
+    public void saveFile()
+    {
+        try {
+            bjEditor.save();
+        }
+        catch (IOException ioe) {}
+    }
+
+    /**
+     * Request the editor to load the file currently opened.
+     */
+    public void loadFile()
+    {
+        bjEditor.reloadFile();
+    }
+
+
+    /**
+     * Show or hide this Editor.
+     *
+     * @param  visible  If true, make this editor visible
+     */
+    public void setVisible(boolean visible)
+    {
+        bjEditor.setVisible(visible);
+    }
+
+
+    /**
+     * Is this Editor currently visible?
+     *
+     * @return    true if the Editor is visible, false otherwise.
+     */
+    public boolean isVisible()
+    {
+        return bjEditor.isShowing();
+    }
+
+
+    /**
+     * Returns the current caret location (the position of the user's cursor) within the edited text.
+     *
+     * @return    the textLocation.
+     */
+    public TextLocation getCaretLocation()
+    {
+        return convertLocation(bjEditor.getCaretLocation());
+    }
+
+
+    /**
+     * Sets the current caret location within the edited text.
+     *
+     * @param  location                   The location in the text to set the Caret to.
+     * @throws  IllegalArgumentException  if the specified TextLocation represents a position which does not exist in the text.
+     */
+    public void setCaretLocation(TextLocation location)
+    {
+        bjEditor.setCaretLocation(convertLocation(location));
+    }
+
+
+    /**
+     * Request the editor to display the given message in the editor message area.
+     * The message will be cleared using BlueJ's usual rules.
+     *
+     * @param  message  The message to display.
+     */
+    public void showMessage(String message)
+    {
+        bjEditor.writeMessage(message);
+    }
+
+
+    /**
+     * Returns the location at which current selection begins.
+     *
+     * @return    the current beginning of the selection or null if no text is selected.
+     */
+    public TextLocation getSelectionBegin()
+    {
+        return convertLocation(bjEditor.getSelectionBegin());
+    }
+
+
+    /**
+     * Returns the location at which the current selection ends.
+     *
+     * @return    the current end of the selection or null if no text is selected
+     */
+    public TextLocation getSelectionEnd()
+    {
+        return convertLocation(bjEditor.getSelectionEnd());
+    }
+
+
+    /**
+     * Returns the text which lies between the two TextLocations.
+     *
+     * @param  begin                      The beginning of the text to get
+     * @param  end                        The end of the text to get
+     * @return                            The text value
+     * @throws  IllegalArgumentException  if either of the specified TextLocations represent a position which does not exist in the text.
+     */
+    public String getText(TextLocation begin, TextLocation end)
+    {
+        return bjEditor.getText(convertLocation(begin), convertLocation(end));
+    }
+
+
+    /**
+     * Request the editor to replace the text between beginning and end with the given newText
+     * If begin and end refer to the same location, the text is inserted.
+     *
+     * @param  begin                      where to start to replace
+     * @param  end                        where to end to replace
+     * @param  newText                    The new text value
+     * @throws  IllegalArgumentException  if either of the specified TextLocations
+     * represent a position which does not exist in the text.
+     */
+    public void setText(TextLocation begin, TextLocation end, String newText)
+    {
+        try {
+            bjEditor.setText(convertLocation(begin), convertLocation(end), newText);
+        }
+        catch (BadLocationException exc) {
+            throw new IllegalArgumentException(exc.getMessage());
+        }
+    }
+
+
+    /**
+     * Request the editor to mark the text between begin and end as selected.
+     *
+     * @param  begin                      where to start the selection
+     * @param  end                        where to end the selection
+     * @throws  IllegalArgumentException  if either of the specified TextLocations
+     * represent a position which does not exist in the text.
+     */
+    public void setSelection(TextLocation begin, TextLocation end)
+    {
+        bjEditor.setSelection(convertLocation(begin), convertLocation(end));
+    }
+
+
+    /**
+     * Request the editor to permit or deny editor content modification (via the editor GUI).
+     * Extensions should set readOnly to true before changing the editor content programmatically.
+     *
+     * @param  readOnly  If true user cannot change the editor content using the GUI, false allows user interaction.
+     */
+    public void setReadOnly(boolean readOnly)
+    {
+        bjEditor.setReadOnly(readOnly);
+    }
+
+
+    /**
+     * Is the editor currently set to readOnly?.
+     *
+     * @return    true if the user cannot change the text using the GUI, false othervise
+     */
+    public boolean isReadOnly()
+    {
+        return bjEditor.isReadOnly();
+    }
+
+
+    /**
+     * Returns a property of the current editor.
+     * This allows custom versions of the editor to communicate with extensions.
+     *
+     * @param  propertyKey  The propertyKey of the property to retrieve.
+     * @return              the property value or null if it is not found
+     */
+    public Object getProperty(String propertyKey)
+    {
+        return bjEditor.getProperty(propertyKey);
+    }
+
+
+    /**
+     * Set a property for the current editor. Any existing property with
+     * this key will be overwritten.
+     *
+     * @param  propertyKey  The property key of the new property
+     * @param  value        The new property value
+     */
+    public void setProperty(String propertyKey, Object value)
+    {
+        bjEditor.setProperty(propertyKey,value);
+    }
+
+
+    /**
+     * Translates a text location into an offset into the text held by the editor.
+     *
+     * @param  location                   position to be translated
+     * @return                            the offset into the text of this location
+     * @throws  IllegalArgumentException  if the specified TextLocation
+     * represent a position which does not exist in the text.
+     */
+    public int getOffsetFromTextLocation(TextLocation location)
+    {
+        return bjEditor.getOffsetFromLineColumn(convertLocation(location));
+    }
+
+
+    /**
+     * Translate an offset in the text held by the editor into a TextLocation.
+     *
+     * @param  offset  location to be translated
+     * @return         the TextLocation in the text of this offset or null if the offset is invalid
+     */
+    public TextLocation getTextLocationFromOffset(int offset)
+    {
+        return convertLocation(bjEditor.getLineColumnFromOffset(offset));
+    }
+
+
+    /**
+     * Returns the length of the line indicated in the edited text.
+     *
+     * @param  line  the line in the text for which the length should be calculated, starting from zero.
+     * @return       the length of the line, -1 if line is invalid
+     */
+    public int getLineLength(int line)
+    {
+        return bjEditor.getLineLength(line);
+    }
+
+
+    /**
+     * Returns the total number of lines in the currently edited text.
+     *
+     * @return    The number of lines in the text >= 0
+     */
+    public int getLineCount()
+    {
+        return bjEditor.numberOfLines();
+    }
+
+
+    /**
+     * Returns the length of the currently edited text.  This is the number of
+     * characters of content that represents the user's data.
+     *
+     * The line number and column of the last character of text can be obtained by using
+     * the getLineColumnFromOffset(getTextLength()) method.
+     *
+     * @return the length >= 0
+     */
+    public int getTextLength ()
+    {
+        return bjEditor.getTextLength();
+    }
+
+    /**
+     * Utility to convert a TextLocation into a LineColumn.
+     * If null is given as parameter then null is returned.
+     *
+     * @param  location  The point in the editor to convert to a LineColumn.
+     * @return           The LineColumn object describing a point in the editor.
+     */
+    private SourceLocation convertLocation(TextLocation location)
+    {
+        if (location == null) {
+            return null;
+        }
+
+        return new SourceLocation(location.getLine() + 1, location.getColumn() + 1);
+    }
+
+
+    /**
+     * Utility to convert a LineColumn into a TextLocation.
+     * If null is given as parameter then null is returned.
+     * 
+     * @param  location  The point in the editor to convert to a TextLocation.
+     * @return           The TextLocation object describing a point in the editor.
+     */
+    private TextLocation convertLocation(SourceLocation location)
+    {
+        if (location == null) {
+            return null;
+        }
+
+        return new TextLocation(location.getLine() - 1, location.getColumn() - 1);
+    }
+
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/editor/EditorBridge.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/editor/EditorBridge.java
new file mode 100644
index 0000000000000000000000000000000000000000..510f6a55115dfdbb468bd7c9db6816cb913d34c0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/editor/EditorBridge.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.editor;
+
+import bluej.pkgmgr.target.*;
+
+/**
+ * This class acts as a bridge between the extensions.editor classes
+ * and BlueJ-internal to provide access to methods which
+ * shouldn't be documented in the Extensions API Javadoc. By using this class,
+ * those methods can be made package-local.
+ *
+ * This class should be excluded when the Javadoc API documentation is generated.
+ *
+ * @version $Id: EditorBridge.java 7337 2010-04-14 14:52:24Z nccb $
+ * @author Damiano Bolla, University of Kent at Canterbury, 2004
+ */ 
+public class EditorBridge
+{
+    /**
+     *  Returns a new Editor for the given ClassTarget.
+     *
+     * @param  aTarget  Bluej Class Target to retrieve the editor from
+     * @return          Proxy editor object or null if it cannot be created
+     */
+    public static Editor newEditor(ClassTarget aTarget)
+    {
+        bluej.editor.Editor bjEditor = aTarget.getEditor();
+        if (bjEditor == null) 
+            return null;
+        return new Editor(bjEditor);
+    }
+    
+    public static bluej.editor.Editor getEditor(Editor editor)
+    {
+        return editor.getEditor();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/editor/TextLocation.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/editor/TextLocation.java
new file mode 100644
index 0000000000000000000000000000000000000000..14655e659b6925e04b790d254d21ece20342044b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/editor/TextLocation.java
@@ -0,0 +1,125 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.editor;
+
+/**
+ * A TextLocation object groups two pieces of information: a line number and a column number.
+ * They represent a position in the editor's text.
+ * A text location represents the gap to the left of the position identified, so
+ * that (0, 0) is the start of the file, (0, 1) is between the first and
+ * second characters in the file, and so on. There is a TextLocation position to
+ * the right of the last character on a line. The column value of this
+ * position can be determined using Editor.getLineLength(int line).
+ *
+ * When applied to a particular edited text, a TextLocation may be <em>invalid</em>. 
+ * That is, at the time of use, it points to an area outside the text being edited.
+ * 
+ * @version $Id: TextLocation.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+/*
+ * @author Damiano Bolla, University of Kent at Canterbury, 2004
+ */  
+public class TextLocation
+{
+    private int line,column;
+    
+    /**
+     * Create a TextLocation representing the text position at the specified line and column
+     *
+     * @param  line    a line number starting from 0
+     * @param  column  a column number starting from 0
+     */
+    public TextLocation(int line, int column)
+    {
+        this.line = line;
+        this.column = column;
+    }
+
+
+    /**
+     * Sets the line number of this text position, leaving the column unchanged.
+     *
+     * @param  line  the line number starting from zero
+     */
+    public void setLine(int line)
+    {
+        this.line = line;
+    }
+
+
+    /**
+     * Returns the line of this text position
+     *
+     * @return    the line number of this text position
+     */
+    public int getLine()
+    {
+        return line;
+    }
+
+
+    /**
+     * Sets the column of this text position, leaving the line number unchanged.
+     *
+     * @param  column  the column number starting from zero
+     */
+    public void setColumn(int column)
+    {
+        this.column = column;
+    }
+
+
+    /**
+     * Returns the column of this text location
+     *
+     * @return    the column number of this text location
+     */
+    public int getColumn()
+    {
+        return column;
+    }
+
+
+    /**
+     * Set both the line number and column of this text location
+     *
+     * @param  line    a line number starting from zero
+     * @param  column  a column number starting from zero
+     */
+    public void setPosition(int line, int column)
+    {
+        this.line = line;
+        this.column = column;    
+    }
+    
+    /**
+     * Returns a string representation of this text location.
+     *
+     * @return a string that represents this object status
+     */
+    public String toString ()
+    {
+        return "line="+line+" column="+column;
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ApplicationEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ApplicationEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7251afcf85815bc138a77e2b1b1f453d7a9506f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ApplicationEvent.java
@@ -0,0 +1,69 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * This class encapsulates BlueJ application events.
+ * 
+ * @version $Id: ApplicationEvent.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+ /*
+  * Author Damiano Bolla, University of Kent at Canterbury, January 2003
+  */
+
+public class ApplicationEvent implements ExtensionEvent 
+  {
+  /**
+   * Event generated when the BlueJ application is initialised and ready.
+   */
+  public static final int APP_READY_EVENT=1;
+
+  private int eventId;
+
+  /**
+   * Constructs an ApplicationEvent
+   */
+  public ApplicationEvent(int anEventId)
+    {
+    eventId = anEventId;
+    }
+
+  /**
+   * Returns the event type, one of the values defined.
+   */
+  public int getEvent ()
+    {
+    return eventId;
+    }
+
+
+  /**
+   * Returns a meaningful description of this event.
+   */
+  public String toString()
+    {
+    if ( eventId == APP_READY_EVENT ) return "AppEvent: APP_READY_EVENT";
+
+    return "AppEvent: UNKNOWN eventId="+eventId;
+    }
+  }
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ApplicationListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ApplicationListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..59ab976d760fbbe288fb9baf91dedccc5ba0e39d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ApplicationListener.java
@@ -0,0 +1,40 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * This interface allows you to listen for application events.
+ *
+ * @version $Id: ApplicationListener.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface ApplicationListener
+{
+    /**
+     * This method will be called when the BlueJ application is initialised.
+     * Warning: If you load an extension with a Project you will not get this event since
+     * BlueJ has already completed its initialisation when the project is loaded.
+     * Note that this method is called from a Swing-like dispatcher and therefore you must
+     * return as quickly as possible. 
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void blueJReady (ApplicationEvent event);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..d0a44bdf021e9a7774d1e83597a7c3acb31cc708
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassEvent.java
@@ -0,0 +1,122 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+import bluej.extensions.BClass;
+import bluej.extensions.BPackage;
+import bluej.pkgmgr.Package;
+
+/**
+ * This class encapsulates events which occur on BlueJ classes.<p>
+ * 
+ * The following events can occur:<p>
+ * 
+ * STATE_CHANGED: The compile state changed (either from uncompiled to compiled,
+ *                or from compiled to uncompiled)<p>
+ * CHANGED_NAME:  The class has changed name.<p>
+ * REMOVED:       The class has been removed.
+ * 
+ * 
+ * @author Davin McCall
+ */
+public class ClassEvent implements ExtensionEvent
+{
+    public static final int STATE_CHANGED = 0;
+    public static final int CHANGED_NAME = 1;
+    public static final int REMOVED = 2;
+    
+    private int eventId;
+    private Package bluejPackage;
+    private BClass bClass;
+    private boolean isCompiled;
+    private String oldName;
+    
+    /**
+     * Construct a new ClassEvent object for a STATE_CHANGED event.
+     * @param eventId    The event identifier (STATE_CHANGED)
+     * @param isCompiled  Whether the class is compiled or not
+     */
+    public ClassEvent(int eventId, Package bluejPackage, BClass bClass, boolean isCompiled)
+    {
+        this.eventId = eventId;
+        this.bluejPackage = bluejPackage;
+        this.isCompiled = isCompiled;
+        this.bClass = bClass;
+    }
+    
+    /**
+     * Construct a new ClassEvent object for a CHANGED_NAME event.
+     * @param eventId  The event identifier (CHANGED_NAME)
+     * @param bClass   The class which was renamed (refers to the new name)
+     */
+    public ClassEvent(int eventId, Package bluejPackage, BClass bClass, String oldName)
+    {
+        this.eventId = eventId;
+        this.bluejPackage = bluejPackage;
+        this.bClass = bClass;
+        this.oldName = oldName;
+    }
+    
+    /**
+     * Get the event Id (one of STATE_CHANGED, CHANGED_NAME).
+     */
+    public int getEventId()
+    {
+        return eventId;
+    }
+    
+    /**
+     * Check whether the class for which the event occurred is compiled.
+     * Valid for STATE_CHANGED event.
+     */
+    public boolean isClassCompiled()
+    {
+        return isCompiled;
+    }
+    
+    /**
+     * Returns the package to which the class that caused this event belongs.
+     * 
+     * @return The package to which the class that caused this event belongs.
+     */
+    public BPackage getPackage()
+    {
+        return bluejPackage.getBPackage();
+    }
+
+    /**
+     * Get the BClass object identifying the class on which the event
+     * occurred.
+     */
+    public BClass getBClass()
+    {
+        return bClass;
+    }
+    
+    /**
+     * Get the new class name. Valid for CHANGED_NAME event.
+     */
+    public String getOldName()
+    {
+        return oldName;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..b097d167127cf3dd885154515910af20ec3f0936
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassListener.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * This interface allows you to listen for class events.
+ * 
+ * <p>Currently the only event is the "state changed" event which can
+ * be used to detect when a class becomes uncompiled (i.e. the source is
+ * changed) or compiled. 
+ * 
+ * @author Davin McCall
+ * @version $Id: ClassListener.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface ClassListener
+{
+    /**
+     * The class state changed. This means that the class source was
+     * changed so that the class is now uncompiled, or the class was
+     * compiled, or the class was renamed.
+     */
+    public void classStateChanged(ClassEvent event);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassListener2.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassListener2.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f0392f3020db02f5fec3fe1cd79a9f05076f2f7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassListener2.java
@@ -0,0 +1,46 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * <p>
+ * This interface is an extension of the {@link ClassListener} interface and
+ * provides one additional method which allows you to get notified if a class
+ * has been removed.
+ * </p>
+ * <p>
+ * The interfaces are split for the reason of backward compatibility.
+ * </p>
+ * 
+ * @author Simon Gerlach
+ */
+public interface ClassListener2 extends ClassListener
+{
+    /**
+     * A class has been removed. The removed class can be acquired from the
+     * passed in {@link ClassEvent} object.
+     * 
+     * @param event
+     *            A <code>ClassEvent</code> object which describes the event.
+     */
+    void classRemoved(ClassEvent event);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassTargetEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassTargetEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc704feae73f9aac32708a920be33a84c9ee2b81
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassTargetEvent.java
@@ -0,0 +1,189 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import bluej.extensions.BClassTarget;
+import bluej.extensions.BDependency;
+import bluej.extensions.BPackage;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.DependentTarget;
+
+/**
+ * This class encapsulates events which occur on class targets of the class
+ * diagram.
+ * 
+ * @author Simon Gerlach
+ */
+public class ClassTargetEvent implements ExtensionEvent
+{
+    /**
+     * This enumeration contains constants which describe the different types of
+     * "class target changed" events.
+     * 
+     * @author Simon Gerlach
+     */
+    public enum Type
+    {
+        /** This event occurs when a class target was set to invisible. */
+        CLASS_TARGET_HIDDEN,
+
+        /** This event occurs when a class target was set to visible. */
+        CLASS_TARGET_SHOWN;
+    }
+
+    private Type eventType;
+    private ClassTarget classTarget;
+    private Package bluejPackage;
+
+    /**
+     * Constructor. Creates a new {@link ClassTargetEvent}.
+     * 
+     * @param classTarget
+     *            The class target which caused this event.
+     * @param bluejPackage
+     *            The package to which the class target belongs.
+     * @param visible
+     *            The new visibility of the class target.
+     */
+    public ClassTargetEvent(ClassTarget classTarget, Package bluejPackage, boolean visible) {
+        this.classTarget = classTarget;
+        this.bluejPackage = bluejPackage;
+
+        if (visible) {
+            eventType = Type.CLASS_TARGET_SHOWN;
+        } else {
+            eventType = Type.CLASS_TARGET_HIDDEN;
+        }
+    }
+
+    /**
+     * Returns the type of this event.
+     * 
+     * @return The type of this event.
+     */
+    public Type getEventType()
+    {
+        return eventType;
+    }
+
+    /**
+     * Returns the class target which caused this event.
+     * 
+     * @return The class target which caused this event.
+     */
+    public BClassTarget getClassTarget()
+    {
+        return classTarget.getBClassTarget();
+    }
+    
+    /**
+     * Returns the associated target of the class target which caused this event
+     * or <code>null</code> if there is no associated target. For example, this
+     * can be the the class target of the corresponding test class of the class
+     * whose class target caused this event.
+     * 
+     * @return The associated target of the class target which caused this event
+     *         or <code>null</code> if there is no associated target.
+     */
+    public BClassTarget getAssociation()
+    {
+        DependentTarget association = classTarget.getAssociation();
+        
+        if (association instanceof ClassTarget) {
+            return ((ClassTarget) association).getBClassTarget();
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a {@link List} containing all dependencies which are related to
+     * super classes and implemented interfaces.
+     * 
+     * @return A {@link List} containing all dependencies which are related to
+     *         super classes and implemented interfaces. This may be a view
+     *         (i.e. it may be updated automatically) and should not be modified.
+     */
+    public List<BDependency> getParentDependencies()
+    {
+        return getBDependencies(classTarget.getParents());
+    }
+
+    /**
+     * Returns a {@link List} containing all dependencies which are related to
+     * sub classes and implementors.
+     * 
+     * @return A {@link List} containing all dependencies which are related to
+     *         sub classes and implementors. Thi smay be a view (i.e. it may be
+     *         updated automatically) and should not be modified.
+     */
+    public List<BDependency> getChildDependencies()
+    {
+        return getBDependencies(classTarget.getChildren());
+    }
+
+    /**
+     * Takes a {@link List} of dependencies and returns a {@link List}
+     * containing the corresponding {@link BDependency} objects.
+     * 
+     * @param dependencies
+     *            The {@link List} of dependencies.
+     * @return A {@link List} containing the corresponding {@link BDependency}
+     *         objects.
+     */
+    private List<BDependency> getBDependencies(List<Dependency> dependencies)
+    {
+        List<BDependency> result = new ArrayList<BDependency>();
+
+        for (Dependency dependency : dependencies) {
+            result.add(dependency.getBDependency());
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns the package to which the class target belongs that caused this
+     * event.
+     * 
+     * @return The package to which the class target belongs that caused this
+     *         event.
+     */
+    public BPackage getPackage()
+    {
+        return bluejPackage.getBPackage();
+    }
+
+    /**
+     * Returns a {@link String} representation of this event.
+     */
+    @Override
+    public String toString()
+    {
+        return "ClassTargetEvent: " + eventType + " (" + classTarget + ")";
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassTargetListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassTargetListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..5903645884fe847a51c53c151bcfd1ebe409ffef
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ClassTargetListener.java
@@ -0,0 +1,55 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * <p>
+ * This interface allows you to listen for class target events.
+ * </p>
+ * <p>
+ * Currently the only event is the "visibility changed" event which occurs when
+ * the visibility of a class target has changed to the opposite of the previous
+ * state.
+ * </p>
+ * 
+ * @author Simon Gerlach
+ */
+public interface ClassTargetListener
+{
+    /**
+     * <p>
+     * The visibility of a class target has changed. This means that the class
+     * target has either been hidden from the graph or became visible again. The
+     * new visibility can be acquired from the passed in
+     * {@link ClassTargetEvent} object.
+     * </p>
+     * <p>
+     * This event only occurs if the visibility of the class target has really
+     * <em>changed</em>. It is not fired if a class target is set to a
+     * visibility in which it already is.
+     * </p>
+     * 
+     * @param event
+     *            A {@code ClassTargetEvent} object which describes the event.
+     */
+    public void classTargetVisibilityChanged(ClassTargetEvent event);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/CompileEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/CompileEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..c404d04fbd335bbb36b0f4cb62011ba5ffce2221
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/CompileEvent.java
@@ -0,0 +1,186 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+import java.io.File;
+
+/**
+ * This class encapsulates compiler events.
+ * It allows an extension writer to know when a compilation starts and
+ * finishes, whether it succeeds or fails, and what warnings or errors are 
+ * generated.
+ * 
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class CompileEvent implements ExtensionEvent 
+{
+    /**
+     * Event generated when compilation begins.
+     */
+    public static final int COMPILE_START_EVENT = 1;
+
+    /**
+     * Event generated when a compilation warning occurs.
+     * A warning event is one that will not invalidate the compilation.
+     */
+    public static final int COMPILE_WARNING_EVENT = 2;
+
+    /**
+     * Event generated when a compilation error occurs.
+     * An error event is one that will invalidate the compilation
+     */
+    public static final int COMPILE_ERROR_EVENT = 3;
+
+    /**
+     * Event generated when a compilation finishes successfully.
+     */
+    public static final int COMPILE_DONE_EVENT = 4;
+
+    /**
+     * Event generated when a compilation finishes unsuccessfully.
+     */
+    public static final int COMPILE_FAILED_EVENT = 5;
+
+    private int    eventId;
+    private File[] fileNames;   // An array of names this event belong to
+    private int    errorLineNumber;
+    private int    errorColumn;
+    private int    endErrorLine;
+    private int    endErrorColumn;
+    private String errorMessage;
+
+    /**
+     * Constructor for a CompileEvent.
+     */
+    public CompileEvent(int anEventId, File[] aFileNames)
+    {
+        eventId   = anEventId;
+        fileNames = aFileNames;
+    }
+
+    /**
+     * Returns the eventId, one of the values defined.
+     */
+    public int getEvent()
+    {
+        return eventId;
+    }
+
+    /**
+     * Returns an array of zero, one or more files related to this event.
+     */
+    public File[] getFiles()
+    {
+        return fileNames;
+    }
+
+    /**
+     * Sets the line number where an error or warning occurred.
+     */
+    public void setErrorLineNumber(int aLineNumber)
+    {
+        errorLineNumber = aLineNumber;
+    }
+    
+    /**
+     * Set the error position - beginning line [0] and column [1], ending line [2] and column [3]
+     */
+    public void setErrorPosition(int [] errorPosition)
+    {
+        errorLineNumber = errorPosition[0];
+        errorColumn = errorPosition[1];
+        endErrorLine = errorPosition[2];
+        endErrorColumn = errorPosition[3];
+    }
+
+    /**
+     * Returns the line number where the compilation error occurs.
+     * Only valid in the case of an error or warning event.
+     */
+    public int getErrorLineNumber()
+    {
+        return errorLineNumber;
+    }
+    
+    /**
+     * Get the error position - beginning line [0] and column [1], ending line [2] and column [3].
+     */
+    public int[] getErrorPosition()
+    {
+        int [] r = new int[4];
+        r[0] = errorLineNumber;
+        r[1] = errorColumn;
+        r[2] = endErrorLine;
+        r[3] = endErrorColumn;
+        return r;
+    }
+
+    /**
+     * Sets the error message for an error or warning event.
+     */
+    public void setErrorMessage(String anErrorMessage)
+    {
+        errorMessage = anErrorMessage;
+    }
+
+    /**
+     * Returns the error message generated by the compiler.
+     * Only valid in the case of an error or warning event.
+     */
+    public String getErrorMessage()
+    {
+        return errorMessage;
+    }
+
+    /**
+     * Returns a meaningful description of this event.
+     */
+    @Override
+    public String toString()
+    {
+        StringBuffer aRisul = new StringBuffer(500);
+
+        aRisul.append("CompileEvent:");
+
+        if ( eventId == COMPILE_START_EVENT ) aRisul.append(" COMPILE_START_EVENT");
+        if ( eventId == COMPILE_WARNING_EVENT ) aRisul.append(" COMPILE_WARNING_EVENT");
+        if ( eventId == COMPILE_ERROR_EVENT ) aRisul.append(" COMPILE_ERROR_EVENT");
+        if ( eventId == COMPILE_DONE_EVENT ) aRisul.append(" COMPILE_DONE_EVENT");
+        if ( eventId == COMPILE_FAILED_EVENT ) aRisul.append(" COMPILE_FAILED_EVENT");
+
+        aRisul.append(" getFiles().length=");
+        aRisul.append(fileNames.length);
+
+        for(int i = 0; i < fileNames.length; i++) {
+            aRisul.append(" getFiles()[" + i + "]=");
+            aRisul.append(fileNames[i]);
+        }
+
+        if ( eventId == COMPILE_WARNING_EVENT || eventId == COMPILE_ERROR_EVENT )
+        {
+            aRisul.append(" errorLineNumber=" + errorLineNumber);
+            aRisul.append(" errorMessage=" + errorMessage);
+        }
+
+        return aRisul.toString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/CompileListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/CompileListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..f52f0dca9cf4a010a7495e2a74529aad4a0cacb2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/CompileListener.java
@@ -0,0 +1,71 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * This interface allows you to listen for compile events.
+ * The order of occurence of these method calls for a given compilation is:
+ * <pre>
+ *     compileStarted()
+ *     compileError()                        # If a compilation error occurs
+ *     compileWarning()                      # If a compilation warning occurs
+ *     compileFailed() or compileSucceeded()
+ * </pre>
+ * Note that currently BlueJ only reports the first compilation error or warning.
+ *
+ * @version $Id: CompileListener.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface CompileListener
+{
+    /**
+     * This method will be called when a compilation starts.
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void compileStarted (CompileEvent event);
+    
+    /**
+     * This method will be called when there is a report of a compile error.
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void compileError (CompileEvent event);
+
+    /**
+     * This method will be called when there is a report of a compile warning.
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void compileWarning (CompileEvent event);
+
+    /**
+     * This method will be called when the compile ends successfully.
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void compileSucceeded (CompileEvent event);
+
+
+    /**
+     * This method will be called when the compile fails.
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void compileFailed (CompileEvent event);
+
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/DependencyEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/DependencyEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d09230a513f822260798fbe01ce14c9a41588d6
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/DependencyEvent.java
@@ -0,0 +1,160 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+import bluej.extensions.BClassTarget;
+import bluej.extensions.BDependency;
+import bluej.extensions.BPackage;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.DependentTarget;
+
+/**
+ * This class encapsulates events which occur on dependencies of the class
+ * diagram.
+ * 
+ * @author Simon Gerlach
+ */
+public class DependencyEvent implements ExtensionEvent
+{
+    /**
+     * This enumeration contains constants which describe the different types of
+     * "dependency changed" events.
+     * 
+     * @author Simon Gerlach
+     */
+    public enum Type
+    {
+        /** This event occurs when a dependency was added to the package. */
+        DEPENDENCY_ADDED,
+
+        /** This event occurs when a dependency was set to invisible. */
+        DEPENDENCY_HIDDEN,
+
+        /** This event occurs when a dependency was set to visible. */
+        DEPENDENCY_SHOWN,
+
+        /** This event occurs when a dependency was removed from the package. */
+        DEPENDENCY_REMOVED;
+    }
+
+    private Type eventType;
+    private Dependency dependency;
+    private Package bluejPackage;
+
+    /**
+     * Constructor. Creates a new {@link DependencyEvent}. The type of the event
+     * is determined by the given visibility.
+     * 
+     * @param dependency
+     *            The dependency which caused this event.
+     * @param bluejPackage
+     *            The package to which the dependency belongs.
+     * @param visible
+     *            The new visibility of the dependency.
+     */
+    public DependencyEvent(Dependency dependency, Package bluejPackage, boolean visible)
+    {
+        this(dependency, bluejPackage, (visible ? Type.DEPENDENCY_SHOWN : Type.DEPENDENCY_HIDDEN));
+    }
+
+    /**
+     * Constructor. Creates a new {@link DependencyEvent} with the given values.
+     * 
+     * @param dependency
+     *            The dependency which caused this event.
+     * @param bluejPackage
+     *            The package to which the dependency belongs.
+     * @param eventType
+     *            The type of this event.
+     */
+    public DependencyEvent(Dependency dependency, Package bluejPackage, Type eventType)
+    {
+        this.dependency = dependency;
+        this.bluejPackage = bluejPackage;
+        this.eventType = eventType;
+    }
+
+    /**
+     * Returns the type of this event.
+     * 
+     * @return The type of this event.
+     */
+    public Type getEventType()
+    {
+        return eventType;
+    }
+    
+    /**
+     * Returns the type of the dependency which caused this event.
+     * 
+     * @return The type of the dependency which caused this event.
+     */
+    public BDependency.Type getDependencyType()
+    {
+        return dependency.getType();
+    }
+
+    /**
+     * Returns the origin of the dependency which caused this event.
+     * 
+     * @return The origin of the dependency which caused this event.
+     */
+    public BClassTarget getOrigin()
+    {
+        DependentTarget origin = dependency.getFrom();
+        return ((ClassTarget) origin).getBClassTarget();
+    }
+
+    /**
+     * Returns the target of the dependency which caused this event.
+     * 
+     * @return The target of the dependency which caused this event.
+     */
+    public BClassTarget getTarget()
+    {
+        DependentTarget target = dependency.getTo();
+        return ((ClassTarget) target).getBClassTarget();
+    }
+    
+    /**
+     * Returns the package to which the dependency belongs that caused this
+     * event.
+     * 
+     * @return The package to which the dependency belongs that caused this
+     *         event.
+     */
+    public BPackage getPackage()
+    {
+        return bluejPackage.getBPackage();
+    }
+
+    /**
+     * Returns a {@link String} representation of this event.
+     */
+    @Override
+    public String toString()
+    {
+        return "DependencyEvent: " + eventType + " (" + dependency + ")";
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/DependencyListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/DependencyListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee1f9a5b9b60b67dea0bf84b8f91b34bba1d17b4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/DependencyListener.java
@@ -0,0 +1,73 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * <p>
+ * This interface allows you to listen for dependency events.
+ * </p>
+ * <p>
+ * Dependency events occur when a dependency was added or removed from the
+ * package and when the visibility of a dependency has changed to the opposite
+ * of the previous state.
+ * </p>
+ * 
+ * @author Simon Gerlach
+ */
+public interface DependencyListener {
+    /**
+     * A dependency was added to the package.
+     * 
+     * @param event
+     *            A <code>DependencyEvent</code> object which describes the
+     *            event.
+     */
+    public void dependencyAdded(DependencyEvent event);
+
+    /**
+     * A dependency was removed from the package.
+     * 
+     * @param event
+     *            A <code>DependencyEvent</code> object which describes the
+     *            event.
+     */
+    public void dependencyRemoved(DependencyEvent event);
+
+    /**
+     * <p>
+     * The visibility of a dependency has changed. This means that the
+     * dependency has either been hidden from the graph or became visible again.
+     * The new visibility can be acquired from the passed in
+     * {@link DependencyEvent} object.
+     * </p>
+     * <p>
+     * This event only occurs if the visibility of the dependency has really
+     * <em>changed</em>. It is not fired if a dependency is set to a visibility
+     * in which it already is.
+     * </p>
+     * 
+     * @param event
+     *            A <code>DependencyEvent</code> object which describes the
+     *            event.
+     */
+    public void dependencyVisibilityChanged(DependencyEvent event);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ExtensionEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ExtensionEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..05df9ebf0679dfb22e8545b4a9620d2ebf46fcaf
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ExtensionEvent.java
@@ -0,0 +1,47 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * Base class for the different event types generated by BlueJ for extensions.
+ * 
+ * @version $Id: ExtensionEvent.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+ /*
+  * Author Damiano Bolla, Universoty of Kent at Canterbury.
+  * This is a different one than the previous one done by Clive Miller.
+  */
+public interface ExtensionEvent 
+  {
+  /*
+   * The issue here is the following. This class is desirable to put all Extensions events under the same ubmbrealla
+   * So it is s logical grouper, unfortunately at the moment it cannot be anything else, the reason being
+   * 1) The id of each event should be handled in the more dedicated classes (so the id disappear here) since
+   *    is has a defined meaning ONLY in the specific implementation.
+   * 2) The BPackage is not always present and has a meaning in certain cases (so no point to have it here)
+   * 
+   * It may be argued that it is nice to have a getEvent at this level, the point is that it WILL return meaningless
+   * results if it is not matched with the particular class, it is therefore safere to leave it there.
+   * Damiano
+   */
+  }
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ExtensionEventListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ExtensionEventListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..1bd908a68ba5362a5a2284fa85bd22c04c70df6e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/ExtensionEventListener.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * This interface allows you to listen for all BlueJ events by using a single listener.
+ * Normally, extensions will use the specialised event types and listeners, but 
+ * in some cases (e.g.) logging or testing extensions this overarching event type 
+ * will be more appropriate.
+ *
+ * @version $Id: ExtensionEventListener.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface ExtensionEventListener
+{
+    /**
+     * This method will be called when an event occurs.
+     * Note that this method is called from a Swing-like dispatcher and therefore you must
+     * return as quickly as possible. 
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void eventOccurred (ExtensionEvent event);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/InvocationEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/InvocationEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..e84c8949cb8c4c8d975d157c1bc000073a16ddb1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/InvocationEvent.java
@@ -0,0 +1,338 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+import bluej.debugger.*;
+import bluej.debugger.gentype.*;
+import bluej.debugmgr.*;
+import bluej.debugmgr.objectbench.*;
+import bluej.extensions.*;
+import bluej.pkgmgr.*;
+import com.sun.jdi.*;
+
+
+/**
+ * This class encapsulates events generated when the construction or invocation
+ * of a BlueJ object finishes.
+ * An invocation may finish in a normal way or it may be interrupted.
+ * From this event you can extract the actual result of the invocation, and access the BlueJ
+ * classes and objects involved.
+ *
+ * @author Clive Miller, University of Kent at Canterbury, 2002
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003,2004
+ */
+public class InvocationEvent implements ExtensionEvent
+{
+    /**
+     *  This event is returned in case of unknown mapping
+     */
+    public final static int UNKNOWN_EXIT = 0;
+    /**
+     * The execution finished normally.
+     */
+    public final static int NORMAL_EXIT = 1;
+    /**
+     * The execution finished through a call to <code>System.exit()</code>. This is
+     * deprecated; it cannot actually occur.
+     */
+    @Deprecated
+    public final static int FORCED_EXIT = 2;
+    /**
+     * The execution finished due to an exception
+     */
+    public final static int EXCEPTION_EXIT = 3;
+    /**
+     * The execution finished because the user forcefully terminated it
+     */
+    public final static int TERMINATED_EXIT = 4;
+
+    private String className, objectName, methodName;
+    private JavaType[] signature;
+    private String[] parameters;
+    private int invocationStatus;
+    private bluej.pkgmgr.Package bluej_pkg;
+    private DebuggerObject resultObj;
+
+
+    /**
+     * Constructor for the event.
+     *
+     * @param  exevent  Description of the Parameter
+     */
+    public InvocationEvent(ExecutionEvent exevent)
+    {
+        invocationStatus = UNKNOWN_EXIT;
+        String resultType = exevent.getResult();
+
+        if (resultType == ExecutionEvent.NORMAL_EXIT) {
+            invocationStatus = NORMAL_EXIT;
+        }
+        if (resultType == ExecutionEvent.EXCEPTION_EXIT) {
+            invocationStatus = EXCEPTION_EXIT;
+        }
+        if (resultType == ExecutionEvent.TERMINATED_EXIT) {
+            invocationStatus = TERMINATED_EXIT;
+        }
+
+        bluej_pkg = exevent.getPackage();
+        className = exevent.getClassName();
+        objectName = exevent.getObjectName();
+        methodName = exevent.getMethodName();
+        signature = exevent.getSignature();
+        parameters = exevent.getParameters();
+        resultObj = exevent.getResultObject();
+    }
+
+
+    /**
+     * Returns the invocation status. One of the values listed above.
+     *
+     * @return    The invocationStatus value
+     */
+    public int getInvocationStatus()
+    {
+        return invocationStatus;
+    }
+
+
+    /**
+     * Returns the package in which this invocation took place.
+     * Further information about the context of the event can be retrieved via the package object.
+     *
+     * @return    The package value
+     */
+    public BPackage getPackage()
+    {
+        return bluej_pkg.getBPackage();
+    }
+
+
+    /**
+     * Returns the class name on which this invocation took place.
+     * If you need further information about this class you can obtain a
+     * BClass from <code>BPackage.getBClass()</code> using this name as a reference.
+     *
+     * @return    The className value
+     */
+    public String getClassName()
+    {
+        return className;
+    }
+
+
+    /**
+     * Returns the instance name of the invoked object on the object bench.
+     * If you need further information about this object you can obtain a BObject using
+     * <code>BPackage.getObject()</code> using this name as a reference.
+     *
+     * For a static method invocation, this method will return <code>null</code>.
+     * For a constructor call it will return the new instance name of the object on the object bench.
+     * For a method call it will return the name of the object on which the operation was invoked.
+     *
+     * @return    The objectName value
+     */
+    public String getObjectName()
+    {
+        return objectName;
+    }
+
+
+    /**
+     * Returns the method name being called.
+     * Returns <code>null</code> if this is an invocation of a constructor.
+     *
+     * @return    The methodName value
+     */
+    public String getMethodName()
+    {
+        return methodName;
+    }
+
+
+    /**
+     * Returns the signature of the invoked method or constructor. 
+     *
+     * This is an array of Class objects representing the static types of 
+     * the parameters to the method or constructor, in order. In the case of 
+     * parameterised types, only the base type (e.g. List, not 
+     * List<String>) is returned.
+     *
+     * @return    An array of Classes corresponding to the static types of the method's parameters.
+     */
+    public Class<?>[] getSignature()
+    {
+        if (signature == null) {
+            return new Class[0];
+        }
+
+        Class<?>[] risul = new Class[signature.length];
+        for (int index = 0; index < signature.length; index++) {
+            JavaType sig = signature[index];
+            if (sig.isPrimitive()) {
+                // Map the primitive bluej types to java types
+                if(sig == JavaPrimitiveType.getBoolean()) {
+                    risul[index] = boolean.class;
+                } 
+                else if(sig == JavaPrimitiveType.getByte()) {
+                    risul[index] = byte.class;
+                }  
+                else if(sig == JavaPrimitiveType.getChar()) {
+                    risul[index] = char.class;
+                }  
+                else if(sig == JavaPrimitiveType.getDouble()) {
+                    risul[index] = double.class;
+                }  
+                else if(sig == JavaPrimitiveType.getFloat()) {
+                    risul[index] = float.class;
+                }  
+                else if(sig == JavaPrimitiveType.getInt()) {
+                    risul[index] = int.class;
+                }  
+                else if(sig == JavaPrimitiveType.getLong()) {
+                    risul[index] = long.class;
+                }  
+                else if(sig == JavaPrimitiveType.getShort()) {
+                    risul[index] = short.class;
+                }  
+            }
+            else {
+                // It's a non-primitive class. Until we abandon Java 1.4
+                // support, we can't use java.lang.reflect.Type, and we
+                // don't want to reveal the JavaType hierarchy, so we use 
+                // the "raw" class name provided by the JavaType
+
+                String className = sig.asClass().classloaderName();
+                risul[index] = bluej_pkg.getProject().loadClass(className);
+            }
+        }
+        return risul;
+    }
+
+
+    /**
+     * Returns the values of the parameters to the invocation as strings.
+     * If a parameter really was a String, this will be returned either as the
+     * name of the string instance, or as a literal string enclosed in double quotes.
+     *
+     * @return    The values of the parameters
+     */
+    public String[] getParameters()
+    {
+        if (parameters == null) {
+            return new String[0];
+        }
+        return parameters;
+    }
+
+
+    /**
+     * Returns the newly created object (if any).
+     * If the object is one that can be put on the object bench it will be an instance of BObject.
+     *
+     * @return    an Object of various types or <code>null</code> if the result type is <code>void</code>.
+     */
+
+    // TODO: There ought to be a way of retrieving the declared return type of the invoked method.
+
+    public Object getResult()
+    {
+        if (resultObj == null) {
+            return null;
+        }
+
+        if (methodName != null) {
+            return getMethodResult();
+        }
+
+        // Here I am dealing with a new instance...
+        PkgMgrFrame pmf = PkgMgrFrame.findFrame(bluej_pkg);
+        ObjectWrapper wrapper = ObjectWrapper.getWrapper(pmf, pmf.getObjectBench(), resultObj, resultObj.getGenType(), objectName);
+
+        return ExtensionBridge.newBObject(wrapper);
+    }
+
+
+    /**
+     * Returns of a result from a method call
+     *
+     * @return    The methodResult value
+     */
+    private Object getMethodResult()
+    {
+        ObjectReference objRef = resultObj.getObjectReference();
+        ReferenceType type = objRef.referenceType();
+
+        // It happens that the REAL result is in the result field of this Object...
+        Field thisField = type.fieldByName("result");
+        if (thisField == null) {
+            return null;
+        }
+
+        // WARNING: I do not have the newly created name here....
+        PkgMgrFrame aFrame = PkgMgrFrame.findFrame(bluej_pkg);
+        return ExtensionBridge.getVal(aFrame, "", objRef.getValue(thisField));
+    }
+
+
+    /**
+     * Returns a meaningful description of this Event.
+     *
+     * @return    Description of the Return Value
+     */
+    public String toString()
+    {
+        StringBuffer aRisul = new StringBuffer(500);
+
+        aRisul.append("ResultEvent:");
+
+        if (invocationStatus == NORMAL_EXIT) {
+            aRisul.append(" NORMAL_EXIT");
+        }
+        if (invocationStatus == FORCED_EXIT) {
+            aRisul.append(" FORCED_EXIT");
+        }
+        if (invocationStatus == EXCEPTION_EXIT) {
+            aRisul.append(" EXCEPTION_EXIT");
+        }
+        if (invocationStatus == TERMINATED_EXIT) {
+            aRisul.append(" TERMINATED_EXIT");
+        }
+
+        if (className != null) {
+            aRisul.append(" BClass=" + className);
+        }
+        if (objectName != null) {
+            aRisul.append(" objectName=" + objectName);
+        }
+        if (methodName != null) {
+            aRisul.append(" methodName=" + methodName);
+        }
+
+        Object aResult = getResult();
+        if (resultObj != null) {
+            aRisul.append(" resultObj=" + aResult);
+        }
+
+        return aRisul.toString();
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/InvocationListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/InvocationListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..667656deaf14a64fc6669a8be282d2c43b316adb
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/InvocationListener.java
@@ -0,0 +1,36 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * This interface allows you to listen for when an invocation has finished.
+ *
+ * @version $Id: InvocationListener.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface InvocationListener
+{
+    /**
+     * This method will be called when an invocation has finished.
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void invocationFinished (InvocationEvent event);
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/PackageEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/PackageEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..b552e30f15dfc7ad69538615bc96ba61b140d747
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/PackageEvent.java
@@ -0,0 +1,90 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+import bluej.extensions.*;
+import bluej.pkgmgr.Package;
+
+/**
+ * This class encapsulates events on BlueJ packages.
+ *
+ * @author Clive Miller, University of Kent at Canterbury, 2002
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class PackageEvent implements ExtensionEvent
+{
+    /**
+     * This event occurs when a package has just been opened.
+     */
+    public static final int PACKAGE_OPENED = 1;
+
+    /**
+     * This event occurs when a package is just about to be closed.
+     */ 
+    public static final int PACKAGE_CLOSING = 2;
+
+    private int eventId;
+    private Package thisPackage;
+
+    /**
+     * Constructor for the PackageEvent.
+     */
+    public PackageEvent (int eventId, Package pkg)
+    {
+        this.eventId = eventId;
+        thisPackage = pkg;
+    }
+
+    /**
+     * Returns the eventId of this event.
+     */
+    public int getEvent ()
+    {
+        return eventId;
+    }
+
+    /**
+     * Returns the package associated with this event.
+     */
+    public BPackage getPackage ()
+    {
+        return thisPackage.getBPackage();
+    }
+
+    /**
+     * Returns a meaningful description of this event.
+     */
+    @Override
+    public String toString()
+    {
+        StringBuffer aRisul = new StringBuffer (500);
+
+        aRisul.append("PackageEvent:");
+
+        if ( eventId == PACKAGE_OPENED ) aRisul.append(" PACKAGE_OPENED");
+        if ( eventId == PACKAGE_CLOSING ) aRisul.append(" PACKAGE_CLOSING");
+
+        aRisul.append(" packageName="+thisPackage.getQualifiedName());
+
+        return aRisul.toString();      
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/PackageListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/PackageListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ef18475ee77ad68fdcaf3a9e71e806f21cec2c8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/event/PackageListener.java
@@ -0,0 +1,43 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.event;
+
+/**
+ * This interface allows you to listen for events on BlueJ packages.
+ *
+ * @version $Id: PackageListener.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface PackageListener
+{
+    /**
+     * This method will be called when a package has been opened.
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void packageOpened (PackageEvent event);
+
+    /**
+     * This method will be called when a package is about to be closed.
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void packageClosing (PackageEvent event);
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/painter/ExtensionClassTargetPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/painter/ExtensionClassTargetPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf088200d7cf492f53cd8935ffb8b701f8ae5846
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extensions/painter/ExtensionClassTargetPainter.java
@@ -0,0 +1,84 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extensions.painter;
+
+import java.awt.Graphics2D;
+
+import bluej.extensions.BClassTarget;
+
+/**
+ * <p>
+ * This interface allows extensions to provide custom implementations for
+ * painting a class target. Although, extensions are not allowed to define a
+ * completely new visual representation of a class target. A class target is
+ * always rectangular and the name of the class is printed in the top area. Only
+ * the area below the name may be customized by extensions.
+ * </p>
+ * <p>
+ * To prevent extensions from painting over each others representation of a
+ * class target, the process is split into two methods. One is responsible for
+ * the background while the other prints the foreground. Extensions are
+ * encouraged to decide wisely where their painting should go. However, there is
+ * no guarantee that your drawing will not be painted over by another extension.
+ * </p>
+ * <p>
+ * NOTE: The warnings of BlueJ (e.g. the stripped image, if the class is
+ * uncompiled and the "broken" image if the source code could not be parsed)
+ * will always be drawn <em>after</em> the extensions have drawn their images.
+ * Therefore, extensions are unable to paint over the warnings or prevent them
+ * from appearing.
+ * </p>
+ * 
+ * @author Simon Gerlach
+ */
+public interface ExtensionClassTargetPainter
+{
+    /**
+     * Ask the extension to draw the background of its class target
+     * representation.
+     * 
+     * @param bClassTarget
+     *            The class target that will be painted.
+     * @param graphics
+     *            The {@link Graphics2D} instance to draw on.
+     * @param width
+     *            The width of the area to paint.
+     * @param height
+     *            The height of the area to paint.
+     */
+    void drawClassTargetBackground(BClassTarget bClassTarget, Graphics2D graphics, int width, int height);
+
+    /**
+     * Ask the extension to draw the foreground of its class target
+     * representation.
+     * 
+     * @param bClassTarget
+     *            The class target that will be painted.
+     * @param graphics
+     *            The {@link Graphics2D} instance to draw on.
+     * @param width
+     *            The width of the area to paint.
+     * @param height
+     *            The height of the area to paint.
+     */
+    void drawClassTargetForeground(BClassTarget bClassTarget, Graphics2D graphics, int width, int height);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ClassMenuObject.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ClassMenuObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ec17529e14352b3f387a1c4c938ef197d48ee5d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ClassMenuObject.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import javax.swing.JMenuItem;
+
+import bluej.extensions.BClass;
+import bluej.extensions.ExtensionBridge;
+import bluej.extensions.MenuGenerator;
+import bluej.pkgmgr.target.ClassTarget;
+
+/**
+ * Implementation of the {@link ExtensionMenuObject} interface for the Class
+ * menu.
+ * 
+ * @author Simon Gerlach
+ */
+public class ClassMenuObject implements ExtensionMenuObject
+{
+    private ClassTarget classTarget;
+
+    /**
+     * Constructor. Creates a new {@link ClassMenuObject}.
+     * 
+     * @param classTarget
+     *            The class target which was selected by the user.
+     */
+    public ClassMenuObject(ClassTarget classTarget)
+    {
+        this.classTarget = classTarget;
+    }
+
+    @Override
+    public JMenuItem getMenuItem(MenuGenerator menuGenerator)
+    {
+        BClass bClass = ExtensionBridge.newBClass(classTarget);
+        return menuGenerator.getClassMenuItem(bClass);
+    }
+
+    @Override
+    public void postMenuItem(MenuGenerator menuGenerator, JMenuItem onThisItem)
+    {
+        BClass bClass = ExtensionBridge.newBClass(classTarget);
+        menuGenerator.notifyPostClassMenu(bClass, onThisItem);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionMenuObject.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionMenuObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..acdd9b8bbabeb61d0771ae694dafb1f3cd33586e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionMenuObject.java
@@ -0,0 +1,56 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import javax.swing.JMenuItem;
+
+import bluej.extensions.MenuGenerator;
+
+/**
+ * This interface provides methods for retrieving custom menu entries of an
+ * extension and to notify it if a menu is about to show. Implementations of
+ * this interface serve as a bridge between BlueJ and the extension mechanism.
+ * 
+ * @author Simon Gerlach
+ */
+public interface ExtensionMenuObject
+{
+    /**
+     * Calls the extension to get a menu item.
+     * 
+     * @param menuGenerator
+     *            The {@link MenuGenerator} which creates the menu.
+     * @return The {@link JMenuItem} the extension provides or <code>null</code>
+     *         if it does not provide a menu entry.
+     */
+    JMenuItem getMenuItem(MenuGenerator menuGenerator);
+
+    /**
+     * Post a notification about a menu going to be displayed.
+     * 
+     * @param menuGenerator
+     *            The {@link MenuGenerator} which creates the menu.
+     * @param onThisItem
+     *            The {@link JMenuItem} which is about to show.
+     */
+    void postMenuItem(MenuGenerator menuGenerator, JMenuItem onThisItem);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionPrefManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionPrefManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..f46c90f4d4c3ce24f0bbfe1ccb3b6d7a5395a0cf
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionPrefManager.java
@@ -0,0 +1,202 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import java.awt.BorderLayout;
+import java.awt.EventQueue;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.border.EmptyBorder;
+
+import bluej.prefmgr.PrefPanelListener;
+
+/**
+ * This manages the whole preference pane for Extensions
+ * It will be loaded in the appropriate tab when the register() is called
+ * 
+ * @author  Damiano Bolla: University of Kent at Canterbury
+ * @author  Michael Kolling
+ */
+public class ExtensionPrefManager implements PrefPanelListener
+{
+    private List<ExtensionWrapper> extensionsList;
+
+    private final int DO_panelUpdate=1;
+    private final int DO_loadValues=2;
+    private final int DO_saveValues=3;
+
+    private JPanel drawPanel;
+    private JPanel rootPanel;
+
+    /**
+     * The manager needs to know the installed extensions
+     */
+    public ExtensionPrefManager(List<ExtensionWrapper> i_extensionsList) 
+    {
+        extensionsList = i_extensionsList;
+
+        // I need a draw panel Components in here should be laid on the top - down
+        drawPanel = new JPanel();
+        drawPanel.setLayout(new BoxLayout(drawPanel,BoxLayout.Y_AXIS));
+
+        // I need a middle panel just to pack everything up
+        JPanel middlePanel = new JPanel (new BorderLayout());
+        middlePanel.add(drawPanel,BorderLayout.NORTH);
+
+        // And I need to put this panel into a scroll pane
+        JScrollPane drawScroll = new JScrollPane (middlePanel);
+        drawScroll.setBorder(new EmptyBorder(0,0,0,0));
+        drawScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+
+        /* Add the scroll pane to the root panel
+         * It needs to use all the available space, otherwise the scroll pane does not
+         * understand when to draw its scrollbars
+         */
+        rootPanel = new JPanel(new BorderLayout());
+        rootPanel.add(drawScroll,BorderLayout.CENTER);
+    }
+
+    /**
+     * Return the panel that shows the GUI.
+     */
+    public JPanel getPanel()
+    {
+        return rootPanel;
+    }
+    
+    /**
+     * This is the looper, I will use some const to decide at the end
+     * what to do. Just to make code simples and cleaner
+     * Note that half or more of the code is on Fault managment ...
+     */
+    private void doWorkLoop(int doAction) 
+    {
+        // I need to remove all content, in any case...
+        if (doAction == DO_panelUpdate) 
+            drawPanel.removeAll();
+      
+        synchronized (extensionsList) {
+            for (ExtensionWrapper wrapper : extensionsList) {
+                doWorkItem (wrapper, doAction);
+            }            
+        }
+    }
+
+    /**
+     * Do some work on one extension wrapper.
+     * It is either adding panels, saving or loading...
+     */
+    private void doWorkItem(ExtensionWrapper aWrapper, int doAction) 
+    {
+        // This extension is not valid, let me skip it
+        if (! aWrapper.isValid()) return;
+
+        String extensionName = aWrapper.safeGetExtensionName();
+
+        switch (doAction) {
+            case DO_loadValues:  
+                aWrapper.safePrefGenLoadValues();   
+                return;
+            case DO_saveValues:  
+                aWrapper.safePrefGenSaveValues();   
+                return;
+            case DO_panelUpdate: 
+                addUserPanel (aWrapper, extensionName); 
+                return;
+        }
+    }
+
+  
+    /**
+     * Being here to make code cleaner. 
+     * Given an Extension preference panel add it into the main panel
+     */
+    private void addUserPanel(ExtensionWrapper aWrapper, String extensionName) 
+    {
+        JPanel aPanel = aWrapper.safePrefGenGetPanel();
+        if (aPanel == null) {
+            return;
+        }
+
+        // The panel that the user gives me goes into a container pane
+        JPanel framePanel = new JPanel(new BorderLayout());
+        framePanel.setBorder(BorderFactory.createTitledBorder(extensionName));
+
+        // The panel that the user gives me goes into the north, packed
+        framePanel.add (aPanel,BorderLayout.NORTH);
+
+        // Finally put this panel into the drawing panel, it will be stacket Y axis
+        drawPanel.add (framePanel);
+    }
+
+
+    /**
+     * Start the revalidation of the panels associated to the extensions.
+     */
+    public void panelRevalidate() 
+    {
+        if (EventQueue.isDispatchThread()) {
+            doWorkLoop(DO_panelUpdate);
+        }
+        else {
+            EventQueue.invokeLater(new ExtensionPrefManager.DoPanelUpdate());
+        }
+    }
+    
+    /**
+     * Nothing much to do, this is to satisfy the invokeLater
+     */
+    private class DoPanelUpdate implements Runnable
+    {
+        public void run()
+        {
+            doWorkLoop (DO_panelUpdate);
+        }
+    }
+
+    /*
+     * Needed only to satisfy the implements
+     */
+    public void beginEditing()  {  }
+    
+    
+    /*
+     * Called by the system when it is time to reload the panel values
+     */
+    public void revertEditing() 
+    {
+        doWorkLoop(DO_loadValues);
+    }
+
+    /*
+     * Called by the system when the user has pressed the OK buton
+     */
+    public void commitEditing()
+    {
+        doWorkLoop(DO_saveValues);
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionWrapper.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ed5d952cb5d9922918ee00cb05d34e5c7d6401a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionWrapper.java
@@ -0,0 +1,699 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import bluej.*;
+import bluej.extensions.*;
+import bluej.extensions.event.*;
+import bluej.extensions.painter.ExtensionClassTargetPainter;
+import bluej.pkgmgr.*;
+import bluej.pkgmgr.graphPainter.ClassTargetPainter.Layer;
+import bluej.utility.*;
+
+import java.awt.Graphics2D;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.jar.*;
+import javax.swing.*;
+import java.lang.ClassNotFoundException;
+
+/**
+ * This is the wrapper for an extension. Its duties are: 
+ * <ul>
+ * <li>Keep track of an extension class, this is to allow loading and unloading 
+ * <li>Given a jar try to load an extension that is in it (if any) 
+ * <li>Hold all state that is needed to get the whole system working
+ * </ul> 
+ *  
+ * <p>Note: When an extension is loaded a BlueJ object is given to it. This object MUST
+ * be fully usable by the extension AND all associated components !
+ * 
+ * <p>The creation of an extension Wrapper is disjoint from the loading of an extension.
+ *  
+ * @author Damiano Bolla, 2002,2003,2004
+ */
+public class ExtensionWrapper
+{
+    private final ExtensionPrefManager prefManager;
+
+    private File extensionJarFileName;
+
+    // If != null the jar is good.
+    private Class<?> extensionClass;
+
+    // If != null the extension is loaded
+    private Extension extensionInstance;
+
+    private BlueJ   extensionBluej;
+    private String  extensionStatusString;
+    private Project project;
+
+    /**
+     * Construct a new ExtensionWrapper for the given jar file.
+     * 
+     * <p>This may fail; in that case isJarValid() will return false.
+     * 
+     * <p>The extension is not actually loaded: call newExtension() for that.
+     */
+    public ExtensionWrapper(ExtensionPrefManager prefManager, File jarFile)
+    {
+        this.prefManager = prefManager;
+
+        // Let me try to load the extension class
+        extensionClass = getExtensionClass(jarFile);
+        if (extensionClass == null) {
+            return;
+        }
+
+        extensionJarFileName  = jarFile;
+    }
+
+
+    /**
+     * Get the extension class for an extension .jar file. Return the Class or
+     * null if none is found.
+     * 
+     * <p>Some messages are logged in case of failure since otherwise a user may never
+     * understand why his lovely extension was not loaded.
+     *
+     * @param  jarFileName  The name of the (potential) extension jar file name to load
+     * @return              The extension class.
+     */
+    private Class<?> getExtensionClass(File jarFileName)
+    {
+        Class<?> extensionClass = null;
+        extensionStatusString = Config.getString("extmgr.status.loading");
+
+        // It may happen, no reason to core dump for this...
+        if (jarFileName == null) return null;
+
+        // Also this may happen, again, no reason to continue further
+        if (!jarFileName.getName().endsWith(".jar")) return null;
+
+        // Needed so on error I know which file is trowing it
+        String errorPrefix = "getExtensionsClass: jarFile="+jarFileName.getName()+" ";
+
+        try {
+            JarFile jarFile = new JarFile(jarFileName);
+            Manifest manifest = jarFile.getManifest();
+            if (manifest == null) {
+                Debug.message(errorPrefix+Config.getString("extmgr.error.nomanifest"));
+                return null;
+            }
+
+            String className = manifest.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
+            if (className == null) {
+                Debug.message(errorPrefix+Config.getString("extmgr.error.nomain"));
+                return null;
+            }
+
+            URL url = jarFileName.toURI().toURL();
+            URL[] urlList=new URL[]{url};
+            FirewallLoader fireLoader = new FirewallLoader(getClass().getClassLoader());
+            URLClassLoader ucl = new URLClassLoader(urlList,fireLoader);
+
+            extensionClass = ucl.loadClass(className);
+            if (!Extension.class.isAssignableFrom(extensionClass)) {
+                Debug.message(errorPrefix+Config.getString("extmgr.error.notsubclass"));
+                return null;
+            }
+        } catch (Throwable exc) {
+            Debug.message(errorPrefix+"Exception="+exc.getMessage());
+            exc.printStackTrace();
+            return null;
+        }
+
+        return extensionClass;
+    }
+
+    /**
+     * A ClassLoader which only finds bluej.* classes and system classes. This is used to
+     * prevent extensions from seeing other libraries which might be bundled with and used by
+     * BlueJ, so that they can use their own versions of those libraries if they wish.
+     */
+    class FirewallLoader extends ClassLoader
+    {
+        ClassLoader myParent;
+      
+        /**
+         * Constructor. Note that this classloader breaks from the delegation model; the parent
+         * is not the actual parent classloader, it is only used by findClass() below. 
+         */
+        FirewallLoader ( ClassLoader parent )
+        {
+            myParent = parent;
+        }
+
+        public Class<?> findClass(String name) throws ClassNotFoundException
+        {
+            if ( name.startsWith("bluej.") || name.startsWith("rmiextension.") || name.startsWith("greenfoot.")) {
+                return myParent.loadClass(name);
+            }
+
+            throw new ClassNotFoundException();
+        }
+    }
+  
+    /**
+     * Now, assume you have the class and you want to "instantiate" the
+     * extension You have to call this. NOTE that the extension wrapper is
+     * ALREADY UP and running. I do not return a value, you may check
+     * how this went by using the isValid() method...
+     *
+     * @param  project  The project this extension is linked to, null if none
+     */
+    void newExtension(Project aProject)
+    {
+        // It may happen
+        if (extensionClass == null)  return;
+
+        project = aProject;
+        extensionBluej = ExtensionBridge.newBluej(this, prefManager);
+
+        try {
+            extensionInstance = (Extension)extensionClass.newInstance();
+        } catch (Throwable ex) {
+            extensionInstance = null;
+            extensionStatusString = "newExtension: Exception=" + ex.getMessage();
+            return;
+        }
+
+        // Let me see if this extension is somewhat compatible...
+        if ( ! safeIsCompatible() ) {
+            extensionStatusString = Config.getString("extmgr.status.badversion");
+            extensionInstance = null;
+            return;
+        }
+
+        // Ok, time to really start everything... This MUST be here.... after all is initialised
+        safeStartup(extensionBluej);
+        extensionStatusString = Config.getString("extmgr.status.loaded");
+    }
+
+
+    /**
+     * Gets the project this extension is associated with.
+     * This happens in case of extensions loaded with a Project.
+     * If it is a system wide extension this will be null.
+     *
+     * @return    the project owning this extension.
+     */
+    Project getProject()
+    {
+        return project;
+    }
+
+
+    /**
+     *  Checks if a this extension is valid
+     *
+     * @return true if it is instantiated, false if it is not.
+     */
+    public boolean isValid()
+    {
+        return (extensionInstance != null);
+    }
+
+
+    /**
+     * Gets the jarValid attribute of the ExtensionWrapper object
+     *
+     * @return    The jarValid value
+     */
+    boolean isJarValid()
+    {
+        return (extensionClass != null);
+    }
+
+
+    /**
+     * Kills off this extension as much as possible
+     * items and making access to BlueJ no longer possible.
+     * Not only ! we are even going to release the wrapper after this.
+     * So it can be loaded again, hopefully from a clean environment
+     */
+    void terminate()
+    {
+        safeTerminate();
+
+        // Needed to signal to the revalidate (below) that this instance is no longer here.            
+        extensionInstance = null;
+
+        // Time to clean up things from the visual point of view.
+        prefManager.panelRevalidate();
+
+        // Ok, I am ready to get erased from the world.
+    }
+
+
+    /**
+     * Gets the current status of this extension.
+     *
+     * @return    something like 'Loaded' or 'Error'.
+     */
+    public String getExtensionStatus()
+    {
+        return extensionStatusString;
+    }
+
+
+    /**
+     * Gets the fully-qualified name of this extension class.
+     *
+     * @return This extension class name or null if nothing is loaded
+     */
+    public String getExtensionClassName()
+    {
+        if (extensionClass == null) {
+            return null;
+        }
+
+        return extensionClass.getName();
+    }
+
+
+    /**
+     * Tries to return a reasonable Properties instance of the extension labels
+     * It may return null if nothing reasonable can be found in the extension jar
+     * 
+     * @return the properties or null if nothing can be found
+     */
+    public Properties getLabelProperties ()
+    {
+        String localLanguage = Config.getPropString("bluej.language", Config.DEFAULT_LANGUAGE);
+
+        // Let me try to get the properties using the local language
+        Properties extensionsProps = getLabelProperties (localLanguage);
+        if ( extensionsProps != null ) return extensionsProps;
+
+        // Nothing found, let me try to get them using the default one...
+        extensionsProps = getLabelProperties (Config.DEFAULT_LANGUAGE);
+
+        return extensionsProps;
+    }
+
+    
+    /**
+     * Returns the label that are language dependents as a Properties instance
+     * 
+     * @return the equivalent properties if found, null if nothing
+     */
+    private Properties getLabelProperties (String language)
+    {
+        if ( extensionClass == null ) {
+            return null;
+        }
+
+        String languageFileName = "lib/" + language + "/labels";
+        
+        InputStream inStream = extensionClass.getClassLoader().getResourceAsStream (languageFileName);
+        if ( inStream == null ) return null;
+
+        Properties props = new Properties();
+
+        try {
+            props.load(inStream);
+        } catch(Exception ex) {
+            // Really it should never happen, if it does there is really something weird going on
+            Debug.message("ExtensionWrapper.getLabelProperties(): Exception="+ex.getMessage());
+        } 
+        closeInputStream ( inStream );
+        return props;
+    }
+
+
+    /**
+     * UFF, this is here but it really ought to be in a public util.
+     * Simply close a stream without complaining too much.
+     * Just to avoid the Nth level of try catch with no value added
+     */
+    public static void closeInputStream(InputStream aStream)
+    {
+        try {
+            aStream.close();
+        } catch ( Exception ee ) {
+            // Do nothing, really
+        }
+    }
+
+    
+    /**
+     * Gets a String representation of the path to the <CODE>.jar</CODE> file
+     * containing the extension.
+     *
+     * @return    String like <CODE>C:/bluej/lib/extensions/fun.jar</CODE> or null 
+     */
+    public String getExtensionFileName()
+    {
+        if (extensionJarFileName == null) return null;
+        return extensionJarFileName.getPath();
+    }
+
+
+    /**
+     *  Convenience method to ensure uniformity of settings items.
+     */
+    public String getSettingsString( String key)
+    {
+        return "extensions." + getExtensionClassName() + ".settings." + key;
+    }
+
+
+    /**
+     * Returns useful information about this wrapper
+     */
+    public String toString()
+    {
+        if (! isValid()) {
+            return "ExtensionWrapper: invalid";
+        }
+
+        return "ExtensionWrapper: "+ extensionClass.getName();
+    }
+
+    /* 
+     * ====================== ERROR WRAPPED CALLS HERE =========================
+     * We need to wrap all calls from BlueJ to the Extension into a try/catch;
+     * otherwise an error in the extension will render BlueJ unusable.
+     */
+
+    /**
+     * Informs any registered listeners that an event has occurred.
+     */
+    public void safeEventOccurred(ExtensionEvent event)
+    {
+        if (!isValid()) {
+            return;
+        }
+
+        try {
+            ExtensionBridge.delegateEvent(extensionBluej,event);
+        }
+        catch (Exception exc)  {
+            Debug.message("ExtensionWrapper.safeEventOccurred: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+            return;
+        }
+    }
+
+    
+    /**
+     * Returns the extension's description.
+     */
+    public String safeGetExtensionDescription()
+    {
+        if (extensionInstance == null) {
+            return null;
+        }
+
+        try {
+            return extensionInstance.getDescription();
+        }
+        catch (Exception exc)  {
+            Debug.message("ExtensionWrapper.safeGetExtensionDescription: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+            return null;
+        }
+    }
+
+    
+    /**
+     * Returns the extension's name.
+     */
+    public String safeGetExtensionName()
+    {
+        if (extensionInstance == null) 
+            return "";
+
+        try {
+            return extensionInstance.getName();
+        }
+        catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safeGetExtensionName: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+            return "";
+        }
+    }
+
+    
+    /**
+     * Gets the extension's 'further information' URL
+     *
+     * @return    the extension's URL, or <CODE>null</CODE>.
+     */
+    public URL safeGetURL()
+    {
+        if (extensionInstance == null) 
+            return null;
+
+        try {
+            return extensionInstance.getURL();
+        }
+        catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safeGetURL: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+            return null;
+        }
+    }
+
+
+    /**
+     * Gets the formal version of this extension.
+     *
+     * @return  the version of the extension
+     */
+    public String safeGetExtensionVersion()
+    {
+        if (extensionInstance == null) 
+            return null;
+
+        try {
+          return extensionInstance.getVersion();
+        }
+        catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safeGetExtensionVersion: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+            return null;
+        }
+    }
+
+
+    /**
+     * Ask the extension if it thinks it is compatible.
+     *
+     * @return  true if it is, false otherwise
+     */
+    private boolean safeIsCompatible()
+    {
+        if (extensionInstance == null) 
+            return false;
+
+        try {
+            return extensionInstance.isCompatible();
+        }
+        catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safeIsCompatible: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+            // If one bombs at me it shurely is not compatilbe 
+            return false;
+        }
+    }
+
+    
+    /**
+     * Call the startup method in a safe way
+     */
+    private void safeStartup(BlueJ bluejProxy)
+    {
+        if (extensionInstance == null) {
+            return;
+        }
+
+        try {
+            extensionInstance.startup(bluejProxy);
+        }
+        catch (Exception exc)  {
+            Debug.message("ExtensionWrapper.safeStartup: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+        }
+    }
+
+
+    /**
+     * Call the terminate method in a safe way
+     */
+    private void safeTerminate()
+    {
+        if (extensionInstance == null) {
+            return;
+        }
+
+        try {
+            // Give a chance to extension to clear up after itself.
+            extensionInstance.terminate();
+        }
+        catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safeTerminate: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+        }
+    }
+
+
+    /**
+     * Calls the EXTENSION preference panel loadValues in a safe way
+     */
+    public void safePrefGenLoadValues()
+    {
+        if (extensionBluej == null) { 
+            return;
+        }
+
+        PreferenceGenerator aPrefGen = extensionBluej.getPreferenceGenerator();
+        // The above is safe. An extension may not have a preference panel
+        if (aPrefGen == null)  {
+            return;
+        }
+
+        try {
+            aPrefGen.loadValues();
+        }
+        catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safePrefGenLoadValues: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+        }
+    }
+
+    
+    /**
+     * Calls the EXTENSION preference panel saveValues in a safe way
+     */
+    public void safePrefGenSaveValues()
+    {
+        if (extensionBluej == null) 
+            return;
+
+        PreferenceGenerator aPrefGen = extensionBluej.getPreferenceGenerator();
+        // The above is dafe. An extension may not have a preference panel
+        if (aPrefGen == null) 
+            return;
+
+        try {
+            aPrefGen.saveValues();
+        }
+        catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safePrefGenSaveValues: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+        }
+    }
+
+    
+    /**
+     *  Calls the EXTENSION preference panel getPanel in a sfe way
+     */
+    public JPanel safePrefGenGetPanel()
+    {
+        if (extensionBluej == null) 
+            return null;
+
+        PreferenceGenerator aPrefGen = extensionBluej.getPreferenceGenerator();
+        // The above is dafe. An extension may not have a preference panel
+        if (aPrefGen == null) 
+            return null;
+
+        try {
+            return aPrefGen.getPanel();
+        }
+        catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safePrefGenGetPanel: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+            return null;
+        }
+    }
+
+
+    /**
+     *  Calls the EXTENSION getMenuItem in a safe way
+     */
+    public JMenuItem safeGetMenuItem(ExtensionMenuObject attachedObject)
+    {
+        if (extensionBluej == null) 
+            return null;
+
+        try {
+            return ExtensionBridge.getMenuItem(extensionBluej, attachedObject);
+        }
+        catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safeMenuGenGetMenuItem: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     *  Calls the EXTENSION postMenuItem in a safe way
+     */
+    public void safePostMenuItem(ExtensionMenuObject attachedObject, JMenuItem onThisItem)
+    {
+        if (extensionBluej == null) 
+            return;
+
+        try {
+            ExtensionBridge.postMenuItem(extensionBluej, attachedObject, onThisItem );
+        }
+        catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safePostGenGetMenuItem: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+        }
+    }
+
+    /**
+     * Calls the extension drawExtensionClassTarget in a safe way.
+     * 
+     * @param layer
+     *            The layer of the drawing which causes the different methods of
+     *            the {@link ExtensionClassTargetPainter} instance to be called.
+     * @param bClassTarget
+     *            The class target that will be painted.
+     * @param graphics
+     *            The {@link Graphics2D} instance to draw on.
+     * @param width
+     *            The width of the area to paint.
+     * @param height
+     *            The height of the area to paint.
+     */
+    public void safeDrawExtensionClassTarget(Layer layer, BClassTarget bClassTarget,
+            Graphics2D graphics, int width, int height)
+    {
+        if (extensionBluej == null) { 
+            return;
+        }
+        
+        try {
+            ExtensionBridge.drawExtensionClassTarget(extensionBluej, layer, bClassTarget, graphics,
+                width, height);
+        } catch (Exception exc) {
+            Debug.message("ExtensionWrapper.safeDrawExtensionClassTarget: Class="+getExtensionClassName()+" Exception="+exc.getMessage());
+            exc.printStackTrace();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionsManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionsManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..ffe3d6396d1ce30ebb16eed9700913682d483d06
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ExtensionsManager.java
@@ -0,0 +1,446 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import java.awt.Graphics2D;
+import java.io.File;
+import java.util.*;
+
+import javax.swing.JFrame;
+
+import bluej.*;
+import bluej.debugmgr.ExecutionEvent;
+import bluej.extensions.BClassTarget;
+import bluej.extensions.event.*;
+import bluej.extensions.painter.ExtensionClassTargetPainter;
+import bluej.pkgmgr.*;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.graphPainter.ClassTargetPainter.Layer;
+import bluej.utility.Debug;
+import javax.swing.*;
+
+/**
+ * Manages extensions and provides the main interface to them. A
+ * singleton.
+ * 
+ * @author Clive Miller, University of Kent at Canterbury, 2002
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003
+ * @author Michael Kolling
+ */
+public class ExtensionsManager
+    implements BlueJEventListener
+{
+    private static ExtensionsManager instance;
+
+    /**
+     * Singleton factory method.
+     */
+    public static synchronized ExtensionsManager getInstance()
+    {
+        if (instance == null) {
+            instance = new ExtensionsManager();
+            instance.loadExtensions();
+        }
+        return instance;
+    }
+
+    // ============== instance part ==============
+
+    private List<ExtensionWrapper> extensions;
+    private ExtensionPrefManager prefManager = null;
+
+    /**
+     * Constructor for the ExtensionsManager object. It is private, as the
+     * ExtensionsManager is a singleton.
+     */
+    private ExtensionsManager()
+    {
+        // Sync issues should be clear...
+        extensions = new ArrayList<ExtensionWrapper>();
+
+        // This must be here, after all has been initialized.
+        BlueJEvent.addListener(this);
+    }
+
+    /**
+     * Loads extensions that are in system and user location.
+     */
+    private void loadExtensions()
+    {
+        // Most of the time the systemDirectory will be this.
+        File systemDir = new File(Config.getBlueJLibDir(), "extensions");
+
+        String dirPath = Config.getPropString("bluej.extensions.systempath", null);
+        // But we allow one to override the default location of system
+        // extension.
+        if (dirPath != null) {
+            systemDir = new File(dirPath);
+        }
+
+        // Now we try to load the extensions from the BlueJ system repository.
+        loadDirectoryExtensions(systemDir, null);
+
+        // Load extensions that are in a user space location.
+        loadDirectoryExtensions(Config.getUserConfigFile("extensions"), null);
+    }
+
+    /**
+     * Unloads all extensions that are loaded. Normally called just before BlueJ
+     * is closing.
+     */
+    public void unloadExtensions()
+    {
+        synchronized(extensions) {
+            for (Iterator<ExtensionWrapper> iter = extensions.iterator(); iter.hasNext();) {
+                ExtensionWrapper aWrapper = iter.next();
+                aWrapper.terminate();
+                iter.remove();
+            }
+        }
+    }
+
+    /**
+     * Searches through the given directory for jar files that contain a valid
+     * extension. On finding a loadable extension, try to load it.
+     * 
+     * @param directory
+     *            Where to look for extensions
+     * @param project
+     *            A project this extension is bound to, or null if
+     *            the extension is not bound to a specific project.
+     */
+    private void loadDirectoryExtensions(File directory, Project project)
+    {
+        File[] files = directory.listFiles();
+        if (files == null) {
+            return;
+        }
+
+        for (int index = 0; index < files.length; index++) {
+            File thisFile = files[index];
+
+            // We do not want to try to make sense of directories
+            if (thisFile.isDirectory())
+                continue;
+
+            // Skip also files that do not end in .jar
+            if (!thisFile.getName().endsWith(".jar"))
+                continue;
+
+            // Ok, lets try to get a wrapper up and running
+            ExtensionWrapper aWrapper = new ExtensionWrapper(getPrefManager(), thisFile);
+
+            // Loading this wrapper failed miserably, too bad...
+            if (!aWrapper.isJarValid()) {
+                continue;
+            }
+
+            // Let me see if I already have this extension loaded
+            if (isWrapperAlreadyLoaded(aWrapper)) {
+                continue;
+            }
+
+            // Now that all is nice and clean I can safely try to instantiate
+            // the extension
+            aWrapper.newExtension(project);
+
+            if (aWrapper.isValid()) {
+                synchronized (extensions) {
+                    extensions.add(aWrapper);
+                }
+            }
+        }
+        
+        // The last extension may have added a preference panel, but due to the way that is
+        // implemented the panel won't be visible as the extension wasn't in the list of
+        // valid extensions at that stage.
+        getPrefManager().panelRevalidate();
+    }
+
+    /**
+     * Checks if the loaded wrappers/extensions if is already loaded.
+     */
+    private boolean isWrapperAlreadyLoaded(ExtensionWrapper thisWrapper)
+    {
+        String thisClassName = thisWrapper.getExtensionClassName();
+        String thisJarName = thisWrapper.getExtensionFileName();
+
+        synchronized(extensions) {            
+            for (ExtensionWrapper aWrapper : extensions) {
+                String aClassName = aWrapper.getExtensionClassName();
+                if (aClassName == null) {
+                    continue;
+                }
+    
+                // Found it, this wrapper is already loaded...
+                if (thisClassName.equals(aClassName)) {
+                    Debug.message("Extension is already loaded: " + thisClassName + " jarName=" + thisJarName);
+                    return true;
+                }
+            }
+        }
+
+        // This wrapper is not already loaded in the list of wrappers/extensions
+        return false;
+    }
+
+    /**
+     * Return the preferences manager for extensions.
+     */
+    public ExtensionPrefManager getPrefManager()
+    {
+        if (prefManager == null) {
+            prefManager = new ExtensionPrefManager(extensions);
+        }
+        return prefManager;
+    }
+
+    /**
+     * Ask for extension manager to show the help dialog for extensions. This is
+     * here to be sure that the help dialog is called when extension manager is
+     * valid.
+     */
+    public void showHelp(JFrame parentFrame)
+    {
+        List<ExtensionWrapper> extensionsList = new ArrayList<ExtensionWrapper>();
+        synchronized (extensions) {
+            extensionsList.addAll(extensions);
+        }
+        new HelpDialog(extensionsList, parentFrame);
+    }
+
+    /**
+     * Searches for and loads any new extensions found in the project.
+     */
+    public void projectOpening(Project project)
+    {
+        File exts = new File(project.getProjectDir(), "extensions");
+        loadDirectoryExtensions(exts, project);
+    }
+
+    /**
+     * Inform extensions that a package has been opened
+     */
+    public void packageOpened(Package pkg)
+    {
+        delegateEvent(new PackageEvent(PackageEvent.PACKAGE_OPENED, pkg));
+    }
+
+    /**
+     * This package frame is about to be closed. The issue here is to remove the
+     * extension if this is the right time to do it.
+     */
+    public void packageClosing(Package pkg)
+    {
+        // Before removing the extension, signal that this package is closing
+        delegateEvent(new PackageEvent(PackageEvent.PACKAGE_CLOSING, pkg));
+
+        // Let's assume we are NOT going to delete the extension...
+        boolean invalidateExtension = false;
+
+        // Here comes the hard part of deciding IF to release the given
+        // wrapper/extension..
+        Project thisProject = pkg.getProject();
+
+        // Surely I cannot release anything if I don't know what I am talking
+        // about...
+        if (thisProject == null) {
+            return;
+        }
+
+        // The following CAN return null....
+        PkgMgrFrame[] frameArray = PkgMgrFrame.getAllProjectFrames(thisProject);
+        if (frameArray == null) {
+            invalidateExtension = true;
+        }
+        else {
+            invalidateExtension = frameArray.length <= 1;
+        }
+
+        // Nothing to do....
+        if (!invalidateExtension) {
+            return;
+        }
+
+        synchronized(extensions) {            
+            // I am closing the last frame of the project, time to invalidate the
+            // right extensions
+            for (Iterator<ExtensionWrapper> iter = extensions.iterator(); iter.hasNext();) {
+                ExtensionWrapper aWrapper = iter.next();
+    
+                // If the extension did not got loaded with this project skip it...
+                if (thisProject != aWrapper.getProject()) {
+                    continue;
+                }
+    
+                // The following terminated the Extension
+                aWrapper.terminate();
+                iter.remove();
+            }
+        }
+    }
+
+    /**
+     * Check whether the menus provided by this extension should not be shown for the
+     * given project.
+     * 
+     * @param onThisProject   the project to check whether menus should be shown (may be null)
+     * @param extensionProject  the project which the extension was loaded for (may be null, for
+     *                          an extension not bound to a particular project)
+     */
+    private boolean skipThisMenu(Project onThisProject, Project extensionProject)
+    {
+        // I want menus if nothing it is a sys loaded extension on an empty
+        // frame
+        if (onThisProject == null && extensionProject == null)
+            return false;
+
+        // Menu should not be generated if an extension belongs to a project
+        if (onThisProject == null && extensionProject != null)
+            return true;
+
+        // Menu should be generated if we are openieng a project and an
+        // extension is not boukd to any
+        if (onThisProject != null && extensionProject == null)
+            return false;
+
+        // now both are not null, generate a menu if they are the same.
+        if (onThisProject == extensionProject)
+            return false;
+
+        // None of the above cases, do not generate a menu
+        return true;
+    }
+
+    /**
+     * Returns a List of menus currently provided by extensions.
+     */
+    LinkedList<JMenuItem> getMenuItems(ExtensionMenuObject attachedObject, Project onThisProject)
+    {
+        LinkedList<JMenuItem> menuItems = new LinkedList<JMenuItem>();
+
+        synchronized(extensions) {                
+            for (ExtensionWrapper aWrapper : extensions) {
+                if (!aWrapper.isValid()) {
+                    continue;
+                }
+    
+                if (skipThisMenu(onThisProject, aWrapper.getProject())) {
+                    continue;
+                }
+    
+                JMenuItem anItem = aWrapper.safeGetMenuItem(attachedObject);
+                if (anItem == null) {
+                    continue;
+                }
+    
+                anItem.putClientProperty("bluej.extmgr.ExtensionWrapper", aWrapper);
+    
+                menuItems.add(anItem);
+            }
+        }
+
+        return menuItems;
+    }
+
+    /**
+     * Delegates an event to all known extensions.
+     */
+    public void delegateEvent(ExtensionEvent event)
+    {
+        synchronized(extensions) {            
+            for (ExtensionWrapper wrapper : extensions) {
+                wrapper.safeEventOccurred(event);
+            }
+        }
+    }
+
+    /**
+     * This is called back when some sort of event occurs. Depending on the
+     * event we will adapt it and send it up to the extension.
+     * 
+     * @param eventId
+     *            The event id (see BlueJEvent)
+     * @param arg
+     *            This really depends on that event is given
+     *            
+     * @see BlueJEvent
+     */
+    public void blueJEvent(int eventId, Object arg)
+    {
+        if (eventId == BlueJEvent.EXECUTION_RESULT) {
+            ExecutionEvent exevent = (ExecutionEvent) arg;
+            delegateEvent(new InvocationEvent(exevent));
+            return;
+        }
+    }
+    
+    /**
+     * Calls the extension to draw its representation of a class target.
+     * 
+     * @param layer
+     *            The layer of the drawing which causes the different methods of
+     *            the {@link ExtensionClassTargetPainter} instance to be called.
+     * @param bClassTarget
+     *            The class target that will be painted.
+     * @param graphics
+     *            The {@link Graphics2D} instance to draw on.
+     * @param width
+     *            The width of the area to paint.
+     * @param height
+     *            The height of the area to paint.
+     */
+    public void drawExtensionClassTarget(Layer layer, BClassTarget bClassTarget,
+            Graphics2D graphics, int width, int height)
+    {
+        synchronized (extensions) {
+            for (ExtensionWrapper extension : extensions) {
+                if (!extension.isValid()) {
+                    continue;
+                }
+
+                extension.safeDrawExtensionClassTarget(layer, bClassTarget, graphics, width, height);
+            }
+        }
+    }
+    
+    /**
+     * Gets the loaded extensions, for data collection purposes.
+     * 
+     * @param proj Pass a project to get the project-specific extensions,
+     *             pass null to get *only* extensions that are not project-specific
+     */
+    public List<ExtensionWrapper> getLoadedExtensions(Project proj)
+    {
+        ArrayList<ExtensionWrapper> r = new ArrayList<ExtensionWrapper>();
+        
+        for (ExtensionWrapper ext : extensions)
+        {
+            if (ext.getProject() == proj)
+            {
+                r.add(ext);
+            }
+        }
+        
+        return r;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/HelpDetailDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/HelpDetailDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..1993ea488ad52bda861e0a0ceb434828204187bf
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/HelpDetailDialog.java
@@ -0,0 +1,184 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import bluej.*;
+import bluej.utility.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.net.*;
+import javax.swing.*;
+
+/**
+ * This class can display info on a particular extension. It is not really
+ * bound to the HelpDialog and may be useful in the future.
+ *  
+ * @author Damiano Bolla, University of Kent at Canterbury, 2002,2003,2004
+ */
+class HelpDetailDialog extends EscapeDialog implements ActionListener
+{
+    private final String detailsTag = Config.getString("extmgr.details");
+    private final String systemString = Config.getString("extmgr.systemExtensionLong");
+    private final String projectString = Config.getString("extmgr.projectExtensionLong");
+    private final String locationTag = Config.getString("extmgr.details.location");
+    private final String versionTag = Config.getString("extmgr.details.version");
+    private final String urlTag = Config.getString("extmgr.details.url");
+
+    private JLabel nameField, locationField, typeField;
+    private JLabel urlField;
+    private JTextArea descriptionField;
+    private URL url;
+    private JButton closeButton;
+
+    /**
+     * Constructor
+     */
+    HelpDetailDialog(Dialog owner)
+    {
+        super(owner);
+        setTitle(detailsTag);
+        
+        JPanel mainPanel = new JPanel();
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+
+        nameField = new JLabel();
+        typeField = new JLabel();
+        locationField = new JLabel();
+
+        urlField = new JLabel();
+        urlField.setCursor(new Cursor(Cursor.HAND_CURSOR));
+        urlField.setForeground(Color.blue);
+        urlField.addMouseListener(new MouseAdapter()  {
+                public void mouseClicked(MouseEvent e) {
+                    openURL();
+                }
+            });
+
+        descriptionField = new JTextArea(4, 20);
+        descriptionField.setLineWrap(true);
+        descriptionField.setWrapStyleWord(true);
+        descriptionField.setEnabled(false);
+        descriptionField.setDisabledTextColor(Color.black);
+        descriptionField.setBackground(urlField.getBackground());
+
+        JScrollPane descriptionScroller = new JScrollPane(descriptionField);
+        descriptionScroller.setBorder(null);
+        descriptionScroller.setAlignmentX(0.0F);
+
+        mainPanel.add(nameField);
+        mainPanel.add(typeField);
+        mainPanel.add(Box.createVerticalStrut(12));
+        
+        mainPanel.add(locationField);
+        mainPanel.add(Box.createVerticalStrut(12));
+        
+        mainPanel.add(descriptionScroller);
+        mainPanel.add(Box.createVerticalStrut(12));
+
+        JPanel urlPanel = new JPanel();
+        urlPanel.setAlignmentX(0.0F);
+        urlPanel.add(new JLabel(urlTag));
+        urlPanel.add(urlField);
+        mainPanel.add(urlPanel);
+        
+        // The close button goes into a panel, to make it nice...
+        JPanel buttonPanel = new JPanel();
+        closeButton = new JButton(Config.getString("close"));
+        closeButton.addActionListener(this);
+        buttonPanel.add(closeButton);
+
+        // TIme to put the two main panels into the root pane
+        JPanel rootPane = (JPanel) getContentPane();
+        rootPane.setLayout(new BorderLayout());
+        rootPane.setBorder(BlueJTheme.dialogBorder);
+
+        rootPane.add(mainPanel, BorderLayout.CENTER);
+        rootPane.add(buttonPanel, BorderLayout.SOUTH);
+
+        // save position when window is moved
+        addComponentListener(
+            new ComponentAdapter()
+            {
+                public void componentMoved(ComponentEvent event)
+                {
+                    Config.putLocation("bluej.extmgr.helpdialog.details", getLocation());
+                }
+            });
+
+        setLocation(Config.getLocation("bluej.extmgr.helpdialog.details"));
+        pack();
+        // Do not call the setVisible
+    }
+
+
+    /**
+     *  Called when the button is pressed
+     *
+     * @param  evt  Description of the Parameter
+     */
+    public void actionPerformed(ActionEvent evt)
+    {
+        Object src = evt.getSource();
+        if (src == null) return;
+
+        if (src == closeButton) setVisible(false);
+    }
+
+    /**
+     * When a different extension is shown you call this one.
+     */
+    void updateInfo(ExtensionWrapper wrapper)
+    {
+        if (wrapper == null) return;
+
+        nameField.setText(wrapper.safeGetExtensionName() + " " + versionTag + " " 
+                          + wrapper.safeGetExtensionVersion());
+        typeField.setText((wrapper.getProject() != null) ? projectString : systemString);
+        locationField.setText(locationTag + " " + wrapper.getExtensionFileName() +
+                              " (" + wrapper.getExtensionStatus() +')');
+
+        url = wrapper.safeGetURL();
+        if (url == null)
+            urlField.setText(null);
+        else
+            urlField.setText(url.toExternalForm());
+
+        descriptionField.setText(wrapper.safeGetExtensionDescription());
+        descriptionField.setCaretPosition(0);
+
+        validate();
+        pack();
+        setVisible(true);
+    }
+
+
+    /**
+     * Description of the Method
+     */
+    private void openURL()
+    {
+        if (url == null)
+            return;
+        Utility.openWebBrowser(url.toExternalForm());
+    }
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/HelpDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/HelpDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..f31c1d2edd73ec12c8c54a695c03df3b99e85384
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/HelpDialog.java
@@ -0,0 +1,290 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import bluej.*;
+import bluej.utility.EscapeDialog;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.List;
+import javax.swing.*;
+import javax.swing.table.*;
+
+/**
+ * The Extensions Manager help panel allows the user to view current extensions.
+ *
+ * @author Clive Millaer, University of Kent at Canterbury, 2002
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003
+ */
+public class HelpDialog implements ActionListener
+{
+    private final String systemString = Config.getString("extmgr.systemExtensionShort");
+    private final String projectString = Config.getString("extmgr.projectExtensionShort");
+    private final ImageIcon infoIcon = Config.getImageAsIcon("image.extmgr.info");
+
+    private JDialog mainFrame;
+    private HelpDetailDialog detailDialog;
+    private JButton closeButton;
+    private JTable extensionsTable;
+    private ExtensionsTableModel extensionsTableModel;
+    private List<ExtensionWrapper> extensionsList;
+
+    /**
+     * Setup the UI for the dialog and event handlers for the dialog's buttons.
+     * This new version is guarantee to have a valid extension manager.
+     */
+    HelpDialog(List<ExtensionWrapper> i_extensionsList, JFrame parent)
+    {
+        extensionsList = i_extensionsList;
+    
+        extensionsTable = getExtensionTable();
+        JScrollPane extensionsPane = new JScrollPane(extensionsTable);
+
+        JPanel buttonPanel = new JPanel();
+        closeButton = new JButton(Config.getString("close"));
+        closeButton.addActionListener(this);
+        buttonPanel.add(closeButton);
+
+
+        mainFrame = new EscapeDialog(parent, Config.getString("extmgr.title"), true);
+        JPanel rootPane = (JPanel)mainFrame.getContentPane();
+        rootPane.setLayout(new BorderLayout());
+        rootPane.setBorder(BlueJTheme.dialogBorder);
+
+        rootPane.add(extensionsPane, BorderLayout.CENTER);
+        rootPane.add(buttonPanel, BorderLayout.SOUTH);
+
+        // save position when window is moved
+        mainFrame.addComponentListener(
+            new ComponentAdapter()
+            {
+                public void componentMoved(ComponentEvent event)
+                {
+                    Config.putLocation("bluej.extmgr.helpdialog", mainFrame.getLocation());
+                }
+            });
+
+        mainFrame.setLocation(Config.getLocation("bluej.extmgr.helpdialog"));
+        mainFrame.pack();
+        mainFrame.setVisible(true);
+    }
+
+
+    /**
+     *  Just to manage the close button.
+     */
+    public void actionPerformed(ActionEvent evt)
+    {
+        // We really want all of this to go away, really, not just hiding it !
+        mainFrame.dispose();
+    }
+
+
+    /**
+     *  Utility, to make code cleaner
+     */
+    private void showDetails()
+    {
+        // If no detail dialog is created then make it...
+        if (detailDialog == null) 
+            detailDialog = new HelpDetailDialog(mainFrame);
+
+        int selectedColumn = extensionsTable.getSelectedColumn();
+
+        // We want the user to click on the ICON !!!
+        if (selectedColumn != 0) 
+            return;
+
+        ExtensionWrapper aWrapper = getWrapper(extensionsTable.getSelectedRow());
+        if (aWrapper == null) 
+            return;
+        
+        detailDialog.updateInfo(aWrapper);
+    }
+
+
+    /**
+     *  Utility, to make the code clean. Returns the table that describes the
+     *  installed extensions I really would like not to set so many preferred
+     *  values...
+     *
+     * @return    The extensionTable value
+     */
+    private JTable getExtensionTable()
+    {
+        extensionsTableModel = new ExtensionsTableModel();
+
+        JTable aTable = new JTable(extensionsTableModel);
+        aTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        aTable.setPreferredScrollableViewportSize(new Dimension(400, 100));
+
+        TableColumnModel tcm = aTable.getColumnModel();
+        tcm.getColumn(0).setPreferredWidth(20);
+        tcm.getColumn(2).setPreferredWidth(250);
+
+        aTable.setRowHeight(18);
+        aTable.setRowSelectionAllowed(false);
+
+        aTable.addMouseListener(new myMouseAdapter());
+        return aTable;
+    }
+
+
+    /**
+     *  Gets the wrapper attribute of the ExtensionsTableModel object
+     *
+     * @param  index  Description of the Parameter
+     * @return        The wrapper value
+     */
+    private ExtensionWrapper getWrapper(int index)
+    {
+        // of ExtensionWrapper
+        if (index > extensionsList.size()) 
+            return null;
+
+        return (ExtensionWrapper) extensionsList.get(index);
+    }
+
+
+    /**
+     *  When a mouse is clicked I come here Maybe I can do it with the selected,
+     *  it may be easier... next release ?
+     */
+    private class myMouseAdapter extends MouseAdapter
+    {
+        /**
+         *  Description of the Method
+         *
+         * @param  e  Description of the Parameter
+         */
+        public void mouseClicked(MouseEvent e)
+        {
+            if(e.getClickCount() == 1)  
+                showDetails();
+        }
+    }
+
+    private final static String columnNames[] = {
+            " ",
+            Config.getString("extmgr.statuscolumn"),
+            Config.getString("extmgr.namecolumn"),
+            Config.getString("extmgr.typecolumn")
+    };
+
+    /**
+     *  This models the data of the table. Basically the JTable ask this class
+     *  about the data to be displayed on the screen
+     */
+    class ExtensionsTableModel extends AbstractTableModel
+    {
+        // It does not matter very much if it is not static, it is created once only
+
+        /**
+         *  Returns the rowCount attribute of the ExtensionsTableModel object
+         */
+        public int getRowCount()
+        {
+            return extensionsList.size();
+        }
+
+        /**
+         * Returns the columnCount attribute of the ExtensionsTableModel object
+         */
+        public int getColumnCount()
+        {
+            return columnNames.length;
+        }
+
+        /**
+         * Gets the columnName attribute of the ExtensionsTableModel object
+         *
+         * @param  col  Description of the Parameter
+         * @return      The columnName value
+         */
+        public String getColumnName(int col)
+        {
+            return columnNames[col];
+        }
+
+        /**
+         *  Gets the cellEditable attribute of the ExtensionsTableModel object
+         *
+         * @param  row  Description of the Parameter
+         * @param  col  Description of the Parameter
+         * @return      The cellEditable value
+         */
+        public boolean isCellEditable(int row, int col)
+        {
+            return false;
+        }
+
+        /**
+         * Gets the valueAt attribute of the ExtensionsTableModel object
+         *
+         * @param  row  Description of the Parameter
+         * @param  col  Description of the Parameter
+         * @return      The valueAt value
+         */
+        public Object getValueAt(int row, int col)
+        {
+            if (col == 0) {
+                return infoIcon;
+            }
+
+            ExtensionWrapper wrapper = getWrapper(row);
+            if (wrapper == null) {
+                return "getValueAt: ERROR: no wrapper at row=" + row + " col=" + col;
+            }
+
+            if (col == 1) {
+                return wrapper.getExtensionStatus();
+            }
+
+            if (col == 2) { 
+                return wrapper.safeGetExtensionName();
+            }
+
+            if (col == 3) {
+                return (wrapper.getProject() != null) ? projectString : systemString;
+            }
+
+            // If I throw an exception all will stop. This instead keeps going
+            return "getValueAt: ERROR at row=" + row + " col=" + col;
+        }
+
+        /**
+         * Gets the columnClass attribute of the ExtensionsTableModel object
+         *
+         * @param  col  Description of the Parameter
+         * @return      The columnClass value
+         */
+        public Class<?> getColumnClass(int col)
+        {
+            if (col == 0) {
+                return new ImageIcon().getClass();
+            }
+
+            return new String().getClass();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/MenuManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/MenuManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..117d17cb1267ded7551fa177cc8d2656dae68106
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/MenuManager.java
@@ -0,0 +1,177 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import bluej.pkgmgr.*;
+
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.JPopupMenu;
+import javax.swing.event.*;
+
+
+/**
+ * Manages the menus being added by extensions.
+ * An instance of this class is attached to each popup menu that needs to be aware of extensions menu.
+ *
+ * @author Damiano Bolla, University of Kent at Canterbury, 2003,2004,2005
+ */
+public final class MenuManager implements PopupMenuListener
+{
+    private final ExtensionsManager extMgr;
+    private final JPopupMenu.Separator menuSeparator;
+    private final JPopupMenu popupMenu;
+    private ExtensionMenuObject attachedObject;
+
+    /**
+     * Constructor for the MenuManager object.
+     *
+     * @param  aPopupMenu  The menu that extensions are attaching to.
+     */
+    public MenuManager(JPopupMenu aPopupMenu)
+    {
+        extMgr = ExtensionsManager.getInstance();
+        popupMenu = aPopupMenu;
+        popupMenu.addPopupMenuListener(this);
+        menuSeparator = new JPopupMenu.Separator();
+    }
+
+    /**
+     * Add all the menu currently available to the menu.
+     * This may be called any time BlueJ feels that the menu needs to be updated.
+     *
+     * @param  onThisProject  a specific project to look for, or null for all projects.
+     */
+    public void addExtensionMenu(Project onThisProject)
+    {
+        // Get all menus that can be possibly be generated now.
+        List<JMenuItem> menuItems = extMgr.getMenuItems(attachedObject, onThisProject);
+
+        // Retrieve all the items from the current menu
+        MenuElement[] elements = popupMenu.getSubElements();
+
+        for (int index = 0; index < elements.length; index++) {
+            JComponent aComponent = (JComponent) elements[index].getComponent();
+
+            if (aComponent == null) {
+                continue;
+            }
+
+            if (!(aComponent instanceof JMenuItem)) {
+                continue;
+            }
+
+            ExtensionWrapper aWrapper = (ExtensionWrapper) aComponent.getClientProperty(
+                    "bluej.extmgr.ExtensionWrapper");
+
+            if (aWrapper == null) {
+                continue;
+            }
+
+            popupMenu.remove(aComponent);
+        }
+
+        popupMenu.remove(menuSeparator);
+
+        // If the provided menu is empty we are done here.
+        if (menuItems.isEmpty()) {
+            return;
+        }
+
+        popupMenu.add(menuSeparator);
+
+        for (JMenuItem menuItem : menuItems) {
+            popupMenu.add(menuItem);
+        }
+    }
+
+    /**
+     * Sets the object being attached to this menu.
+     *
+     * @param  attachedTo  The new attachedObject value
+     */
+    public void setAttachedObject(ExtensionMenuObject attachedTo)
+    {
+        attachedObject = attachedTo;
+    }
+
+    /**
+     * Notify to all valid extensions that this menu Item is about to be displayed.
+     *
+     * @param  event  The associated event
+     */
+    @Override
+    public void popupMenuWillBecomeVisible(PopupMenuEvent event)
+    {
+        int itemsCount = 0;
+
+        JPopupMenu aPopup = (JPopupMenu) event.getSource();
+
+        MenuElement[] elements = aPopup.getSubElements();
+
+        for (int index = 0; index < elements.length; index++) {
+            JComponent aComponent = (JComponent) elements[index].getComponent();
+
+            if (aComponent == null) {
+                continue;
+            }
+
+            if (!(aComponent instanceof JMenuItem)) {
+                continue;
+            }
+
+            ExtensionWrapper aWrapper = (ExtensionWrapper) aComponent.getClientProperty(
+                    "bluej.extmgr.ExtensionWrapper");
+
+            if (aWrapper == null) {
+                continue;
+            }
+
+            if (!aWrapper.isValid()) {
+                popupMenu.remove(aComponent);
+
+                continue;
+            }
+
+            aWrapper.safePostMenuItem(attachedObject, (JMenuItem) aComponent);
+
+            itemsCount++;
+        }
+
+        if (itemsCount <= 0) {
+            popupMenu.remove(menuSeparator);
+        }
+    }
+
+    /*
+     * Satisfy PopupMenuListener interface
+     */
+    @Override
+    public void popupMenuWillBecomeInvisible(PopupMenuEvent event) { }
+
+    /*
+     * Satisfy PopupMenuListener interface
+     */
+    @Override
+    public void popupMenuCanceled(PopupMenuEvent event) { }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ObjectMenuObject.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ObjectMenuObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..29893c089c3d182e7b2778cfd30bef3bf35b5bc7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ObjectMenuObject.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import javax.swing.JMenuItem;
+
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.extensions.BObject;
+import bluej.extensions.ExtensionBridge;
+import bluej.extensions.MenuGenerator;
+
+/**
+ * Implementation of the {@link ExtensionMenuObject} interface for the Object
+ * menu.
+ * 
+ * @author Simon Gerlach
+ */
+public class ObjectMenuObject implements ExtensionMenuObject
+{
+    private ObjectWrapper objectWrapper;
+
+    /**
+     * Constructor. Creates a new {@link ObjectMenuObject}.
+     * 
+     * @param objectWrapper
+     *            The object which was selected by the user.
+     */
+    public ObjectMenuObject(ObjectWrapper objectWrapper)
+    {
+        this.objectWrapper = objectWrapper;
+    }
+
+    @Override
+    public JMenuItem getMenuItem(MenuGenerator menuGenerator)
+    {
+        BObject bObject = ExtensionBridge.newBObject(objectWrapper);
+        return menuGenerator.getObjectMenuItem(bObject);
+    }
+
+    @Override
+    public void postMenuItem(MenuGenerator menuGenerator, JMenuItem onThisItem)
+    {
+        BObject bObject = ExtensionBridge.newBObject(objectWrapper);
+        menuGenerator.notifyPostObjectMenu(bObject, onThisItem);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/PackageMenuObject.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/PackageMenuObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..fe56de10b23d4e0a80fbe9d3ec8ca68da0d85f99
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/PackageMenuObject.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import javax.swing.JMenuItem;
+
+import bluej.extensions.BPackage;
+import bluej.extensions.ExtensionBridge;
+import bluej.extensions.MenuGenerator;
+import bluej.pkgmgr.Package;
+
+/**
+ * Implementation of the {@link ExtensionMenuObject} interface for the Package
+ * menu.
+ * 
+ * @author Simon Gerlach
+ */
+public class PackageMenuObject implements ExtensionMenuObject
+{
+    private Package bluejPackage;
+
+    /**
+     * Constructor. Creates a new {@link PackageMenuObject}.
+     * 
+     * @param bluejPackage
+     *            The current package opened in BlueJ.
+     */
+    public PackageMenuObject(Package bluejPackage)
+    {
+        this.bluejPackage = bluejPackage;
+    }
+
+    @Override
+    public JMenuItem getMenuItem(MenuGenerator menuGenerator)
+    {
+        BPackage bPackage = ExtensionBridge.newBPackage(bluejPackage);
+        return menuGenerator.getPackageMenuItem(bPackage);
+    }
+
+    @Override
+    public void postMenuItem(MenuGenerator menuGenerator, JMenuItem onThisItem)
+    {
+        BPackage bPackage = ExtensionBridge.newBPackage(bluejPackage);
+        menuGenerator.notifyPostPackageMenu(bPackage, onThisItem);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ToolsMenuObject.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ToolsMenuObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ecb19a95eb32bef48402e20990dde1194239607
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ToolsMenuObject.java
@@ -0,0 +1,82 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import javax.swing.JMenuItem;
+
+import bluej.extensions.BPackage;
+import bluej.extensions.ExtensionBridge;
+import bluej.extensions.MenuGenerator;
+import bluej.pkgmgr.Package;
+
+/**
+ * Implementation of the {@link ExtensionMenuObject} interface for the Tools
+ * menu.
+ * 
+ * @author Simon Gerlach
+ */
+public class ToolsMenuObject implements ExtensionMenuObject
+{
+    private Package bluejPackage;
+    
+    /**
+     * Constructor. Creates a new {@link ToolsMenuObject}.
+     * 
+     * @param bluejPackage
+     *            The current package opened in BlueJ.
+     */
+    public ToolsMenuObject(Package bluejPackage)
+    {
+        this.bluejPackage = bluejPackage;
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public JMenuItem getMenuItem(MenuGenerator menuGenerator)
+    {
+        if (bluejPackage == null) {
+            JMenuItem menuItem = menuGenerator.getToolsMenuItem(null);
+
+            if (menuItem != null) {
+                return menuItem;
+            }
+
+            // Try to use the old deprecated method.
+            return menuGenerator.getMenuItem();
+        }
+
+        BPackage bPackage = ExtensionBridge.newBPackage(bluejPackage);
+        return menuGenerator.getToolsMenuItem(bPackage);
+    }
+
+    @Override
+    public void postMenuItem(MenuGenerator menuGenerator, JMenuItem onThisItem)
+    {
+        if (bluejPackage == null) {
+            // Only BPackages can be null when a menu is invoked
+            menuGenerator.notifyPostToolsMenu(null, onThisItem);
+        } else {
+            BPackage bPackage = ExtensionBridge.newBPackage(bluejPackage);
+            menuGenerator.notifyPostToolsMenu(bPackage, onThisItem);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ViewMenuObject.java b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ViewMenuObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..a97ae7585d83868f31ebfe3556bdecab0e868f54
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/extmgr/ViewMenuObject.java
@@ -0,0 +1,74 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.extmgr;
+
+import javax.swing.JMenuItem;
+
+import bluej.extensions.BPackage;
+import bluej.extensions.ExtensionBridge;
+import bluej.extensions.MenuGenerator;
+import bluej.pkgmgr.Package;
+
+/**
+ * Implementation of the {@link ExtensionMenuObject} interface for the View
+ * menu.
+ * 
+ * @author Simon Gerlach
+ */
+public class ViewMenuObject implements ExtensionMenuObject
+{
+    private Package bluejPackage;
+
+    /**
+     * Constructor. Creates a new {@link ViewMenuObject}.
+     * 
+     * @param bluejPackage
+     *            The current package opened in BlueJ.
+     */
+    public ViewMenuObject(Package bluejPackage)
+    {
+        this.bluejPackage = bluejPackage;
+    }
+
+    @Override
+    public JMenuItem getMenuItem(MenuGenerator menuGenerator)
+    {
+        if (bluejPackage == null) {
+            return menuGenerator.getViewMenuItem(null);
+        }
+
+        BPackage bPackage = ExtensionBridge.newBPackage(bluejPackage);
+        return menuGenerator.getViewMenuItem(bPackage);
+    }
+
+    @Override
+    public void postMenuItem(MenuGenerator menuGenerator, JMenuItem onThisItem)
+    {
+        if (bluejPackage == null) {
+            // Only BPackages can be null when a menu is invoked
+            menuGenerator.notifyPostViewMenu(null, onThisItem);
+        } else {
+            BPackage bPackage = ExtensionBridge.newBPackage(bluejPackage);
+            menuGenerator.notifyPostViewMenu(bPackage, onThisItem);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Edge.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Edge.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6d8d45aab514b305f9cf04c59b0157094c06082
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Edge.java
@@ -0,0 +1,40 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+/**
+ * A superclass for all kinds of edges in th graph.
+ * 
+ * @version $Id: Edge.java 6215 2009-03-30 13:28:25Z polle $ *
+ * @author Michael Cahill
+ */
+public abstract class Edge extends SelectableGraphElement
+{
+    public Vertex from, to;
+
+    public Edge(Vertex from, Vertex to)
+    {
+        this.from = from;
+        this.to = to;
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Graph.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Graph.java
new file mode 100644
index 0000000000000000000000000000000000000000..8b64289c5fdb0cbb6d47e2178d06b30d00020731
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Graph.java
@@ -0,0 +1,235 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.geom.Area;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A superclass representing a general graph structure. The graph consists of
+ * vertices and edges. All three classes (Graph, Vertex, Edge) should be
+ * subclassed to create a specific graph implementation.
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ */
+public abstract class Graph
+{
+    private static final int RIGHT_PLACEMENT_MIN = 300;
+    private static final int WHITESPACE_SIZE = 10;
+    
+    private List<GraphListener> listeners = new ArrayList<GraphListener>();
+
+    /**
+     * Return an iterator over the vertices in this graph.
+     */
+    public abstract Iterator<? extends Vertex> getVertices();
+
+    /**
+     * Return an iterator over the edges in this graph.
+     */
+    public abstract Iterator<? extends Edge> getEdges();
+
+    /**
+     * Return the minimum size of this graph. The minimum size depends on the
+     * position of the elements in this graph. It is calculated so that all
+     * graph elements are visible within it.
+     * 
+     * @return The minimum size.
+     */
+    public Dimension getMinimumSize()
+    {
+        int minWidth = 1;
+        int minHeight = 1;
+
+        for (Iterator<? extends Vertex> it = getVertices(); it.hasNext();) {
+            Vertex v = (Vertex) it.next();
+
+            if (v.getX() + v.getWidth() > minWidth)
+                minWidth = v.getX() + v.getWidth();
+            if (v.getY() + v.getHeight() > minHeight)
+                minHeight = v.getY() + v.getHeight();
+        }
+
+        return new Dimension(minWidth + 20, minHeight + 20); // add some space
+                                                             // for looks
+    }
+
+    /**
+     * Position the given vertex nicely in the graph. Thsi usually means that it
+     * will be placed somewhere near the top where it does not overlap with
+     * existing vertices.
+     * 
+     * @param t
+     *            The vertex to place.
+     */
+    public void findSpaceForVertex(Vertex t)
+    {
+        Area a = new Area();
+
+        for (Iterator<? extends Vertex> it = getVertices(); it.hasNext();) {
+            Vertex vertex = it.next();
+
+            // lets discount the vertex we are adding from the space
+            // calculations
+            if (vertex != t) {
+                Rectangle vr = new Rectangle(vertex.getX(), vertex.getY(), vertex.getWidth(), vertex.getHeight());
+                a.add(new Area(vr));
+            }
+        }
+
+        Dimension min = getMinimumSize();
+
+        if (RIGHT_PLACEMENT_MIN > min.width)
+            min.width = RIGHT_PLACEMENT_MIN;
+
+        Rectangle targetRect = new Rectangle(t.getWidth() + WHITESPACE_SIZE * 2, t.getHeight() + WHITESPACE_SIZE * 2);
+
+        for (int y = 0; y < (2 * min.height); y += 10) {
+            for (int x = 0; x < (min.width - t.getWidth() - 2 * WHITESPACE_SIZE); x += 10) {
+                targetRect.setLocation(x, y);
+                if (!a.intersects(targetRect)) {
+                    t.setPos(x + 10, y + 10);
+                    return;
+                }
+            }
+        }
+
+        t.setPos(10, min.height + 10);
+    }
+
+    /**
+     * Finds the graphElement that covers the coordinate x,y. If no element is
+     * found, null is returned. If a Vertex and an Edge both cover (x,y) the
+     * Vertex will be returned.
+     * 
+     * @param x
+     *            The x coordinate of the point to check
+     * @param y
+     *            The x coordinate of the point to check
+     * @return A graph element at this point, or null.
+     */
+    public SelectableGraphElement findGraphElement(int x, int y)
+    {
+        SelectableGraphElement element = findVertex(x, y);
+
+        if (element == null) {
+            element = findEdge(x, y);
+        }
+        return element;
+    }
+
+    /**
+     * Finds the Edge that covers the coordinate x,y and is visible. If no
+     * (visible) edge is found, null is returned.
+     * 
+     * @param x
+     *            the x coordinate
+     * @param y
+     *            the y coordinate
+     * @return an edge at that position, or null
+     */
+    private Edge findEdge(int x, int y)
+    {
+        Edge element = null;
+        for (Iterator<? extends Edge> it = getEdges(); it.hasNext();) {
+            element = it.next();
+            if (element.isVisible() && element.contains(x, y)) {
+                return element;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds the Vertex that covers the coordinate x,y and is visible. If no
+     * (visible) vertex is found, null is returned.
+     * 
+     * @param x
+     *            the x coordinate
+     * @param y
+     *            the y coordinate
+     * @return a vertex at that position, or null
+     */
+    private Vertex findVertex(int x, int y)
+    {
+        Vertex element = null;
+        Vertex topElement = null;
+
+        //Try to find a vertex containing the point
+        // Rather than breaking when we find the vertex we keep searching
+        // which will therefore find the LAST vertex containing the point
+        // This turns out to be the vertex which is rendered at the front
+        for (Iterator<? extends Vertex> it = getVertices(); it.hasNext();) {
+            element = it.next();
+            if (element.isVisible() && element.contains(x, y)) {
+                topElement = element;
+            }
+        }
+        return topElement;
+    }
+    
+    /**
+     * Add a listener to be notified of graph events.
+     */
+    public void addListener(GraphListener listener)
+    {
+        listeners.add(listener);
+    }
+    
+    /**
+     * Detach a graph listener.
+     */
+    public void removeListener(GraphListener listener)
+    {
+        listeners.remove(listener);
+    }
+    
+    /**
+     * Notify listeners that a vertex has been removed.
+     */
+    protected void removedSelectableElement(SelectableGraphElement vertex)
+    {
+        Iterator<GraphListener> i = listeners.iterator();
+        while (i.hasNext()) {
+            GraphListener listener = (GraphListener) i.next();
+            listener.selectableElementRemoved(vertex);
+        }
+    }
+    
+    /**
+     * Notify listeners that the graph has changed in an
+     * unspecified way.
+     */
+    protected void graphChanged()
+    {
+        Iterator<GraphListener> i = listeners.iterator();
+        while (i.hasNext()) {
+            GraphListener listener = (GraphListener) i.next();
+            listener.graphChanged();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphEditor.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphEditor.java
new file mode 100644
index 0000000000000000000000000000000000000000..a5a9004484a47e27d8051777bd784d945dd7e425
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphEditor.java
@@ -0,0 +1,266 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+
+import javax.swing.JComponent;
+
+import bluej.Config;
+import bluej.pkgmgr.graphPainter.GraphPainterStdImpl;
+
+/**
+ * Component to allow editing of general graphs.
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ * @version $Id: GraphEditor.java 9013 2011-06-17 08:35:30Z mik $
+ */
+public class GraphEditor extends JComponent
+    implements MouseMotionListener, GraphListener
+{
+    protected final Color envOpColour = Config.ENV_COLOUR;
+    
+    private final static Cursor handCursor = new Cursor(Cursor.HAND_CURSOR);
+    private final static Cursor defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR);
+    private final static Cursor resizeCursor = new Cursor(Cursor.SE_RESIZE_CURSOR);
+
+    /**  The grid resolution for graph layout. */
+    public static final int GRID_SIZE = 10;
+
+    private Graph graph;
+    private GraphPainter graphPainter;
+    private MarqueePainter marqueePainter;
+
+    private SelectionController selectionController;
+
+    private Cursor currentCursor = defaultCursor;  // currently shown cursor
+    
+    /**
+     * Create a graph editor.
+     * @param graph The graph being edited by this editor.
+     */
+    public GraphEditor(Graph graph)
+    {
+        this.graph = graph;
+        marqueePainter = new MarqueePainter();
+        graphPainter = GraphPainterStdImpl.getInstance();
+        selectionController = new SelectionController(this);
+        graph.addListener(this);
+        setToolTipText(""); // Turn on tool-tips for this component
+    }
+
+    /**
+     * Start our mouse listener. This is not done in the constructor, because we want 
+     * to give others (the PkgMgrFrame) the chance to listen first.
+     */
+    public void startMouseListening()
+    {
+        addMouseMotionListener(this);
+        addMouseMotionListener(selectionController);
+        addMouseListener(selectionController);
+        addKeyListener(selectionController);
+    }
+    
+    
+    /**
+     * Tell how big we would like to be. The preferred size of the graph editor
+     * the the size of the edited graph.
+     */
+    @Override
+    public Dimension getPreferredSize()
+    {
+        return graph.getMinimumSize();
+    }
+
+    /**
+     * Tell how big we would like to be. The minimum size of the graph editor
+     * the the size of the edited graph.
+     */
+    @Override
+    public Dimension getMinimumSize()
+    {
+        return graph.getMinimumSize();
+    }
+
+    /**
+     * Paint this graph editor (this may be on screen or on a printer).
+     */
+    @Override
+    public void paint(Graphics g)
+    {
+        Graphics2D g2D = (Graphics2D) g;
+        //draw background
+        if (!(g2D instanceof PrintGraphics)) {
+            Dimension d = getSize();
+            GradientPaint gp = new GradientPaint(
+                    d.width/4, 0, new Color(253,253,250),
+                    d.width*3/4, d.height, new Color(241,231,196));
+
+            g2D.setPaint(gp);
+            g2D.fillRect(0, 0, d.width, d.height);
+        }
+
+        graphPainter.paint(g2D, this);
+        marqueePainter.paint(g2D, selectionController.getMarquee());
+
+//        super.paint(g); // for border
+    }
+
+    // ---- MouseMotionListener interface: ----
+
+    /**
+     * The mouse was dragged.
+     */
+    public void mouseDragged(MouseEvent evt)
+    {
+    }
+
+    /**
+     * The mouse was moved - check whether we should adjust the cursor.
+     */
+    public void mouseMoved(MouseEvent evt)
+    {
+        int x = evt.getX();
+        int y = evt.getY();
+        SelectableGraphElement element = graph.findGraphElement(x, y);
+        Cursor newCursor = defaultCursor;
+        if (element != null) {
+            if (element.isResizable() && element.isHandle(x, y)) {
+                newCursor = resizeCursor;
+            }
+            else {
+                newCursor = handCursor;                
+            }
+        }
+        if(currentCursor != newCursor) {
+            setCursor(newCursor);
+            currentCursor = newCursor;
+        }
+    }
+
+    // ---- end of MouseMotionListener interface ----
+
+    /**
+     * Process mouse events. This is a bug work-around: we prefer to handle the 
+     * mouse events in the mouse listener methods in the selection controller, 
+     * but on Windows the isPopupTrigger flag is not correctly set in the 
+     * mousePressed event. This method seems to be the only place to reliably get 
+     * it. So unfortunately, we need to process the popup trigger here.
+     * 
+     * This method is called after the corresponding mousePressed method.
+     */
+    @Override
+    protected void processMouseEvent(MouseEvent evt)
+    {
+        super.processMouseEvent(evt);
+        if (evt.isPopupTrigger())
+            selectionController.handlePopupTrigger(evt);
+    }
+
+
+    /**
+     * Clear the set of selected classes. (Nothing will be selected after this.)
+     */
+    public void clearSelection()
+    {
+        selectionController.clearSelection();
+    }
+
+    /**
+     * Clear the current selection.
+     */
+    public void removeFromSelection(SelectableGraphElement element)
+    {
+        selectionController.removeFromSelection(element);
+    }
+    
+    /**
+     * Add to the current selection
+     * @param element the element to add
+     */
+    public void addToSelection(SelectableGraphElement element)
+    {
+        selectionController.addToSelection(element);
+    }
+    
+   
+    /**
+     * Return the rubber band information.
+     */
+    public RubberBand getRubberBand()
+    {
+        return selectionController.getRubberBand();
+    }
+
+    /**
+     * Return the graph currently being edited.
+     */
+    public Graph getGraph()
+    {
+        return graph;
+    }
+
+    public void popupMenu(int x, int y)
+    {
+        // by default, do nothing
+    }
+
+    private boolean hasFocus;
+    
+    @Override
+    public boolean hasFocus(){
+        return hasFocus;
+    }
+    
+    public void setHasFocus(boolean hasFocus){
+        this.hasFocus = hasFocus;
+    }
+    
+    @Override
+    public String getToolTipText(MouseEvent event)
+    {
+        int x = event.getX();
+        int y = event.getY();
+        SelectableGraphElement element = graph.findGraphElement(x, y);
+        
+        if (element == null) {
+            return null;
+        } else {
+            return element.getTooltipText();
+        }
+    }    
+    
+    // ---- GraphListener interface ----
+    
+    public void selectableElementRemoved(SelectableGraphElement element)
+    {
+        removeFromSelection(element);
+    }
+    
+    public void graphChanged()
+    {
+        repaint();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphElement.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..965697e26c83371314a639d0cff91d1f7dbd1c1f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphElement.java
@@ -0,0 +1,88 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.event.MouseEvent;
+
+/**
+ * An element in a Graph
+ * @author fisker
+ * 
+ */
+public abstract class GraphElement {
+    /** Indicates whether this element shall be visible in the graph. */
+    private boolean visible = true;
+    
+    /**
+     * Remove this element from the graph.
+     */
+    abstract public void remove();
+    
+    /**
+     * Subtypes of Graph elements must override this if it want GraphEditor
+     * to be able to locate them. Only classes that can not be selected and that
+     * doesn't have a popupmenu can made due with the default behavior.
+     * @return
+     */
+    abstract public boolean contains(int x, int y);
+    
+    /**
+     * A double click was done on this element.
+     */
+    public void doubleClick(MouseEvent evt) {}
+
+    /**
+     * Post the context menu for this target.
+     */
+    abstract public void popupMenu(int x, int y, GraphEditor graphEditor);
+    
+    /**
+     * Get the text to display as a tool tip when the user hovers over this element
+     * @return null for no tool-tip, otherwise return the text
+     */
+    public String getTooltipText()
+    {
+        return null;
+    }
+    
+    /**
+     * Indicates whether this element shall be visible in the graph.
+     * 
+     * @return <code>true</code> if the element is visible, <code>false</code>
+     *         otherwise.
+     */
+    public boolean isVisible()
+    {
+        return visible;
+    }
+
+    /**
+     * Sets the visible setting of this element.
+     * 
+     * @param visible
+     *            The new visible setting.
+     */
+    public void setVisible(boolean visible)
+    {
+        this.visible = visible;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b572bb62b1d79218bbd931201ff13468899f883
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphListener.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+/**
+ * An interfacing for receiving events from a Graph.
+ * 
+ * @author davmac
+ * @version $Id: GraphListener.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface GraphListener
+{
+    /**
+     * A vertex was removed from the graph.
+     */
+    public void selectableElementRemoved(SelectableGraphElement element);
+    
+    /**
+     * General notification that the graph has changed.
+     */
+    public void graphChanged();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d54ff2123d9ccd5b1740d8523f85070d6dd5457
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/GraphPainter.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.Graphics2D;
+
+/**
+ * Interface for GraphPainters
+ * @author fisker
+ * @version $Id: GraphPainter.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface GraphPainter
+{
+    /**
+     * Paint the given graph editor on screen.
+     * @param g  The graphics contect to paint on.
+     * @param graphEditor  The editor to be painted.
+     */
+    void paint(Graphics2D g, GraphEditor graphEditor);
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Marquee.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Marquee.java
new file mode 100644
index 0000000000000000000000000000000000000000..c20943ed2b09a1abd2e3a27498620243f84a60a2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Marquee.java
@@ -0,0 +1,131 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.*;
+import java.util.*;
+
+/**
+ * The diagram's marquee (a rectangular drag area for selecting graph elements).
+ * 
+ * @author fisker
+ * @author Michael Kolling
+ */
+public final class Marquee
+{
+    private Graph graph;
+    private int drag_start_x, drag_start_y;
+    private Rectangle currentRect;
+    private SelectionSet selected = null;
+
+    /**
+     * Create a marquee for a given graph.
+     */
+    public Marquee(Graph graph)
+    {
+        this.graph = graph;
+    }
+
+    /**
+     * Start a marquee selection at point x, y.
+     */
+    public void start(int x, int y)
+    {
+        drag_start_x = x;
+        drag_start_y = y;
+        selected = new SelectionSet();
+    }
+
+    /**
+     * Place the marquee from its starting point to the coordinate (drag_x,
+     * drag_y). The marquee must have been started before this method is called.
+     * 
+     * @param drag_x  The x coordinate of the current drag position 
+     * @param drag_y  The y coordinate of the current drag position 
+     * @return  The set of graph elements selected by this marquee
+     */
+    public void move(int drag_x, int drag_y)
+    {
+        int x = drag_start_x;
+        int y = drag_start_y;
+        int w = drag_x - drag_start_x;
+        int h = drag_y - drag_start_y;
+        //Rectangle can't handle negative numbers, modify coordinates
+        if (w < 0)
+            x = x + w;
+        if (h < 0)
+            y = y + h;
+        w = Math.abs(w);
+        h = Math.abs(h);
+        currentRect = new Rectangle(x, y, w, h);
+
+        findSelectedVertices(x, y, w, h);
+    }
+
+    
+    /**
+     * Find, and add, all vertices that intersect the specified area.
+     */
+    private void findSelectedVertices(int x, int y, int w, int h)
+    {
+        //clear the currently selected
+        selected.clear();
+
+        //find the intersecting vertices
+        for (Iterator<? extends Vertex> it = graph.getVertices(); it.hasNext();) {
+            Vertex v = it.next();
+            if (v.getRectangle().intersects(x, y, w, h)) {
+                selected.add(v);
+            }
+        }
+    }
+
+    /**
+     * Stop a current marquee selection.
+     */
+    public SelectionSet stop()
+    {
+        currentRect = null;
+        SelectionSet tmp = selected;
+        selected = null;
+        return tmp;
+    }
+
+    /**
+     * Tell whether this marquee is currently active.
+     */
+    public boolean isActive()
+    {
+        return selected != null;
+    }
+    
+    /**
+     * Return the currently visible rectangle of this marquee.
+     * If the marquee is not currently drawn, return null.
+     * 
+     * @return The marquee's rectangle, or null if not visible.
+     */
+    public Rectangle getRectangle()
+    {
+        return currentRect;
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/MarqueePainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/MarqueePainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fe3e0899670d254d2549723b427f6aff41b5d4e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/MarqueePainter.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.*;
+import java.awt.Graphics2D;
+
+/**
+ * Paints a marquee
+ * 
+ * @author fisker
+ * @version $Id: MarqueePainter.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public final class MarqueePainter
+{
+    private static final Color tc = new Color(100, 100, 100, 20);
+    private Rectangle marqRect;
+
+    /**
+     * Paint the given marquee on the specified graphics context.
+     */
+    public void paint(Graphics2D g, Marquee marquee)
+    {
+        marqRect = marquee.getRectangle();
+        if (marqRect != null) {
+            g.setColor(Color.black);
+            g.draw(marqRect);
+            g.setColor(tc);
+            g.fill(marqRect);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Moveable.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Moveable.java
new file mode 100644
index 0000000000000000000000000000000000000000..dbe8993f7563c22d791ce5470ac2734a01a2336f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Moveable.java
@@ -0,0 +1,91 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+/**
+ * @author fisker
+ *
+  */
+public interface Moveable
+{
+    /**
+     * Return the current x coordinate.
+     */
+    public int getX();
+
+    /**
+     * Return the current y coordinate.
+     */
+    public int getY();
+    
+    /**
+     * @return Returns the ghostX.
+     */
+    public int getGhostX();
+    
+    /**
+     * @return Returns the ghostX.
+     */
+    public int getGhostY();
+    
+    /**
+     * Set the position of the ghost image given a delta to the real size.
+     */
+    public void setGhostPosition(int deltaX, int deltaY);
+
+    /**
+     * Set the size of the ghost image.
+     */
+    public void setGhostSize(int ghostWidth, int ghostHeight);
+
+    /**
+     * Set the target's position to its ghost position.
+     */
+    public void setPositionToGhost();
+    
+    /** 
+     * Ask whether we are currently dragging. 
+     */
+    public boolean isDragging();
+    
+    /**
+     * Set whether or not we are currently dragging this class
+     * (either moving or resizing).
+     */
+    public void setDragging(boolean isDragging);
+    
+    /**
+     * Tell whether this element is indeed currently moveable.
+     */
+    public boolean isMoveable();
+    
+    /**
+     * Specify whether this element is indeed currently moveable.
+     */
+    public void setIsMoveable(boolean isMoveable);
+
+    /**
+     * Tell whether this element is resizable.
+     */
+    public boolean isResizable();
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/RubberBand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/RubberBand.java
new file mode 100644
index 0000000000000000000000000000000000000000..51b1f0b415c3476f000b9d12d7469669b099000c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/RubberBand.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.Point;
+
+/**
+ * Class RubberBand describes a rubber line used during line dragging.
+ * The line always extends from a source target to a given end point.
+ */
+
+public class RubberBand 
+{
+    /** The line's start point */
+    public Point startPt;
+    /** The line's end point */
+    public Point endPt;
+
+    /**
+     * Create a rubber band description, giving coordinates of start
+     * and end points.
+     */
+    public RubberBand(int x1, int y1, int x2, int y2)
+    {
+        startPt = new Point(x1, y1);
+        endPt = new Point(x2, y2);
+    }
+
+    /**
+     * Adjust the rubber band's current end point.
+     * @param x  New end point x coordinate
+     * @param y  New end point y coordinate
+     */
+    public void setEnd(int x, int y)
+    {
+        endPt.move(x, y);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Selectable.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Selectable.java
new file mode 100644
index 0000000000000000000000000000000000000000..e865ec4f3377cecbabfba0473ad7331d98e97c67
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Selectable.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+
+/**
+ * Implemented by GraphElements that is selectable
+ * @author fisker
+ * @version $Id: Selectable.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface Selectable 
+{
+    //selection
+    void setSelected(boolean selected);
+    boolean isSelected();
+    
+    //resizing
+    boolean isHandle(int x, int y);
+    boolean isResizable();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/SelectableGraphElement.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/SelectableGraphElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..05a01576eb69b5ef8fff93bdf3ca881fcf1e49b0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/SelectableGraphElement.java
@@ -0,0 +1,31 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+/**
+ * Superclass for all selectable graph elements (that's all of them
+ * right now).
+ */
+public abstract class SelectableGraphElement extends GraphElement
+    implements Selectable
+{
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/SelectionController.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/SelectionController.java
new file mode 100644
index 0000000000000000000000000000000000000000..f89f2832a16cfdb64c5010b05fd3b69233a844d7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/SelectionController.java
@@ -0,0 +1,624 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.util.List;
+import java.util.Iterator;
+
+import bluej.Config;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.graphPainter.GraphPainterStdImpl;
+import bluej.pkgmgr.target.*;
+import bluej.pkgmgr.Package;
+
+/**
+ * This class controls the selection (the set of selected elements in the graph).
+ * To do this, it maintains a selection set, a marquee (a graphical selection rectangle)
+ * and a rubber band (for drawing new edges). Both the marquee and the rubber band can
+ * be inactive.
+ */
+public class SelectionController
+    implements MouseListener, MouseMotionListener, KeyListener
+{
+    private GraphEditor graphEditor;
+    private Graph graph;
+    
+    private Marquee marquee; 
+    private SelectionSet selection;   // Contains the elements that have been selected
+    private RubberBand rubberBand;
+    
+    private boolean moving = false; 
+    private boolean resizing = false; 
+
+    private int dragStartX;
+    private int dragStartY;
+
+    private int keyDeltaX;
+    private int keyDeltaY;
+
+    private int currentDependencyIndex;  // for cycling through dependencies
+
+    private TraverseStragegy traverseStragegiImpl = new TraverseStragegyImpl();
+
+    
+    /**
+     * Create the controller for a given graph editor.
+     * @param graphEditor
+     * @param graph
+     */
+    public SelectionController(GraphEditor graphEditor)
+    {
+        this.graphEditor = graphEditor;
+        this.graph = graphEditor.getGraph();
+        marquee = new Marquee(graph);
+        selection = new SelectionSet();
+
+    }
+
+    // ======= MouseListener interface =======
+
+    /**
+     * A mouse-pressed event. Analyse what we should do with it.
+     */
+    public void mousePressed(MouseEvent evt)
+    {
+        graphEditor.requestFocus();
+        int clickX = evt.getX();
+        int clickY = evt.getY();
+
+        SelectableGraphElement clickedElement = graph.findGraphElement(clickX, clickY);
+        notifyPackage(clickedElement);
+        
+        if (clickedElement == null) {                           // nothing hit
+            if (!isMultiselectionKeyDown(evt)) {
+                selection.clear();
+            }
+            if (isButtonOne(evt))
+                marquee.start(clickX, clickY);
+        }
+        else if (isButtonOne(evt)) {                            // clicked on something
+            if (isMultiselectionKeyDown(evt)) {
+                // a class was clicked, while multiselectionKey was down.
+                if (clickedElement.isSelected()) {
+                    selection.remove(clickedElement);
+                }
+                else {
+                    selection.add(clickedElement);
+                }
+            }
+            else {
+                // a class was clicked without multiselection
+                if (! clickedElement.isSelected()) {
+                    selection.selectOnly(clickedElement);
+                }
+            }
+
+            if(isDrawingDependency()) {
+                if (clickedElement instanceof Target)
+                    rubberBand = new RubberBand(clickX, clickY, clickX, clickY);
+            }
+            else {
+                dragStartX = clickX;
+                dragStartY = clickY;
+
+                if(clickedElement.isHandle(clickX, clickY)) {
+                    resizing = true;
+                }
+                else {
+                    moving = true;                        
+                }
+            }
+        }
+    }
+
+    /**
+     * The mouse was released.
+     */
+    public void mouseReleased(MouseEvent evt)
+    {
+        if (isDrawingDependency()) {
+            SelectableGraphElement selectedElement = graph.findGraphElement(evt.getX(), evt.getY());
+            notifyPackage(selectedElement);
+            graphEditor.repaint();
+        }
+        rubberBand = null;
+        
+        SelectionSet newSelection = marquee.stop();     // may or may not have had a marquee...
+        if(newSelection != null) {
+            selection.addAll(newSelection);
+            graphEditor.repaint();
+        }
+        
+        if(moving || resizing) {
+            endMove();
+            graphEditor.revalidate();
+            graphEditor.repaint();
+        }
+    }
+    
+    /**
+     * A mouse-clicked event. This is only interesting if it was a double
+     * click. If so, inform every element in the current selection.
+     */
+    public void mouseClicked(MouseEvent evt)
+    {
+        if (isButtonOne(evt)) {
+            if (evt.getClickCount() > 1) {
+                selection.doubleClick(evt);
+            }
+        }
+    }
+
+    /**
+     * The mouse pointer entered this component.
+     */
+    public void mouseEntered(MouseEvent e) {}
+
+    /**
+     * The mouse pointer exited this component.
+     */
+    public void mouseExited(MouseEvent e) {}
+
+    // ======= end of MouseListener interface =======
+
+    // ======= MouseMotionListener interface: =======
+
+    /**
+     * The mouse was moved - not interested here.
+     */
+    public void mouseMoved(MouseEvent evt) {}
+
+    /**
+     * The mouse was dragged - either draw a marquee or move some classes.
+     */
+    public void mouseDragged(MouseEvent evt)
+    {
+        if (isButtonOne(evt)) {
+            if (marquee.isActive()) {
+                Rectangle oldRect = marquee.getRectangle();                
+                marquee.move(evt.getX(), evt.getY());
+                Rectangle newRect = (Rectangle) marquee.getRectangle().clone();  
+                if(oldRect != null) {
+                    newRect.add(oldRect);
+                }
+                newRect.width++;
+                newRect.height++;
+                graphEditor.repaint(newRect);
+            }
+            else if (rubberBand != null) {
+                rubberBand.setEnd(evt.getX(), evt.getY());
+                graphEditor.repaint();
+            }
+            else 
+            {
+                if(! selection.isEmpty()) {
+                    int deltaX = snapToGrid(evt.getX() - dragStartX);
+                    int deltaY = snapToGrid(evt.getY() - dragStartY);
+    
+                    if(resizing) {
+                        selection.resize(deltaX, deltaY);
+                    }
+                    else if (moving) {
+                        selection.move(deltaX, deltaY);
+                    }
+                }
+                graphEditor.repaint();
+            }
+        }
+    }
+
+    // ======= end of MouseMotionListener interface =======
+
+    // ======= KeyListener interface =======
+
+    /**
+     * A key was pressed in the graph editor.
+     */
+    public void keyPressed(KeyEvent evt)
+    {
+        boolean handled = true; // assume for a start that we are handling the
+                                // key here
+
+        if (isArrowKey(evt)) {
+            if (evt.isControlDown()) {      // resizing
+                if(!resizing)
+                    startKeyboardResize();
+                setKeyDelta(evt);
+                selection.resize(keyDeltaX, keyDeltaY);
+            }
+            else if (evt.isShiftDown()) {   // moving targets
+                if(!moving)
+                    startKeyboardMove();
+                setKeyDelta(evt);
+                selection.move(keyDeltaX, keyDeltaY);
+            }
+            else {                          // navigate the diagram
+                navigate(evt);
+            }
+        }
+
+        else if (isPlusOrMinusKey(evt)) {
+            resizeWithFixedRatio(evt);
+        }
+
+        // dependency selection
+        else if (evt.getKeyCode() == KeyEvent.VK_PAGE_UP || evt.getKeyCode() == KeyEvent.VK_PAGE_DOWN) {
+            selectDependency(evt);
+        }
+
+        // post context menu
+        else if (evt.getKeyCode() == KeyEvent.VK_SPACE || evt.getKeyCode() == KeyEvent.VK_ENTER) {
+            postMenu();
+        }
+
+        // 'A' (with any or no modifiers) selects all
+        else if (evt.getKeyCode() == KeyEvent.VK_A) {
+            selectAll();
+        }
+
+        // Escape removes selections
+        else if (evt.getKeyCode() == KeyEvent.VK_ESCAPE) {
+            if(moving || resizing) {
+                endMove();
+            }
+            clearSelection();
+        }
+
+        else {
+            handled = false;
+        }
+
+        if (handled)
+            evt.consume();
+
+        graphEditor.repaint();
+    }
+
+    
+    /**
+     * A key was released. Check whether a key-based move or resize operation
+     * has ended.
+     */
+    public void keyReleased(KeyEvent evt)
+    {
+        if(moving && (!evt.isShiftDown())) {    // key-based moving stopped
+            selection.moveStopped();
+            moving = false;
+        }
+        else if(resizing && (!evt.isControlDown())) {    // key-based moving stopped
+            selection.moveStopped();
+            resizing = false;
+        }
+        graphEditor.repaint();
+    }
+
+    /**
+     * Key typed - of no interest to us.
+     */
+    public void keyTyped(KeyEvent evt) {}
+
+    // ======= end of KeyListener interface =======
+
+
+    private void notifyPackage(GraphElement element)
+    {
+        if(element instanceof ClassTarget)
+            ((Package)graph).targetSelected((Target)element);
+        else
+            ((Package)graph).targetSelected(null);
+    }
+    
+    /**
+     * Tell whether the package is currently drawing a dependency.
+     */
+    public boolean isDrawingDependency()
+    {
+        return (((Package)graph).getState() == Package.S_CHOOSE_USES_TO)
+                || (((Package)graph).getState() == Package.S_CHOOSE_EXT_TO);
+    }
+
+    
+    private static boolean isArrowKey(KeyEvent evt)
+    {
+        return evt.getKeyCode() == KeyEvent.VK_UP || evt.getKeyCode() == KeyEvent.VK_DOWN
+                || evt.getKeyCode() == KeyEvent.VK_LEFT || evt.getKeyCode() == KeyEvent.VK_RIGHT;
+    }
+
+    /**
+     * Move the current selection to another selected class, depending on
+     * current selection and the key pressed.
+     */
+    private void navigate(KeyEvent evt)
+    {
+        Vertex currentTarget = findSingleVertex();
+        currentTarget = traverseStragegiImpl.findNextVertex(graph, currentTarget, evt.getKeyCode());
+        selection.selectOnly(currentTarget);
+    }
+
+    /**
+     * Prepare a key-based move operation.
+     */
+    private void startKeyboardMove()
+    {
+        keyDeltaX = 0;
+        keyDeltaY = 0;
+        moving = true;
+    }
+    
+    /**
+     * End a move or resize gesture.
+     *
+     */
+    private void endMove() 
+    {
+        selection.moveStopped();
+        moving = false;
+        resizing = false;
+    }
+    
+    /**
+     * Prepare a key-based resize operation.
+     */
+    private void startKeyboardResize()
+    {
+        keyDeltaX = 0;
+        keyDeltaY = 0;
+        resizing = true;
+    }
+     
+    /**
+     * Move all targets according to the supplied key.
+     */
+    private void setKeyDelta(KeyEvent evt)
+    {
+        switch(evt.getKeyCode()) {
+            case KeyEvent.VK_UP : {
+                keyDeltaY -= GraphEditor.GRID_SIZE;
+                break;
+            }
+            case KeyEvent.VK_DOWN : {
+                keyDeltaY += GraphEditor.GRID_SIZE;
+                break;
+            }
+            case KeyEvent.VK_LEFT : {
+                keyDeltaX -= GraphEditor.GRID_SIZE;
+                break;
+            }
+            case KeyEvent.VK_RIGHT : {
+                keyDeltaX += GraphEditor.GRID_SIZE;
+                break;
+            }
+        }
+    }
+
+    /**
+     * Is the pressed key a plus or minus key?
+     */
+    private boolean isPlusOrMinusKey(KeyEvent evt)
+    {
+        return evt.getKeyChar() == '+' || evt.getKeyChar() == '-';
+    }
+
+    private void resizeWithFixedRatio(KeyEvent evt)
+    {
+        int delta = (evt.getKeyChar() == '+' ? GraphEditor.GRID_SIZE : -GraphEditor.GRID_SIZE);
+        selection.resize(delta, delta);
+        selection.moveStopped();
+    }
+    
+    private void selectDependency(KeyEvent evt)
+    {
+        Vertex vertex = selection.getAnyVertex();
+        if(vertex != null && vertex instanceof DependentTarget) {
+            selection.selectOnly(vertex);
+            List<Dependency> dependencies = ((DependentTarget) vertex).dependentsAsList();
+
+            Dependency currentDependency = dependencies.get(currentDependencyIndex);
+            if (currentDependency != null) {
+                selection.remove(currentDependency);
+            }
+            currentDependencyIndex += (evt.getKeyCode() == KeyEvent.VK_PAGE_UP ? 1 : -1);
+            currentDependencyIndex %= dependencies.size();
+            if (currentDependencyIndex < 0) {//% is not a real modulo
+                currentDependencyIndex = dependencies.size() - 1;
+            }
+            currentDependency = (Dependency) dependencies.get(currentDependencyIndex);
+            if (currentDependency != null) {
+                selection.add(currentDependency);
+            }
+        }
+    }
+
+    /**
+     * A menu popup trigger has been detected. Handle it.
+     */
+    public void handlePopupTrigger(MouseEvent evt)
+    {
+        int clickX = evt.getX();
+        int clickY = evt.getY();
+
+        SelectableGraphElement clickedElement = graph.findGraphElement(clickX, clickY);
+        if (clickedElement != null) {
+            selection.selectOnly(clickedElement);
+            postMenu(clickedElement, clickX, clickY);
+        }
+        else {
+            postMenu(clickX, clickY);
+        }
+    }
+    
+    /**
+     * Post the context menu on the diagram at the specified location
+     * @param x
+     * @param y
+     */
+    private void postMenu(int x, int y)
+    {
+        graphEditor.popupMenu(x,y);
+    }
+    
+    /**
+     * Post the context menu of one selected element of the current selection.
+     * If any dependencies are selected, show the menu for one of those. Otherwise
+     * show the menu for a randomly chosen target.
+     */
+    private void postMenu()
+    {
+        // first check whether we have selected edges
+        Dependency dependency = (Dependency) selection.getAnyEdge();
+        if (dependency != null) {
+            Point p = ((GraphPainterStdImpl) GraphPainterStdImpl.getInstance()).getDependencyPainter(dependency)
+                    .getPopupMenuPosition(dependency);
+            postMenu(dependency, p.x, p.y);
+        }
+        else {
+            // if not, choose a target
+            Vertex vertex = selection.getAnyVertex();
+            if(vertex != null) {
+                selection.selectOnly(vertex);
+                int x = vertex.getX() + vertex.getWidth() - 20;
+                int y = vertex.getY() + 20;
+                postMenu(vertex, x, y);
+            }
+        }
+    }
+
+    
+    /**
+     * Post the context menu for a given element at the given screen position.
+     */
+    private void postMenu(SelectableGraphElement element, int x, int y)
+    {
+        element.popupMenu(x, y, graphEditor);
+    }
+
+
+    /**
+     * Return the marquee of this conroller.
+     */
+    public Marquee getMarquee()
+    {
+        return marquee;
+    }
+
+    
+    private Vertex findSingleVertex()
+    {
+        Vertex vertex = selection.getAnyVertex();
+
+        // if there is no selection we select an existing vertex
+        if (vertex == null) {
+            vertex = (Vertex) graph.getVertices().next();
+        }
+        return vertex;
+    }
+
+
+    /**
+     * Clear the current selection.
+     */
+    public void clearSelection()
+    {
+        selection.clear();
+    }
+
+    /** 
+     * Select all graph vertices.
+     */
+    private void selectAll()
+    {
+        for(Iterator<? extends Vertex> i = graph.getVertices(); i.hasNext(); ) {
+            selection.add(i.next());
+        }
+    }
+    
+    /**
+     * Clear the current selection.
+     */
+    public void removeFromSelection(SelectableGraphElement element)
+    {
+        selection.remove(element);
+    }
+
+    /**
+     * Add to the current selection
+     * @param element
+     */
+    public void addToSelection(SelectableGraphElement element)
+    {
+        selection.add(element);
+    }
+   
+    /**
+     * Check whether this mouse event was from button one.
+     * (Ctrl-button one on MacOS does not count - that posts the menu
+     * so we consider that button two.)
+     */
+    private boolean isButtonOne(MouseEvent evt)
+    {
+        return !evt.isPopupTrigger() && ((evt.getModifiers() & MouseEvent.BUTTON1_DOWN_MASK) != MouseEvent.BUTTON1_DOWN_MASK);
+    }
+
+    /**
+     * Check whether the key used for multiple selections is down.
+     */
+    private boolean isMultiselectionKeyDown(MouseEvent evt)
+    {
+        if (Config.isMacOS()) {
+            return evt.isShiftDown() || evt.isMetaDown();
+        }
+        else {
+            return evt.isShiftDown() || evt.isControlDown();
+        }
+
+    }
+
+    /**
+     * Modify the given point to be one of the deined grid points.
+     * 
+     * @param point  The original point
+     * @return      A point close to the original which is on the grid.
+     */
+    private int snapToGrid(int x)
+    {
+        int steps = x / GraphEditor.GRID_SIZE;
+        int new_x = steps * GraphEditor.GRID_SIZE;//new x-coor w/ respect to
+                                                  // grid
+        return new_x;
+    }
+
+    /**
+     * Return the rubber band of this graph.
+     * @return  The rubber band instance, or null if no rubber band is currently in use.
+     */
+    public RubberBand getRubberBand()
+    {
+        return rubberBand;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/SelectionSet.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/SelectionSet.java
new file mode 100644
index 0000000000000000000000000000000000000000..f87ea63e762a14a915964ee19c3e1351f761d41d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/SelectionSet.java
@@ -0,0 +1,229 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.Point;
+import java.awt.event.MouseEvent;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * SelectionSet holds a set of selected graph elements. By inserting an
+ * element into this set, it is automatically set to selected.
+ * 
+ * @author fisker
+ * @author Michael Kolling
+ */
+public final class SelectionSet
+{
+    private Set<SelectableGraphElement> elements = new HashSet<SelectableGraphElement>();
+
+    /**
+     * 
+     * @param graphEditor
+     */
+    public SelectionSet()
+    {}
+
+    /**
+     * Add an unselected selectable graphElement to the set and
+     * set it's 'selected' flag.
+     * 
+     * @param element  The element to add
+     */
+    public void add(SelectableGraphElement element)
+    {
+        if (!element.isSelected()) {
+            element.setSelected(true);
+            elements.add(element);
+        }
+    }
+    
+    /**
+     * Add all the elements from another selection set to this one.
+     */
+    public void addAll(SelectionSet newSet)
+    {
+        elements.addAll(newSet.elements);
+    }
+
+    /**
+     * Remove the graphElement and set it's 'selected' flag false.
+     * 
+     * @param graphElement
+     */
+    public void remove(SelectableGraphElement element)
+    {
+        if (element != null) {
+            element.setSelected(false);
+            elements.remove(element);
+        }
+    }
+
+    /**
+     * Remove all the graphElements from the list. Set each removed grahpElement
+     * 'selected' flag to false. Does NOT selfuse remove method.
+     */
+    public void clear()
+    {
+        for (SelectableGraphElement element : elements) {
+            element.setSelected(false);
+        }
+        elements.clear();
+    }
+
+    /**
+     * Perform a double click on the selection.
+     * 
+     * @param evt  The mouse event that originated this double click.
+     */
+    public void doubleClick(MouseEvent evt)
+    {
+        final MouseEvent event = evt;
+        for (SelectableGraphElement element : elements) {
+            element.doubleClick(event);
+        }        
+    }
+    
+    /**
+     * Move the selected elements by the specified deltas.
+     */
+    public void move(int deltaX, int deltaY)
+    {
+        for (GraphElement element : elements) {
+            if(element instanceof Moveable) {
+                Moveable target = (Moveable) element;
+                if (target.isMoveable()) {
+                    target.setDragging(true);
+                    Point delta = restrictDelta(deltaX, deltaY);
+                    target.setGhostPosition(delta.x, delta.y);
+                }
+            }
+        }
+    }
+
+    /**
+     * Restrict the delta so that no target moves out of the screen.
+     */
+    private Point restrictDelta(int deltaX, int deltaY)
+    {
+        for (GraphElement element : elements) {
+            if(element instanceof Moveable) {
+                Moveable target = (Moveable) element;
+
+                if(target.getX() + deltaX < 0) {
+                    deltaX = -target.getX();
+                }
+                if(target.getY() + deltaY < 0) {
+                    deltaY = -target.getY();
+                }
+            }
+        }
+        return new Point(deltaX, deltaY);
+    }
+
+
+    /**
+     * A move gesture (either move or resize) has stopped. Inform all elements
+     * in this selection that they shoudl react.
+     */
+    public void moveStopped()
+    {
+        for (GraphElement element : elements) {
+            if(element instanceof Moveable) {
+                Moveable moveable = (Moveable) element;
+                moveable.setPositionToGhost();
+            }
+        }        
+    }
+    
+
+    /**
+     * A resize operation has initiated (or continued). Inform al elements
+     * that they should react to the resize.
+     * 
+     * @param deltaX  The current x offset from the start of the resize.
+     * @param deltaY  The current y offset from the start of the resize.
+     */
+    public void resize(int deltaX, int deltaY)
+    {
+        for (GraphElement element : elements) {
+            if(element instanceof Moveable) {
+                Moveable target = (Moveable) element;
+                if (target.isResizable()) {
+                    target.setDragging(true);
+                    target.setGhostSize(deltaX, deltaY);
+                }
+            }
+        }
+    }
+
+    /**
+     * Tell whether the selection is empty.
+     * 
+     * @return  true, if the selection is empty.
+     */
+    public boolean isEmpty()
+    {
+        return elements.isEmpty();
+    }
+    
+    /**
+     * Change the selection to contain only the specified element.
+     * 
+     * @param element  The single element to hold in the selection. 
+     */
+    public void selectOnly(SelectableGraphElement element)
+    {
+        clear();
+        add(element);
+    }
+    
+    /** 
+     * Return a random vertex from this selection.
+     * @return  An vertex, or null, if none exists.
+     */
+    public Vertex getAnyVertex()
+    {
+        for (GraphElement element : elements) {
+            if(element instanceof Vertex) {
+                return (Vertex) element;
+            }
+        }
+        return null;
+    }
+
+    
+    /** 
+     * Return a random vertex from this selection.
+     * @return  An vertex, or null, if none exists.
+     */
+    public Edge getAnyEdge()
+    {
+        for (GraphElement element : elements) {
+            if(element instanceof Edge) {
+                return (Edge) element;
+            }
+        }
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/TraverseStragegy.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/TraverseStragegy.java
new file mode 100644
index 0000000000000000000000000000000000000000..27c248c32aaadaf98a62927e9c24f2a7cec7aa82
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/TraverseStragegy.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+/**
+ * A strategy to move graph selections with keyboard input.
+ * 
+ * @author fisker
+ */
+public interface TraverseStragegy
+{
+    /**
+     * Given a currently selected vertex and a key press, decide which vertex 
+     * should be selected next.
+     * 
+     * @param graph  The graph we're looking at.
+     * @param currentVertex  The currently selected vertex.
+     * @param key  The key that was pressed.
+     * @return     A vertex that should be selected now.
+     */
+    public Vertex findNextVertex(Graph graph, Vertex currentVertex, int key);
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/TraverseStragegyImpl.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/TraverseStragegyImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e607d4e7fa12292ee27ed0afaac75ae08e79bef
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/TraverseStragegyImpl.java
@@ -0,0 +1,98 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.event.KeyEvent;
+import java.util.Iterator;
+
+/**
+ * A strategy to move graph selections with keyboard input.
+ * 
+ * @author fisker
+ */
+public class TraverseStragegyImpl
+    implements TraverseStragegy
+{
+
+    private double calcDistance(Vertex vertex1, Vertex vertex2)
+    {
+        if (vertex1 == null || vertex2 == null) {
+            return Double.POSITIVE_INFINITY;
+        }
+        int x1 = vertex1.getX() + vertex1.getWidth() / 2;
+        int y1 = vertex1.getY() + vertex1.getHeight() / 2;
+        int x2 = vertex2.getX() + vertex2.getWidth() / 2;
+        int y2 = vertex2.getY() + vertex2.getHeight() / 2;
+        double d = Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));
+        return d;
+    }
+
+    /**
+     * Given a currently selected vertex and a key press, decide which vertex 
+     * should be selected next.
+     * 
+     * @param graph  The graph we're looking at.
+     * @param currentVertex  The currently selected vertex.
+     * @param key  The key that was pressed.
+     * @return     A vertex that should be selected now.
+     */
+    public Vertex findNextVertex(Graph graph, Vertex currentVertex, int key)
+    {
+        int currentVertexCenterX = currentVertex.getX() + currentVertex.getWidth() / 2;
+        int currentVertexCenterY = currentVertex.getY() + currentVertex.getHeight() / 2;
+        int x;
+        int y;
+        Vertex v = null;
+        double closest = Double.POSITIVE_INFINITY;
+        double currentDistance;
+        Vertex closestVertex = null;
+        boolean left, right, up, down, notSelf, inRightRegion;
+        for (Iterator<? extends Vertex> i = graph.getVertices(); i.hasNext();) {
+            v = (Vertex) i.next();
+            x = v.getX() + v.getWidth() / 2 - currentVertexCenterX;
+            y = v.getY() + v.getHeight() / 2 - currentVertexCenterY;
+            left = key == KeyEvent.VK_LEFT && y >= x && y <= -x;
+            right = key == KeyEvent.VK_RIGHT && y <= x && y >= -x;
+            up = key == KeyEvent.VK_UP && y <= x && y <= -x;
+            down = key == KeyEvent.VK_DOWN && y >= x && y >= -x;
+            notSelf = currentVertex != v;
+            inRightRegion = (left || right || up || down) && notSelf;
+
+            if (inRightRegion) {
+                if (closestVertex == null) {
+                    closestVertex = v;
+                    closest = calcDistance(v, currentVertex);
+                }
+                if (closest > (currentDistance = calcDistance(v, currentVertex))) {
+                    closest = currentDistance;
+                    closestVertex = v;
+                }
+
+            }
+
+        }
+        if (closestVertex == null) {
+            closestVertex = currentVertex;
+        }
+        return closestVertex;
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Vertex.java b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Vertex.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad1ce63460561ebc27e8804143f4cd982dcecc80
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/graph/Vertex.java
@@ -0,0 +1,116 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.graph;
+
+import java.awt.*;
+
+/**
+ * General graph vertices
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ * @version $Id: Vertex.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public abstract class Vertex extends SelectableGraphElement
+{
+    private int x, y; // position
+    private int width, height; // size
+
+    /**
+     * Create this vertex with given specific position.
+     */
+    public Vertex(int x, int y, int width, int height)
+    {
+        this.x = x;
+        this.y = y;
+        this.width = width;
+        this.height = height;
+    }
+
+    /**
+     * Set the position to the specified coordinates.
+     */
+    public void setPos(int x, int y)
+    {
+        this.x = x;
+        this.y = y;
+    }
+
+    /**
+     * Set the size to the specified height and width.
+     */
+    public void setSize(int width, int height)
+    {
+        this.width = (width > 0 ? width : 10);
+        this.height = (height > 0 ? height : 10);
+    }
+
+    /**
+     * Get this vertex's enclosing rectangle.
+     */
+    public Rectangle getRectangle()
+    {
+        return new Rectangle(x, y, width, height);
+    }
+
+    /**
+     * Get this vertex's x position.
+     */
+    public int getX()
+    {
+        return this.x;
+    }
+
+    /**
+     * Get this vertex's y position.
+     */
+    public int getY()
+    {
+        return this.y;
+    }
+
+    /**
+     * Get this vertex's width.
+     */
+    public int getWidth()
+    {
+        return this.width;
+    }
+
+    /**
+     * Get this vertex's height.
+     */
+    public int getHeight()
+    {
+        return this.height;
+    }
+
+    /**
+     * The default shape for a vertex is a rectangle. Child classes can override
+     * this method to define more complex shapes.
+     */
+    public boolean contains(int x, int y)
+    {
+        return (getX() <= x) && (x < getX() + getWidth()) && 
+               (getY() <= y) && (y < getY() + getHeight());
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/greenfootsplash.jpg b/Sd1/P/Maven/bluej/src/main/java/bluej/greenfootsplash.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..7d27551083b2c8384ae4ce44b83c61e185f48c63
Binary files /dev/null and b/Sd1/P/Maven/bluej/src/main/java/bluej/greenfootsplash.jpg differ
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CodeFileFilter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CodeFileFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6401c9a2d6386b0199e98853acd86d0fa0c34f2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CodeFileFilter.java
@@ -0,0 +1,170 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import bluej.pkgmgr.BlueJPackageFile;
+import bluej.utility.Debug;
+
+/**
+ * A FilenameFilter that filters out files based on a list of patterns. It also
+ * filters out a standard set of file types (such as bluej.pkh files, ctxt files).
+ *
+ * @author fisker
+ */
+public class CodeFileFilter implements FileFilter, FilenameFilter
+{
+    private boolean includePkgFiles;
+    private List<Pattern> patterns = null;
+    private FileFilter parentFilter = null;
+
+    /**
+     * Construct a filter.
+     * @param ignore  List of file patterns to ignore
+     * @param includePkgFiles if true, pkg files are accepted
+     * @param 
+     */
+    public CodeFileFilter(List<String> ignore, boolean includePkgFiles, FileFilter parent)
+    {
+        this.includePkgFiles = includePkgFiles;
+        patterns = makePatterns(ignore);
+        parentFilter = parent;
+    }
+
+    private List<Pattern> makePatterns(List<String> ignore)
+    {
+        List<Pattern> patterns = new LinkedList<Pattern>();
+        for (Iterator<String> i = ignore.iterator(); i.hasNext();) {
+            String patternString = (String) i.next();
+            try{
+                Pattern p = Pattern.compile(patternString);
+                patterns.add(p);
+            } catch (PatternSyntaxException pse){
+                Debug.message("Couldn't parse ignore pattern: " + patternString);
+            }
+        }
+        return patterns;
+    }
+
+    private boolean matchesPatterns(String input)
+    {
+        for (Iterator<Pattern> i = patterns.iterator(); i.hasNext();) {
+            Pattern pattern = i.next();
+            Matcher matcher = pattern.matcher(input);
+            if (matcher.matches()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determines which files should be included
+     * @param dir the directory in which the file was found.
+     * @param name the name of the file.
+     */
+    public boolean accept(File dir, String name)
+    {
+        boolean result = true;
+
+        if(name.equals("doc") || dir.getName().equals("doc")){
+            result = false;
+        }
+        if (name.equals("CVS") || dir.getName().equals("CVS")){
+            result = false;
+        }
+        if (name.equals("CVSROOT") || dir.getName().equalsIgnoreCase("CVSROOT")){
+            result = false;
+        }
+
+        /* when a package is first created. pkg files should be
+         * added and committed. If we don't, BlueJ can't know which folders
+         * are packages
+         */ 
+        if (!includePkgFiles && BlueJPackageFile.isPackageFileName(name)){
+            result = false;
+        }
+        // the old bluej.pkg backup file
+        if (name.equals("bluej.pkh")){
+            result = false;
+        }	
+        if (name.equals("team.defs")){
+            result = false;
+        }
+        if (name.equals(".DS_Store")){
+            result = false;
+        }
+        if (getFileType(name).equals("ctxt")){
+            result = false;
+        }
+        if (name.charAt(name.length() -1) == '~'){
+            result = false;
+        }
+        if (name.charAt(name.length() -1) == '#'){
+            result = false;
+        }
+        if (name.endsWith("#backup")){
+            result = false;
+        }
+        if (name.startsWith(".#")){
+            result = false;
+        }
+        if (matchesPatterns(name)){
+            result = false;
+        }
+
+        if (result && parentFilter != null) {
+            result = parentFilter.accept(new File(dir, name));
+        }
+
+        return result;
+    }
+
+    public boolean accept(File pathname)
+    {
+        File parent = pathname.getParentFile();
+        return accept(parent, pathname.getName());
+    }
+
+    /**
+     * Get the type of a file
+     * @param filename the name of the file
+     * @return a string with the type of the file.
+     */
+    private String getFileType(String filename)
+    {
+        int lastDotIndex = filename.lastIndexOf('.');
+        if (lastDotIndex > -1 && lastDotIndex < filename.length()){
+            return filename.substring(lastDotIndex + 1);
+        }
+        return "";
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CommitFilter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CommitFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..8b7bffcd091356a40913a9fb58f164dfb0ad3eb5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CommitFilter.java
@@ -0,0 +1,66 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import bluej.pkgmgr.BlueJPackageFile;
+
+/**
+ * Class to filter CVS StatusInformation to calculate those classes that will 
+ * be changed when we next commit. It should include files that are locally 
+ * modified, remotely modified, locally deleted and remotely removed.
+ *
+ * @author bquig
+ * @version $Id: CommitFilter.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class CommitFilter
+{
+    /**
+     * Filter to identify which files in a repository will be altered at 
+     * the next commit.
+     */
+    public boolean accept(TeamStatusInfo statusInfo)
+    {
+        int stat = statusInfo.getStatus();
+        
+        if (stat == TeamStatusInfo.STATUS_DELETED) {
+            return true;
+        }
+        if (stat == TeamStatusInfo.STATUS_NEEDSADD) {
+            return true;
+        }
+        if (stat == TeamStatusInfo.STATUS_NEEDSCOMMIT) {
+            return true;
+        }
+        
+        if (BlueJPackageFile.isPackageFileName(statusInfo.getFile().getName())) {
+            boolean conflict = (stat == TeamStatusInfo.STATUS_CONFLICT_ADD);
+            conflict |= (stat == TeamStatusInfo.STATUS_NEEDSMERGE);
+            conflict |= (stat == TeamStatusInfo.STATUS_CONFLICT_LDRM);
+            conflict |= (stat == TeamStatusInfo.STATUS_UNRESOLVED);
+            if (conflict) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CompoundCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CompoundCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..0742b1212b2199b79d7ab81317a87416f2b259ca
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CompoundCommand.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+/**
+ * A utility class for combining multiple commands into one.
+ * 
+ * @author Davin McCall
+ */
+public class CompoundCommand implements TeamworkCommand
+{
+    private TeamworkCommand command1;
+    private TeamworkCommand command2;
+    
+    public CompoundCommand(TeamworkCommand command1, TeamworkCommand command2)
+    {
+        this.command1 = command1;
+        this.command2 = command2;
+    }
+    
+    public void cancel()
+    {
+        command1.cancel();
+        command2.cancel();
+    }
+
+    public TeamworkCommandResult getResult()
+    {
+        TeamworkCommandResult result = command1.getResult();
+        
+        if (result.wasAborted() || result.isError()) {
+            return result;
+        }
+        
+        result = command2.getResult();
+        return result;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CvsProvider.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CvsProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6a53b0199547efe188aff762680b2e03947e11c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/CvsProvider.java
@@ -0,0 +1,129 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.io.File;
+
+import org.netbeans.lib.cvsclient.CVSRoot;
+
+import bluej.Config;
+import bluej.groupwork.cvsnb.BlueJAdminHandler;
+import bluej.groupwork.cvsnb.CvsRepository;
+import bluej.utility.Debug;
+
+/**
+ * Provider for CVS.
+ * 
+ * @author Davin McCall
+ */
+public class CvsProvider
+    implements TeamworkProvider
+{
+    final static String pserverLabel = Config.getString("team.settings.pserver");
+    final static String extLabel = Config.getString("team.settings.ext");
+    
+    final static String [] protocols = { pserverLabel, extLabel };
+    final static String [] protocolKeys = { CVSRoot.METHOD_PSERVER, CVSRoot.METHOD_EXT };
+    
+    public String getProviderName()
+    {
+        return "CVS";
+    }
+    
+    public TeamworkCommandResult checkConnection(TeamSettings settings)
+    {
+        try {
+            String cvsRoot = makeCvsRoot(settings);
+            return CvsRepository.validateConnection(cvsRoot);
+        }
+        catch (UnsupportedSettingException e) {
+            return new TeamworkCommandUnsupportedSetting(e.getLocalizedMessage());
+        }
+    }
+    
+    public static String makeCvsRoot(TeamSettings settings)
+      throws UnsupportedSettingException
+    {
+        String protocol = settings.getProtocol();
+        String userName = settings.getUserName();
+        String password = settings.getPassword();
+        String server = settings.getServer();
+        String prefix = settings.getPrefix();
+        String group = settings.getGroup();
+        
+        // Password can be null if we are doing a task that doesn't require
+        // connection to the server.
+        if (password != null && password.contains("@")) {
+            throw new UnsupportedSettingException(Config.getString("team.error.password.at"));
+        }
+        if (userName.contains(":")) {
+            throw new UnsupportedSettingException(Config.getString("team.error.username.colon"));
+        }
+        
+        String cvsRoot = ":" + protocol + ":" + userName + ":" + password + "@" +
+            server + ":" + prefix;
+        if (group != null && group.length() != 0) {
+            if (! cvsRoot.endsWith("/")) {
+                cvsRoot += "/";
+            }
+            cvsRoot += group;
+        }
+        else if (cvsRoot.endsWith("/")) {
+            // Repository path should not end with '/'
+            cvsRoot = cvsRoot.substring(0, cvsRoot.length() - 1);
+        }
+        
+        return cvsRoot;
+    }
+
+    public String[] getProtocols()
+    {
+        return protocols;
+    }
+    
+    public String getProtocolKey(int protocol)
+    {
+        return protocolKeys[protocol];
+    }
+    
+    public String getProtocolLabel(String protocolKey)
+    {
+        int i = 0;
+        while (!protocolKeys[i].equals(protocolKey)) i++;
+        return protocols[i];
+    }
+    
+    public Repository getRepository(File projectDir, TeamSettings settings)
+    {
+        try {
+            String cvsRoot = makeCvsRoot(settings);
+            BlueJAdminHandler adminHandler = new BlueJAdminHandler(projectDir);
+            return new CvsRepository(projectDir, settings.getProtocol(), cvsRoot, adminHandler);
+        }
+        catch (UnsupportedSettingException e) {
+            Debug.reportError("CvsProvider.getRepository", e);
+            return null;
+        }
+        
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/HistoryInfo.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/HistoryInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..df76c55dfc73895ef4f0e297464bb44a7bc7f8e7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/HistoryInfo.java
@@ -0,0 +1,72 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+/**
+ * Represents a single element of history information. This includes:
+ * Filename, revision, date, user, comment
+ * 
+ * @author Davin McCall
+ * @version $Id: HistoryInfo.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class HistoryInfo
+{
+    private String [] files;
+    private String revision;
+    private String date;
+    private String user;
+    private String comment;
+    
+    public HistoryInfo(String [] files, String revision, String date, String user, String comment)
+    {
+        this.files = files;
+        this.revision = revision;
+        this.date = date;
+        this.user = user;
+        this.comment = comment;
+    }
+    
+    public String [] getFiles()
+    {
+        return files;
+    }
+    
+    public String getRevision()
+    {
+        return revision;
+    }
+    
+    public String getDate()
+    {
+        return date;
+    }
+    
+    public String getUser()
+    {
+        return user;
+    }
+    
+    public String getComment()
+    {
+        return comment;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/LogHistoryListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/LogHistoryListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..e58e0a0802b3a9cc5aaa277a4a3485cbcd517948
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/LogHistoryListener.java
@@ -0,0 +1,35 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+/**
+ * An interface for receiving log/history information
+ * 
+ * @author Davin McCall
+ */
+public interface LogHistoryListener
+{
+    /**
+     * Some log/history information is available, during execution of a log command.
+     */
+    public void logInfoAvailable(HistoryInfo logInfo);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/Repository.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/Repository.java
new file mode 100644
index 0000000000000000000000000000000000000000..0275f2bcd3379c2ec90a921fac26c9d608105cfc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/Repository.java
@@ -0,0 +1,145 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A version control repository, which comprises a remote repository together with a
+ * local copy.
+ * 
+ * @author Davin McCall
+ */
+public interface Repository
+{
+    /**
+     * Set the password used to access the repository
+     */
+    public void setPassword(TeamSettings newSettings);
+    
+    /**
+     * Returns true if this repository versions directories (subversion),
+     * false otherwise (CVS).
+     */
+    public boolean versionsDirectories();
+    
+    /**
+     * Checkout project from repostitory to local project.
+     */
+    public TeamworkCommand checkout(File projectPath);
+
+    /**
+     * Commits the files and directories in the project.
+     *
+     * @param newFiles Files to be committed which are not presently in the repository
+     *                 (text files only). If the version control system versions directories,
+     *                 this must be an ordered set where directories precede the files they
+     *                 contain.
+     * @param binaryNewFiles Files to be committed which are not presently in the
+     *                       repository and which are to be treated as binary
+     * @param deletedFiles Files which have been deleted locally but which exist
+     *                     in the latest version in the repository 
+     * @param files  All files to be committed (including all in newFiles, binaryNewFiles,
+     *               and deletedFiles, as well as any other files to be committed)
+     * @param commitComment  The comment for this commit
+     */
+    public TeamworkCommand commitAll(Set<File> newFiles, Set<File> binaryNewFiles,
+            Set<File> deletedFiles, Set<File> files, String commitComment);
+    
+    /**
+     * Put the project in the repository. This should create an empty project in
+     * the repository, and set the local project up as a working copy (with
+     * uncommitted files).
+     */
+    public TeamworkCommand shareProject();
+
+    /**
+     * Get status of all the given files.
+     * Returns a List of TeamStatusInfo.
+     *
+     * @param listener  A listener to be notified of the status of each requested file.
+     *                For version management systems which version directories, the status
+     *                of directories will be reported before files they contain.
+     * @param filter  A file filter to determine which files and directories to include
+     *                in the returned statuses
+     * @param includeRemote  Whether to include remote files (files which do not exist
+     *                       locally, but which do exist in the repository), regardless of
+     *                       whether they are listed in the files argument.
+     */
+    public TeamworkCommand getStatus(StatusListener listener, FileFilter filter, boolean includeRemote);
+    
+    /**
+     * Get a list of modules in the repository. The module names (String) are added
+     * to the supplied list before the command terminates.
+     */
+    public TeamworkCommand getModules(List<String> modules);
+    
+    /**
+     * Get the history of the repository - all commits, including file, date,
+     * revision, user, and comment.
+     */
+    public TeamworkCommand getLogHistory(LogHistoryListener listener);
+    
+    /**
+     * Prepare for the deletion of a directory. For CVS, this involves moving
+     * the metadata elsewhere. Returns true if the directory should be physically
+     * removed, or false otherwise, in which case all files and sub-directories
+     * within are assumed to have been handled.
+     * 
+     * <p>Also, calling this may result in the directory
+     * being removed.
+     */
+    public boolean prepareDeleteDir(File dir);
+    
+    /**
+     * Prepare a newly created directory for version control.
+     */
+    public void prepareCreateDir(File dir);
+    
+    /**
+     * Get a filter which can filter out directories/files that comprise metadata
+     * or other housekeeping information in the working copy
+     */
+    public FileFilter getMetadataFilter();
+    
+    /**
+     * Get all the locally deleted files in the repository. The files are put
+     * into the supplied set.
+     * 
+     * <p>Calling this method Does not result in communication with the repository
+     * server.
+     */
+    public void getAllLocallyDeletedFiles(Set<File> files);
+    
+    /**
+     * Gets the version control type, for data collection purposes
+     */
+    public String getVCSType();
+    
+    /**
+     * Gets the version control protocol, for data collection purposes
+     */
+    public String getVCSProtocol();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/Revision.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/Revision.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6ac821a341068e6a97fe71da5565b97cc1950f3
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/Revision.java
@@ -0,0 +1,71 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+/**
+ * A revision number with associated information - author, date, comment.
+ * 
+ * @author Davin McCall
+ */
+public class Revision
+{
+    private String author;
+    private String date;
+    private String comment;
+    
+    public Revision(String author, String date, String comment)
+    {
+        this.author = author;
+        this.date = date;
+        this.comment = comment;
+    }
+    
+    public String getAuthor()
+    {
+        return author;
+    }
+    
+    public String getDateString()
+    {
+        return date;
+    }
+    
+    public String getMessage()
+    {
+        return comment;
+    }
+    
+    public int hashCode()
+    {
+        return author.hashCode() + date.hashCode() + comment.hashCode();
+    }
+    
+    public boolean equals(Object other)
+    {
+        if (other instanceof Revision) {
+            Revision rother = (Revision) other;
+            return rother.author.equals(author) && rother.date.equals(date)
+                && rother.comment.equals(comment);
+        }
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/StatusHandle.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/StatusHandle.java
new file mode 100644
index 0000000000000000000000000000000000000000..9d85dac95861266d8f04675ca60968a3bcfd626d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/StatusHandle.java
@@ -0,0 +1,71 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.io.File;
+import java.util.Set;
+
+public interface StatusHandle
+{
+    /**
+     * Commits the files and directories in the project. Some files can be forced,
+     * which means that the existing local file (regardless of its revision) replaces
+     * the repository version (with the specified version number), only failing if
+     * an intermediate commit has occurred. 
+     *
+     * @param newFiles Files to be committed which are not presently in the repository
+     *                 (text files only). If the version management system versions
+     *                 directories, this should also contain directories, and must be
+     *                 an ordered set such that any directories precede files which
+     *                 they contain.
+     * @param binaryNewFiles Files to be committed which are not presently in the
+     *                       repository and which are to be treated as binary
+     * @param deletedFiles Files which have been deleted locally but which exist
+     *                     in the latest version in the repository 
+     * @param files  All files to be committed (including all in newFiles, binaryNewFiles,
+     *               and deletedFiles, as well as any other files to be committed)
+     * @param forceFiles  Those files for which the commit should be forced, overriding
+     *               the existing file in the repository.
+     *               specified. (The commit can still fail if the file is committed
+     * @param commitComment  The comment for this commit
+     */
+    public TeamworkCommand commitAll(Set<File> newFiles, Set<File> binaryNewFiles,
+            Set<File> deletedFiles, Set<File> files, Set<TeamStatusInfo> forceFiles,
+            String commitComment);
+
+    /**
+     * After a status command, get a command which can be used to
+     * update the working copy to the same revision(s) as was 
+     * shown in the status.
+     * 
+     * For CVS, this doesn't work exactly - it just does an update to
+     * latest revision, which might have changed since the status
+     * was performed.
+     */
+    public TeamworkCommand updateTo(UpdateListener listener, Set<File> files, Set<File> forceFiles);
+    
+    /**
+     * Gets the repository.  Used for data collection.
+     * @return
+     */
+    public Repository getRepository();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/StatusListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/StatusListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..4cfb2401d6fdfb1d243ad72ff2c258a3824ba9b1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/StatusListener.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+/**
+ * Interface for listening for results from a status command.
+ * 
+ * @author Davin McCall
+ */
+public interface StatusListener
+{
+    /**
+     * Status is available for a file.
+     */
+    public void gotStatus(TeamStatusInfo info);
+    
+    /**
+     * The status operation is complete. A status handle is provided
+     * to allow commit operations.
+     */
+    public void statusComplete(StatusHandle statusHandle);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/SubversionProvider.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/SubversionProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..80247523253da010e48c365d0ef1304d06d0865b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/SubversionProvider.java
@@ -0,0 +1,179 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.Revision;
+import org.tigris.subversion.javahl.SVNClientInterface;
+
+import bluej.Config;
+import bluej.groupwork.svn.SvnRepository;
+import bluej.utility.Debug;
+
+/**
+ * Teamwork provider for Subversion.
+ * 
+ * @author Davin McCall
+ */
+public class SubversionProvider implements TeamworkProvider
+{
+    SVNClientInterface client;
+    
+    public SubversionProvider()
+    {
+        client = getClient();
+        if (client == null) {
+            throw new RuntimeException("Can't initialize Subversion provider.");
+        }
+    }
+    
+    /**
+     * Get a handle to the subversion client interface (SVNKit/JavaHL).
+     */
+    private SVNClientInterface getClient()
+    {
+        SVNClientInterface client = null;
+        
+        try {
+            Class<?> clientImplClass = Class.forName("org.tmatesoft.svn.core.javahl.SVNClientImpl");
+            
+            Method newInstanceMethod = clientImplClass.getMethod("newInstance", new Class[0]);
+            Object svnClient = newInstanceMethod.invoke(null, new Object[0]);
+            
+            if (svnClient instanceof SVNClientInterface) {
+                client = (SVNClientInterface) svnClient;
+            }
+            else {
+                Debug.message("Subversion client class does not implement SVNClientInterface");
+            }
+        }
+        catch (ClassNotFoundException cnfe) {}
+        catch (NoSuchMethodException nsme) {
+            Debug.message("No \"newInstance()\" method in SVNClientImpl class.");
+            nsme.printStackTrace();
+        }
+        catch (LinkageError le) {}
+        catch (InvocationTargetException ite) {
+            Debug.message("Error while instantiating subversion client implementation.");
+            ite.printStackTrace();
+            if (ite.getCause() != null) {
+                ite.getCause().printStackTrace();
+            }
+        }
+        catch (IllegalAccessException iae) {}
+    
+        return client;
+    }
+    
+    public String getProviderName()
+    {
+        return "Subversion";
+    }
+    
+    @SuppressWarnings("deprecation")
+    public TeamworkCommandResult checkConnection(TeamSettings settings)
+    {
+        client.username(settings.getUserName());
+        client.password(settings.getPassword());
+        
+        try {
+            client.info2(makeSvnUrl(settings), Revision.HEAD, Revision.HEAD, false);
+            return new TeamworkCommandResult();
+        }
+        catch (ClientException ce) {
+            return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
+        }
+        catch (UnsupportedSettingException e) {
+            return new TeamworkCommandUnsupportedSetting(e.getLocalizedMessage());
+        }
+        
+    }
+    
+    public String[] getProtocols()
+    {
+        return new String [] { "svn", "svn+ssh", "http", "https" };
+    }
+    
+    public String getProtocolKey(int protocol)
+    {
+        return getProtocols()[protocol];
+    }
+    
+    public String getProtocolLabel(String protocolKey)
+    {
+        return protocolKey;
+    }
+    
+    public Repository getRepository(File projectDir, TeamSettings settings)
+    {
+        try {
+            SVNClientInterface client = getClient();
+            client.username(settings.getUserName());
+            client.password(settings.getPassword());
+            return new SvnRepository(projectDir, settings.getProtocol(), makeSvnUrl(settings), client);
+        }
+        catch (UnsupportedSettingException e) {
+            Debug.reportError("SubversionProvider.getRepository", e);
+            return null;
+        }
+    }
+    
+    /**
+     * Construct a subversion URL based on the given team settings
+     */
+    protected String makeSvnUrl(TeamSettings settings)
+      throws UnsupportedSettingException
+    {
+        String protocol = settings.getProtocol();
+        String userName = settings.getUserName();
+        // String password = settings.getPassword();
+        String server = settings.getServer();
+        String prefix = settings.getPrefix();
+        String group = settings.getGroup();
+        
+        if (userName.contains("@")) {
+            throw new UnsupportedSettingException(Config.getString("team.error.username.at"));
+        }
+        
+        String svnUrl = protocol + "://" + userName + "@" + server;
+        if (prefix.length() != 0 && ! prefix.startsWith("/")) {
+            svnUrl += "/";
+        }
+        svnUrl += prefix;
+        if (group != null && group.length() != 0) {
+            if (! svnUrl.endsWith("/")) {
+                svnUrl += "/";
+            }
+            svnUrl += group;
+        }
+        else if (svnUrl.endsWith("/")) {
+            // Repository path should not end with '/'
+            svnUrl = svnUrl.substring(0, svnUrl.length() - 1);
+        }
+
+        return svnUrl;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamSettings.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamSettings.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad5deaa0f20aee06ab0d70e2fa6ec7e81201ff45
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamSettings.java
@@ -0,0 +1,85 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+/**
+ * A class to represent team settings
+ * 
+ * @author Davin McCall
+ */
+public class TeamSettings
+{
+    private TeamworkProvider provider;
+    private String protocol;
+    private String server;
+    private String prefix;
+    private String group;
+    private String username;
+    private String password;
+    
+    public TeamSettings(TeamworkProvider provider, String protocol, String server,
+            String prefix, String group, String username, String password)
+    {
+        this.provider = provider;
+        this.protocol = protocol;
+        this.server = server;
+        this.prefix = prefix;
+        this.group = group;
+        this.username = username;
+        this.password = password;
+    }
+    
+    public TeamworkProvider getProvider()
+    {
+        return provider;
+    }
+    
+    public String getProtocol()
+    {
+        return protocol;
+    }
+    
+    public String getServer()
+    {
+        return server;
+    }
+    
+    public String getPrefix()
+    {
+        return prefix;
+    }
+    
+    public String getGroup()
+    {
+        return group;
+    }
+    
+    public String getUserName()
+    {
+        return username;
+    }
+    
+    public String getPassword()
+    {
+        return password;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamSettingsController.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamSettingsController.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a95f1363cb1f283450742811459364556028a0c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamSettingsController.java
@@ -0,0 +1,512 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.io.*;
+import java.util.*;
+
+import bluej.Config;
+import bluej.groupwork.ui.TeamSettingsDialog;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.utility.Debug;
+
+
+/**
+ * This class is responsible for reading and writing the configuration files
+ * regarding teamwork settings. The files are team.defs, which is located in
+ * the top-level folder of a team project, and the bluej.properties
+ *
+ * @author fisker
+ * @version $Id: TeamSettingsController.java 7492 2010-05-05 05:25:30Z davmac $
+ */
+public class TeamSettingsController
+{
+    private static ArrayList<TeamworkProvider> teamProviders;
+    static {
+        teamProviders = new ArrayList<TeamworkProvider>(2);
+        try {
+            teamProviders.add(new CvsProvider());
+        }
+        catch (Throwable e) {
+            Debug.message("Failed to initialize Cvs: " + e.getClass().getName()
+                    + ": "+ e.getLocalizedMessage());
+        }
+        try {
+            teamProviders.add(new SubversionProvider());
+        }
+        catch (Throwable e) {
+            Debug.message("Failed to initialize Subversion: " + e.getClass().getName()
+                    + ": "+ e.getLocalizedMessage());
+        }
+    }
+    
+    private Project project;
+    private File projectDir;
+    private Properties teamProperties;
+    private TeamSettingsDialog teamSettingsDialog;
+    private TeamSettings settings;
+    
+    //general
+    private String password;
+
+    private File teamdefs;
+    
+    // repository
+    private Repository repository;
+    
+    /**
+     * Construct a team settings controller for the given project.
+     */
+    public TeamSettingsController(Project project)
+    {
+        this.project = project;
+        this.projectDir = project.getProjectDir();
+        teamProperties = new Properties();
+        readSetupFile();
+    }
+
+    /**
+     * Construct a team settings controller, not associated with
+     * any project initially. The supplied projectDir need not be the
+     * final project directory - it is just used as a working location
+     * until the project is set.
+     */
+    public TeamSettingsController(File projectDir)
+    {
+        this.projectDir = projectDir;
+        teamProperties = new Properties();
+    }
+
+    /**
+     * Assign this team settings controller to a particular project.
+     * Once this is done, the repository settings can no longer be
+     * changed.
+     */
+    public void setProject(Project proj)
+    {
+        project = proj;
+        projectDir = proj.getProjectDir();
+        repository = null;
+        checkTeamSettingsDialog();
+    }
+    
+    /**
+     * Get a list of the teamwork providers (CVS, Subversion).
+     */
+    public List<TeamworkProvider> getTeamworkProviders()
+    {
+        return teamProviders;
+    }
+    
+    /**
+     * Get the repository. Returns null if user credentials are required
+     * but the user chooses to cancel.
+     */
+    public Repository getRepository(boolean authRequired)
+    {
+        if (authRequired && password == null) {
+            // If we don't yet know the password, prompt the user
+            getTeamSettingsDialog().doTeamSettings();
+
+            // If we still don't know it, user cancelled
+            if (password == null) {
+                return null;
+            }
+            
+            TeamSettings settings = teamSettingsDialog.getSettings();
+            if (repository == null) {
+                repository = settings.getProvider().getRepository(projectDir, settings);
+            }
+            else {
+                repository.setPassword(settings);
+            }
+        }
+        else if (!authRequired && password == null) {
+            // We'll return a "temporary" repository.
+            return settings.getProvider().getRepository(projectDir, settings);
+        }
+        else {
+            // We might have the password, but not yet have created
+            // the repository
+            if (repository == null) {
+                repository = settings.getProvider().getRepository(projectDir, settings);
+            }
+        }
+        
+        return repository;
+    }
+    
+    /**
+     * Initialize the repository.
+     */
+    public boolean initRepository()
+    {
+        if (repository == null) {
+            TeamworkProvider provider = settings.getProvider();
+            if (password == null) {
+                if (getTeamSettingsDialog().doTeamSettings() == TeamSettingsDialog.CANCEL) {
+                    return false;
+                }
+            }
+            repository = provider.getRepository(projectDir, settings);
+        }
+        return true;
+    }
+    
+    /**
+     * Get a list of files (and possibly directories) in the project which should be
+     * under version control management. This includes files which have been locally
+     * deleted since the last commit.
+     * 
+     * @param includeLayout  indicates whether to include the layout (bluej.pkg) files.
+     * (Note that locally deleted bluej.pkg files are always included).
+     */
+    public Set<File> getProjectFiles(boolean includeLayout)
+    {
+        initRepository(); // make sure the repository is constructed
+        
+        boolean versionsDirs = false;
+        if (repository != null) {
+            versionsDirs = repository.versionsDirectories();
+        }
+        
+        // Get a list of files to commit
+        Set<File> files = project.getFilesInProject(includeLayout, versionsDirs);
+        
+        if (repository != null) {
+            repository.getAllLocallyDeletedFiles(files);
+        }
+        
+        return files;
+    }
+    
+    /**
+     * Get a filename filter suitable for filtering out files which we don't want
+     * to be under version control.
+     */
+    public FileFilter getFileFilter(boolean includeLayout)
+    {
+        initRepository();
+        FileFilter repositoryFilter = null;
+        if (repository != null) {
+            repositoryFilter = repository.getMetadataFilter();
+        }
+        return new CodeFileFilter(getIgnoreFiles(), includeLayout, repositoryFilter);
+    }
+    
+    /**
+     * Read the team setup file in the top level folder of the project
+     */
+    private void readSetupFile()
+    {
+        teamdefs = new File(projectDir, "team.defs");
+
+        try {
+            teamProperties.load(new FileInputStream(teamdefs));
+            if (teamProperties.getProperty("bluej.teamsettings.vcs") == null) {
+                // old project from before Subversion support, was using CVS
+                teamProperties.setProperty("bluej.teamsettings.vcs", "cvs");
+            }
+            
+            initSettings();
+        }
+        catch (FileNotFoundException e) {
+            // e.printStackTrace();
+            // This is allowed to happen - if a non-shared project becomes
+            // shared
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void initSettings()
+    {
+        String user = getPropString("bluej.teamsettings.user");
+        if (user == null) {
+            user = "";
+        }
+        String group = getPropString("bluej.teamsettings.groupname");
+        if(group == null) {
+            group = "";
+        }
+
+        TeamworkProvider provider = null;
+        String providerName = getPropString("bluej.teamsettings.vcs");
+        if (providerName != null) {
+            for (int index = 0; index < teamProviders.size(); index++) {
+                TeamworkProvider prov = (TeamworkProvider) teamProviders.get(index);
+                if (prov.getProviderName().equalsIgnoreCase(providerName)) {
+                    provider = prov;
+                }
+            }
+        }
+        
+        if (provider != null) {
+            settings = initProviderSettings(user, group, password, provider);
+        }
+    }
+    
+    public TeamSettings initProviderSettings(String user, String group, String password,
+            TeamworkProvider provider) {
+        
+        String keyBase = "bluej.teamsettings."
+            + provider.getProviderName().toLowerCase() + "."; 
+        
+        String prefix = getPropString(keyBase + "repositoryPrefix");
+        String server = getPropString(keyBase + "server");
+        
+        String protocol = getPropString(keyBase + "protocol");
+
+        return new TeamSettings(provider, protocol, server, prefix, group, user, password);
+    }
+    
+    /**
+     * Prepare for the deletion of a directory. For CVS, this involves moving
+     * the metadata elsewhere. Returns true if the directory should actually
+     * be deleted, or false if the version control system will delete it either
+     * immediately or at commit time.
+     */
+    public boolean  prepareDeleteDir(File dir)
+    {
+        return getRepository(false).prepareDeleteDir(dir);
+    }
+    
+    /**
+     * Prepare a newly created directory for version control.
+     */
+    public void prepareCreateDir(File dir)
+    {
+        getRepository(false).prepareCreateDir(dir);
+    }
+
+    /**
+     * Get the team settings dialog to edit these team settings.
+     */
+    public TeamSettingsDialog getTeamSettingsDialog()
+    {
+        if (teamSettingsDialog == null) {
+            teamSettingsDialog = new TeamSettingsDialog(this);
+            teamSettingsDialog.setLocationRelativeTo(PkgMgrFrame.getMostRecent());
+            checkTeamSettingsDialog();
+        }
+        
+        return teamSettingsDialog;
+    }
+    
+    /**
+     * Disable the repository fields in the team settings dialog if
+     * we have a project attached.
+     */
+    private void checkTeamSettingsDialog()
+    {
+        if (teamSettingsDialog != null && project != null) {
+            // We have a project, which means we have an established
+            // repository. It shouldn't be changed now.
+            teamSettingsDialog.disableRepositorySettings();
+        }
+    }
+    
+    /**
+     * Write the settings to team.defs in the project. It no project is known,
+     * nothing happens. Note that nothing is written to bluej.properties. That
+     * is handled by the Config class.
+     *
+     */
+    public void writeToProject()
+    {
+        if (projectDir == null) {
+            return;
+        }
+
+        File cfgFile = new File(projectDir + "/team.defs");
+
+        if (!cfgFile.exists()) {
+            addIgnoreFilePatterns(teamProperties);
+        }
+
+        try {
+            teamProperties.store(new FileOutputStream(cfgFile), null);
+            repository = null;
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Add to the team properties the files we wish to ignore, like class files
+     * and ctxt files
+     * @param teamProperties
+     */
+    private void addIgnoreFilePatterns(Properties teamProperties)
+    {
+        teamProperties.put("bluej.teamsettings.ignore1", ".*\\.class");
+        teamProperties.put("bluej.teamsettings.ignore2", "bluej\\.pkh");
+        teamProperties.put("bluej.teamsettings.ignore3", "team\\.defs");
+        teamProperties.put("bluej.teamsettings.ignore4", ".*\\.ctxt");
+        teamProperties.put("bluej.teamsettings.ignore5", ".*\\~");
+        teamProperties.put("bluej.teamsettings.ignore6", ".*\\#");
+        teamProperties.put("bluej.teamsettings.ignore7", ".*\\#backup");
+        teamProperties.put("bluej.teamsettings.ignore8", "\\.DS_Store");
+    }
+
+    /**
+     * get the property by the name strname. If the property is present in
+     * the project, that value is returned. If not, bluej.properties and then
+     * bluej.defs are searched. If not found, null is returned.
+     * @param strname
+     * @return
+     */
+    public String getPropString(String strname)
+    {
+        String result = teamProperties.getProperty(strname);
+
+        if (result != null) {
+            return result;
+        }
+
+        result = Config.getPropString(strname, null);
+
+        return result;
+    }
+
+    public void setPropString(String key, String value)
+    {
+        teamProperties.setProperty(key, value);
+    }
+    
+    public void updateSettings(TeamSettings newSettings, boolean useAsDefault)
+    {
+        settings = newSettings;
+        
+        String userKey = "bluej.teamsettings.user";
+        String userValue = settings.getUserName();
+        setPropString(userKey, userValue);
+
+        String providerKey = "bluej.teamsettings.vcs";
+        
+        String providerName = newSettings.getProvider()
+                .getProviderName().toLowerCase();
+        setPropString(providerKey, providerName);
+        
+        String keyBase = "bluej.teamsettings."
+                + providerName + ".";
+        String serverKey = keyBase + "server";
+        String serverValue = settings.getServer();
+        setPropString(serverKey, serverValue);
+
+        String prefixKey = keyBase + "repositoryPrefix";
+        String prefixValue = settings.getPrefix();
+        setPropString(prefixKey, prefixValue);
+
+        String protocolKey = keyBase + "protocol";
+        String protocolValue = settings.getProtocol();
+        setPropString(protocolKey, protocolValue);
+
+        String groupKey = "bluej.teamsettings.groupname";
+        String groupValue = settings.getGroup();
+        setPropString(groupKey,  groupValue);
+
+        String useAsDefaultKey = "bluej.teamsettings.useAsDefault";
+        Config.putPropString(useAsDefaultKey,
+            Boolean.toString(useAsDefault));
+
+        // passwords are handled differently for security reasons,
+        // we don't at present store them on disk
+        String passValue = settings.getPassword();
+        setPasswordString(passValue);
+        
+        if (repository != null) {
+            TeamSettings settings = getTeamSettingsDialog().getSettings();
+            repository.setPassword(settings);
+        }
+        
+        if (useAsDefault) {
+            Config.putPropString(providerKey, providerName);
+            Config.putPropString(userKey, userValue);
+            Config.putPropString(serverKey, serverValue);
+            Config.putPropString(prefixKey, prefixValue);
+            Config.putPropString(groupKey, groupValue);
+            Config.putPropString(protocolKey, protocolValue);
+        }
+    }
+
+    /**
+     * In the first instance we don't want to store password.
+     * We want to ask the first time they want to try and perform operation
+     * We then store for the rest of the session. Over time we may want to provide
+     * some way of storing with relative security.
+     */
+    public String getPasswordString()
+    {
+        return password;
+    }
+
+    private void setPasswordString(String password)
+    {
+        this.password = password;
+    }
+
+    public boolean hasPasswordString()
+    {
+        return password != null;
+    }
+
+    /**
+     * gets the regular expressions in string form for the files we should ignore
+     * @return List containing Strings
+     */
+    public List<String> getIgnoreFiles()
+    {
+        Iterator<Object> keys = teamProperties.keySet().iterator();
+        List<String> patterns = new LinkedList<String>();
+
+        while (keys.hasNext()) {
+            String key = (String) keys.next();
+
+            // legacy settings
+            if (key.startsWith("bluej.teamsettings.cvs.ignore")) {
+                patterns.add(teamProperties.getProperty(key));
+            }
+            
+            // new settings
+            if (key.startsWith("bluej.teamsettings.ignore")) {
+                patterns.add(teamProperties.getProperty(key));
+            }
+        }
+
+        return patterns;
+    }
+
+    public boolean hasProject()
+    {
+        return project != null;
+    }
+    
+    public Project getProject()
+    {
+        return project;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamStatusInfo.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamStatusInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..81876c5e509b6c8ad21ada7f6fc466e5877692fe
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamStatusInfo.java
@@ -0,0 +1,159 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import bluej.Config;
+import java.io.File;
+
+/**
+ * Team status information for a file
+ * 
+ * @author Davin McCall
+ * @version $Id: TeamStatusInfo.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class TeamStatusInfo
+{
+    private File file;
+    private String localVersion;
+    private String remoteVersion;
+    private int status;
+    
+    /** The file is up-to-date, the local revision is the same as in the repository */
+    public final static int STATUS_UPTODATE = 0;
+    /** The file doesn't exist locally, but is in the repository */
+    public final static int STATUS_NEEDSCHECKOUT = 1;
+    /** The file has been deleted locally, but the deletion hasn't been committed yet */ 
+    public final static int STATUS_DELETED = 2;
+    /** The repository version is newer */
+    public final static int STATUS_NEEDSUPDATE = 3;
+    /** The local version has been modified */
+    public final static int STATUS_NEEDSCOMMIT = 4;
+    /** The repository version is newer, but the file is also locally modified */
+    public final static int STATUS_NEEDSMERGE = 5;
+    /** The file exists locally, but not in the repository */
+    public final static int STATUS_NEEDSADD = 6;
+    /** The file exists locally, but has been removed in the repository */
+    public final static int STATUS_REMOVED = 7;
+    /**
+     * An unresolved conflict. This can happen when:<ul>
+     * <li>when two binary files have been modified maybe?
+     * </ul><p> 
+     * 
+     * The only way out is to either delete the file locally, or do a forced
+     * commit or a forced update.
+     */
+    public final static int STATUS_UNRESOLVED = 8;
+    /** 
+     * There are conflicts now present in the local file. The local file
+     * needs to be edited to resolve the conflicts. (This state occurs
+     * after an update which merged changes from the repository).
+     */
+    public final static int STATUS_HASCONFLICTS = 9;
+    /** Unknown */
+    public final static int STATUS_WEIRD = 10;
+    /**
+     * The file has been created locally, but a file with the same name has been
+     * added in the repository. This is a conflict.
+     */
+    public final static int STATUS_CONFLICT_ADD = 12;
+    /**
+     * Locally modified, but deleted in repository (conflict)
+     */
+    public final static int STATUS_CONFLICT_LMRD = 13;
+    /**
+     * Locally deleted, but modified in repository (conflict)
+     */
+    public final static int STATUS_CONFLICT_LDRM = 14;
+    
+    
+    /* It has no status, only used for default constructor while waiting for cvs */
+    public final static int STATUS_BLANK = 11;
+    
+    public final static String [] statusStrings = {
+        "team.statusinfo.upToDate",
+        "team.statusinfo.needsCheckout",
+        "team.statusinfo.deleted",
+        "team.statusinfo.needsUpdate",
+        "team.statusinfo.needsCommit",
+        "team.statusinfo.needsMerge",
+        "team.statusinfo.needsAdd",    
+        "team.statusinfo.removed",
+        "team.statusinfo.unresolved",
+        "team.statusinfo.hasConflicts",
+        "team.statusinfo.weird",
+        "",
+        "team.statusinfo.conflictAdd",
+        "team.statusinfo.conflictLMRD",
+        "team.statusinfo.conflictLDRM"
+    };
+    
+    /**
+     * Default "blank" status info. Used to pre-populate status table whilst 
+     * awaiting repository response.
+     */
+    public TeamStatusInfo()
+    {
+        this(new File(""), "", "", STATUS_BLANK);
+    }
+    
+    public TeamStatusInfo(File file, String localVersion, String remoteVersion, int status)
+    {
+        this.file = file;
+        this.localVersion = localVersion;
+        this.remoteVersion = remoteVersion;
+        this.status = status;
+    }
+    
+    public File getFile()
+    {
+        return file;
+    }
+    
+    public String getLocalVersion()
+    {
+        return localVersion;
+    }
+    
+    public String getRepositoryVersion()
+    {
+        return remoteVersion;
+    }
+    
+    
+    public int getStatus()
+    {
+        return status;
+    }
+    
+    public String toString()
+    {
+        return getFile().getName();
+    }
+    
+    public static String getStatusString(int status)
+    {
+        if(status == STATUS_BLANK)
+            return "";
+        return Config.getString(statusStrings[status]);
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamUtils.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..3960934219e82d42f1ea2ccfd13f5429ea6eeeb3
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamUtils.java
@@ -0,0 +1,114 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.awt.Window;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+
+public class TeamUtils
+{
+    /**
+     * Handle a server response in an appropriate fashion, i.e. if the response
+     * indicates an error, then display an error dialog.
+     * 
+     * Call on the AWT event handling thread.
+     * 
+     * @param basicServerResponse  The response to handle
+     */
+    public static void handleServerResponse(TeamworkCommandResult result, final Window window)
+    {
+        if (result != null) {
+            if (result.wasAuthFailure()) {
+                DialogManager.showError(window, "team-authentication-problem");
+            }
+            else if (result.isError() && ! result.wasAborted()) {
+                String message = result.getErrorMessage();
+                DialogManager.showErrorText(window, message);
+            }
+        }
+    }
+    
+    /**
+     * From a set of File objects, remove those files which should be treated as
+     * binary files (and put them in a new set). 
+     */
+    public static Set<File> extractBinaryFilesFromSet(Set<File> files)
+    {
+        Set<File> binFiles = new HashSet<File>();
+        Iterator<File> i = files.iterator();
+        while (i.hasNext()) {
+            File f = i.next();
+            if (f.isDirectory()) {
+                continue;
+            }
+            String fname = f.getName();
+            if (! fname.endsWith(".txt") && ! fname.endsWith(".java")) {
+                binFiles.add(f);
+                i.remove();
+            }
+        }
+        return binFiles;
+    }
+
+    /**
+     * Backup a set of files, returning a map from the original file name to
+     * the backup name. The backup files are created in the system's temp
+     * folder/directory.
+     */
+    public static Map<File,File> backupFiles(Set<File> files) throws IOException
+    {
+        Map<File,File> rmap = new HashMap<File,File>();
+        for (Iterator<File> i = files.iterator(); i.hasNext(); ) {
+            File tempFile = File.createTempFile("bluejvcs", null);
+            File srcFile = i.next();
+            FileUtility.copyFile(srcFile, tempFile);
+            rmap.put(srcFile, tempFile);
+        }
+        return rmap;
+    }
+    
+    /**
+     * Copy a set of files, then delete the source files. This is used to
+     * restore a backup created by the backupFiles() method. The source
+     * files (i.e. the backup files) are deleted afterwards.
+     */
+    public static void restoreBackups(Map<File,File> rmap) throws IOException
+    {
+        Iterator<Map.Entry<File,File>> i = rmap.entrySet().iterator();
+        while (i.hasNext()) {
+            Map.Entry<File,File> entry = i.next();
+            File orig = entry.getKey();
+            File backup = entry.getValue();
+            FileUtility.copyFile(backup, orig);
+            backup.delete();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamViewFilter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamViewFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..3833f486b24c79d706fc026d35a33678b418b93f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamViewFilter.java
@@ -0,0 +1,47 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import bluej.pkgmgr.BlueJPackageFile;
+
+/**
+ * Filter for filtering out certain elements from the views in the groupwork UI.
+ * 
+ * @author Poul Henriksen
+ */
+public class TeamViewFilter
+{
+    /**
+     * Filter to identify which files will be shown in the groupwork UI.
+     * <p>
+     * This will filter out the old bluej package file (bluej.pkg) so that
+     * Diagram Layout doesn't appear twice in the same view.
+     * @return True if it should be accepted for viewing, false if not.
+     */
+    public boolean accept(TeamStatusInfo statusInfo)
+    {
+        if(BlueJPackageFile.isOldPackageFileName(statusInfo.getFile().getName())) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a1570e3de883e1045d55aab0c85e7544655abf0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommand.java
@@ -0,0 +1,43 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+
+/**
+ * An interface to represent a teamwork command.
+ * 
+ * @author Davin McCall
+ */
+public interface TeamworkCommand
+{
+    /**
+     * Cancel execution of the command. This can be called from any
+     * thread, and should return immediately.
+     */
+    public void cancel();
+    
+    /**
+     * Complete execution of the command, and get the result.
+     * Command execution might not begin until this method is called.
+     */
+    public TeamworkCommandResult getResult();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandAborted.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandAborted.java
new file mode 100644
index 0000000000000000000000000000000000000000..b22e483d4ce4b3649f27888b23891dbc451db1cd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandAborted.java
@@ -0,0 +1,40 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+/**
+ * A teamwork command result representing an aborted command.
+ * 
+ * @author Davin McCall
+ */
+public class TeamworkCommandAborted extends TeamworkCommandResult
+{
+    public boolean isError()
+    {
+        return true;
+    }
+    
+    public boolean wasAborted()
+    {
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandAuthFailure.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandAuthFailure.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f497066fce77fb4d07c43e5288dc3ca80ddfc39
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandAuthFailure.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import bluej.utility.DialogManager;
+
+public class TeamworkCommandAuthFailure extends TeamworkCommandResult
+{
+    public boolean isError()
+    {
+        return true;
+    }
+    
+    public boolean wasAuthFailure()
+    {
+        return true;
+    }
+    
+    public String getErrorMessage()
+    {
+        return DialogManager.getMessage("team-authentication-problem");
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandError.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandError.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd20486b6730896a592bcca93dcc9381f32ac717
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandError.java
@@ -0,0 +1,139 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.Map.Entry;
+
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+
+/**
+ * A teamwork command result representing a general error during command
+ * execution. If the error message is recognised it will be replaced by a more
+ * helpful message. Messages will also be logged with Debug.
+ * 
+ * @author Davin McCall
+ * @author Poul Henriksen
+ */
+public class TeamworkCommandError extends TeamworkCommandResult
+{
+    private String errMsg;
+    private String localizedErrMsg;
+    
+    // Map of known error messages. Populated below.
+    private static final Map<String, String> messageIdMap = new TreeMap<String, String>();
+
+    // CVS error messages
+    static {
+        messageIdMap.put("cvs server: Up-to-date check failed", "team-uptodate-failed");
+        messageIdMap.put("cvs server: cannot find module", "team-cant-find-module");
+    }    
+    
+    // SVN error messages
+    static {
+        messageIdMap.put("svn: Cannot connect to", "team-cant-connect");
+        messageIdMap.put("svn: No repository found in", "team-cant-find-repository");
+        messageIdMap.put("svn: File not found:", "team-cant-find-path");
+        messageIdMap.put("svn: URL ", "team-cant-find-path");
+        messageIdMap.put("svn: Authentication required for", "team-authentication-problem");
+        messageIdMap.put("svn: File already exists:", "team-project-exists");
+        
+    }
+        
+    /**
+     * Construct a new Teamwork command error result. The supplied error message
+     * will be exchanged with a more descriptive message if possible. If not
+     * possible, it will use the optional translatedErrMsg, and if that fails
+     * too, it will just use the raw errMsg.
+     * 
+     * @param errMsg Error message as returned by the server
+     * @param localizedErrMsg Localized error message, or null if not available.
+     */
+    public TeamworkCommandError(String errMsg, String localizedErrMsg)
+    {
+        this.errMsg = errMsg;
+        this.localizedErrMsg = localizedErrMsg;
+        Debug.message("Teamwork error message: " + errMsg);
+    }
+    
+    public boolean isError()
+    {
+        return true;
+    }
+    
+    /**
+     * Get the error message - ready to be shown in a dialog.
+     */
+    public String getErrorMessage()
+    {
+        String betterMsg = getBetterMsg(errMsg);
+        if(betterMsg != null) {
+            return betterMsg;
+        }
+        else if(localizedErrMsg != null) {
+            return localizedErrMsg;
+        }
+        else {
+            return errMsg;
+        }
+    }
+    
+    /**
+     * Translate the given message (which was received directly from the server)
+     * into a better message. If there is no known translation, returns null.
+     * 
+     * @param msg  The message to translate
+     * @return  The message, or null
+     */
+    private String getBetterMsg(String msg)
+    {        
+        if(msg == null) {
+            return null;
+        }
+
+        String betterMsg = null;
+        String trimmedInput = msg.trim();
+        
+        if (trimmedInput.length() == 0) {
+            betterMsg = "team-empty-message";
+        }
+        else {
+            // Look for the key in the map
+            Set<Entry<String, String>> entries = messageIdMap.entrySet();
+            for (Iterator<Entry<String, String>> iterator = entries.iterator(); iterator.hasNext();) {
+                Entry<String, String> entry = (Entry<String, String>) iterator.next();
+                if (trimmedInput.startsWith(entry.getKey())) {
+                    betterMsg = entry.getValue();
+                    break;
+                }
+            }
+        }
+        if (betterMsg != null) {
+            betterMsg = DialogManager.getMessage(betterMsg);
+        }
+        return betterMsg;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandResult.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..de774b696dab5ed4e495850d8da46cd37ec6d9d8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandResult.java
@@ -0,0 +1,67 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+/**
+ * Represents the result of a teamwork command.<p>
+ * 
+ * This base class represents the default case - no error.
+ * 
+ * @author Davin McCall
+ */
+public class TeamworkCommandResult
+{
+    /**
+     * Did an error occur during the processing of the command?
+     * This includes authentication problems and command cancellation.
+     */
+    public boolean isError()
+    {
+        return false;
+    }
+    
+    /**
+     * Did the command fail due to authentication failure - invalid
+     * username/password?
+     */
+    public boolean wasAuthFailure()
+    {
+        return false;
+    }
+    
+    /**
+     * Was the command aborted? (in this case, isError/wasAuthFailure will both
+     * return false).
+     */
+    public boolean wasAborted()
+    {
+        return false;
+    }
+    
+    /**
+     * Get the error message explaining the problem that occurred.
+     */
+    public String getErrorMessage()
+    {
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandUnsupportedSetting.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandUnsupportedSetting.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee4cbd217ab4a350bba251ebaa649580c103bf45
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkCommandUnsupportedSetting.java
@@ -0,0 +1,27 @@
+package bluej.groupwork;
+
+/**
+ * A result indicating that an UnsupportedSettingException was thrown.
+ */
+public class TeamworkCommandUnsupportedSetting extends TeamworkCommandResult
+{
+	private String message;
+
+	public TeamworkCommandUnsupportedSetting(String message)
+	{
+		this.message = message;
+	}
+
+	@Override
+	public String getErrorMessage()
+	{
+		return message;
+	}
+
+	@Override
+	public boolean isError()
+	{
+		return true;
+	}
+	
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkProvider.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfad50bc946db0d9f50f47b7e0fc54909d2b8bea
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/TeamworkProvider.java
@@ -0,0 +1,66 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.io.File;
+
+/**
+ * An interface for teamwork providers - CVS, Subversion
+ * 
+ * @author Davin McCall
+ */
+public interface TeamworkProvider
+{
+    /**
+     * Get the name of this provider ("CVS", "Subversion", etc)
+     */
+    public String getProviderName();
+    
+    /**
+     * Get a list of the different protocols this provider supports (as human-
+     * readable strings, not necessarily the same as what appears in the
+     * repository url)
+     */
+    public String [] getProtocols();
+    
+    /**
+     * Get the protocol string used internally to represent the given protocol
+     * @param protocol  an index into the array returned by getProviderName()
+     */
+    public String getProtocolKey(int protocol);
+    
+    /**
+     * Get the label for a given protocol key.
+     */
+    public String getProtocolLabel(String protocolKey);
+    
+    /**
+     * Check that supplied information can be used to connect to a repository.
+     * This might take some time to execute.
+     */
+    public TeamworkCommandResult checkConnection(TeamSettings settings);
+    
+    /**
+     * Get a repository from the given settings
+     */
+    public Repository getRepository(File projectDir, TeamSettings settings);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UnableToParseInputException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UnableToParseInputException.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2d3134909700bf9001c152c707860a498fa4767
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UnableToParseInputException.java
@@ -0,0 +1,34 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+/**
+ * @author fisker
+ *
+ */
+public class UnableToParseInputException extends Exception {
+
+
+	public UnableToParseInputException(String message) {
+		super(message);
+	}
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UnsupportedSettingException.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UnsupportedSettingException.java
new file mode 100644
index 0000000000000000000000000000000000000000..5636ac457f13deff430f4c77c846a74877aac377
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UnsupportedSettingException.java
@@ -0,0 +1,25 @@
+package bluej.groupwork;
+
+/**
+ * Due to the way URLs are constructed for the repositories, certain characters are
+ * not supported in the username and password fields.  This exception is thrown
+ * if the user has such an unsupported username or password
+ *
+ */
+public class UnsupportedSettingException extends Exception
+{
+	private String reason;
+
+	public UnsupportedSettingException(String reason)
+	{
+		this.reason = reason;
+	}
+
+	@Override
+	public String getLocalizedMessage()
+	{
+		return reason;
+	}
+
+	
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UpdateFilter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UpdateFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd0e67f361c1636e71cc6349bb44c531280bc86a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UpdateFilter.java
@@ -0,0 +1,82 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+/**
+ * Class to filter TeamStatusInfo objects to calculate those classes that will 
+ * be changed when we next update. 
+ *
+ * @author Davin McCall
+ * @version $Id: UpdateFilter.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class UpdateFilter
+{
+    /**
+     * Filter to identify which files in a repository will be altered at 
+     * the next update.
+     */
+    public boolean accept(TeamStatusInfo statusInfo)
+    {
+        boolean isDir = statusInfo.getFile().isDirectory();
+        int stat = statusInfo.getStatus();
+        
+        if (stat == TeamStatusInfo.STATUS_NEEDSCHECKOUT) {
+            return true;
+        }
+        if (stat == TeamStatusInfo.STATUS_NEEDSMERGE) {
+            return ! isDir;
+        }
+        if (stat == TeamStatusInfo.STATUS_NEEDSUPDATE) {
+            return ! isDir;
+        }
+        if (stat == TeamStatusInfo.STATUS_REMOVED) {
+            return true;
+        }
+        if (stat == TeamStatusInfo.STATUS_CONFLICT_LDRM) {
+            // Locally deleted, remotely modified. Update pulls the repository version
+            return true;
+        }
+        if (stat == TeamStatusInfo.STATUS_CONFLICT_LMRD) {
+            // Update will succeed if forced (for bluej.pkg files)
+            return true;
+        }
+    
+        return false;
+    }
+    
+    /**
+     * For layout files, checks whether the file should be updated unconditionally.
+     */
+    public boolean updateAlways(TeamStatusInfo statusInfo)
+    {
+        if (statusInfo.getStatus() == TeamStatusInfo.STATUS_NEEDSCHECKOUT) {
+            return true;
+        }
+        if (statusInfo.getStatus() == TeamStatusInfo.STATUS_REMOVED) {
+            return true;
+        }
+        if (statusInfo.getStatus() == TeamStatusInfo.STATUS_CONFLICT_LMRD) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UpdateListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UpdateListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..c31b5df6bc0dc00a819a48f126bb720fe11058c7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UpdateListener.java
@@ -0,0 +1,60 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.io.File;
+
+/**
+ * An interface for listening to changes performed to local files
+ * by an update from the repository.
+ * 
+ * @author Davin McCall
+ * @version $Id: UpdateListener.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface UpdateListener
+{
+    /**
+     * A file was added locally.
+     */
+    public void fileAdded(File f);
+    
+    /**
+     * A file was removed locally.
+     */
+    public void fileRemoved(File f);
+    
+    /**
+     * A file was updated.
+     */
+    public void fileUpdated(File f);
+    
+    /**
+     * A directory (and all files within) was removed.
+     * The files within might not be individually reported.
+     */
+    public void dirRemoved(File f);
+    
+    /**
+     * Conflicts must be handled.
+     */
+    public void handleConflicts(UpdateResults updateResults);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UpdateResults.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UpdateResults.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a55407fbdcf23dc5c51cde2bf6579d9590a242b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/UpdateResults.java
@@ -0,0 +1,60 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork;
+
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Represents a set of update results from an update, and provides a method to decide
+ * conflict resolution in the case of binary file conflicts.
+ * 
+ * @author Davin McCall
+ */
+public interface UpdateResults
+{
+    /**
+     * Get a list of File objects that represents conflicts. 
+     */
+    public List<File> getConflicts();
+    
+    /**
+     * Get the set of files which had binary conflicts. These are files which
+     * have been modified both locally and in the repository. A decision needs to
+     * be made about which version (local or repository) is to be retained; use
+     * the overrideFiles() method to finalise this decision.
+     */
+    public Set<File> getBinaryConflicts();
+    
+    /**
+     * Once the initial update has finished and the binary conflicts are known,
+     * this method must be called to select whether to keep the local or use the
+     * remove version of the conflicting files.
+     *  
+     * @param files  A set of files to fetch from the repository, overwriting the
+     *               local version. (For any file not in the set, the local version
+     *               is retained). 
+     */
+    public void overrideFiles(Set<File> files);
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/CheckoutAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/CheckoutAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..01a4ce68a321ef60c593c7e6d8e21ccf9bfd1a5d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/CheckoutAction.java
@@ -0,0 +1,207 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import java.io.File;
+
+import bluej.Config;
+import bluej.groupwork.*;
+import bluej.groupwork.ui.ModuleSelectDialog;
+import bluej.groupwork.ui.TeamSettingsDialog;
+import bluej.pkgmgr.Import;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+import bluej.utility.SwingWorker;
+
+
+/**
+ * An action to perform a checkout of a module in CVS. The module is checked
+ * out into some directory (chosen by the user) and then opened as a BlueJ
+ * project.
+ * 
+ * @author Kasper
+ */
+public class CheckoutAction extends TeamAction
+{
+    static private CheckoutAction instance = null;
+
+    public CheckoutAction()
+    {
+        super("team.checkout");
+    }
+
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public CheckoutAction getInstance()
+    {
+        if (instance == null) {
+            instance = new CheckoutAction();
+        }
+
+        return instance;
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(PkgMgrFrame oldFrame)
+    {
+        //TeamSettingsController tsc = new TeamSettingsController(projectDir);
+        // Create a TeamSettingsController for the current project directory,
+        // switch it to the new one once it's been created
+        TeamSettingsController tsc = new TeamSettingsController(new File(".").getAbsoluteFile());
+        TeamSettingsDialog tsd = tsc.getTeamSettingsDialog();
+        tsd.setLocationRelativeTo(oldFrame);
+        
+        if (tsd.doTeamSettings() == TeamSettingsDialog.OK) {
+            ModuleSelectDialog moduleDialog = new ModuleSelectDialog(oldFrame, tsc.getRepository(true));
+            moduleDialog.setLocationRelativeTo(oldFrame);
+            moduleDialog.setVisible(true);
+            
+            String moduleName = moduleDialog.getModuleName();
+            if (moduleName != null) {
+                // Select parent directory for the new project
+                
+                File parentDir = FileUtility.getDirName(oldFrame, Config.getString("team.checkout.filechooser.title"),
+                        Config.getString("team.checkout.filechooser.button"), true, true);
+                
+                if (parentDir != null) {
+                    File projectDir = new File(parentDir, moduleName);
+                    if (projectDir.exists()) {
+                        DialogManager.showError(null, "directory-exists");
+                        return;
+                    }
+                    
+                    PkgMgrFrame newFrame;
+                    if (oldFrame.isEmptyFrame()) {
+                        newFrame = oldFrame;
+                    }
+                    else {
+                        newFrame = PkgMgrFrame.createFrame();
+                        if(Config.isJava15()) {
+                            newFrame.setLocationByPlatform(true);
+                        }
+                        newFrame.setVisible(true);
+                        newFrame.setEnabled(false);
+                    }
+                    
+                    new CheckoutWorker(newFrame, tsc.getRepository(true), projectDir, tsc).start();
+                }
+            }
+        }
+    }
+    
+    /**
+     * A worker to perform the checkout operation.
+     * 
+     * @author Davin McCall
+     */
+    private class CheckoutWorker extends SwingWorker
+    {
+        private Repository repository;
+        private PkgMgrFrame newFrame;
+        private File projDir;
+        private TeamSettingsController tsc;
+        
+        private TeamworkCommandResult response;
+        private boolean failed = true;
+        
+        public CheckoutWorker(PkgMgrFrame newFrame, Repository repository, File projDir, TeamSettingsController tsc)
+        {
+            this.newFrame = newFrame;
+            this.repository = repository;
+            this.projDir = projDir;
+            this.tsc = tsc;
+        }
+        
+        /*
+         * Get the files from the repository.
+         * @see bluej.utility.SwingWorker#construct()
+         */
+        public Object construct()
+        {
+            newFrame.setStatus(Config.getString("team.checkingout"));
+            newFrame.startProgress();
+            TeamworkCommand checkoutCmd = repository.checkout(projDir);
+            response = checkoutCmd.getResult();
+
+            failed = response.isError();
+
+            newFrame.stopProgress();
+            if (! failed) {
+                newFrame.setStatus(Config.getString("team.checkedout"));
+            }
+
+            newFrame.stopProgress();
+
+            return response;
+        }
+        
+        /*
+         * Now open the directory as a BlueJ project.
+         * @see bluej.utility.SwingWorker#finished()
+         */
+        public void finished()
+        {
+            if (! failed) {
+                if (! Project.isProject(projDir.toString())) {
+                    // Try and convert it to a project
+                    if (! Import.convertNonBlueJ(newFrame, projDir)) {
+                        cleanup();
+                        return;
+                    }
+                }
+                
+                Project project = Project.openProject(projDir.toString(), newFrame);
+                
+                project.setTeamSettingsController(tsc);
+                Package initialPackage = project.getPackage(project.getInitialPackageName());
+                newFrame.openPackage(initialPackage);
+                newFrame.setEnabled(true);
+            }
+            else {
+                TeamUtils.handleServerResponse(response, newFrame);
+                cleanup();
+            }
+        }
+        
+        /**
+         * Clean up after failed checkout.
+         */
+        public void cleanup()
+        {
+            projDir.delete();
+            newFrame.doClose(true, false);
+            // The frame might not have closed if it was the
+            // last frame. In that case we want to enable it.
+            newFrame.setEnabled(true);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/CommitAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/CommitAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..567ed35c1b6b55b95ad1d895939f25d64203a1ea
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/CommitAction.java
@@ -0,0 +1,207 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import java.awt.EventQueue;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+
+import bluej.Config;
+import bluej.groupwork.StatusHandle;
+import bluej.groupwork.TeamStatusInfo;
+import bluej.groupwork.TeamUtils;
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.groupwork.ui.CommitCommentsFrame;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.utility.SwingWorker;
+
+
+/**
+ * An action to do an actual commit.
+ * 
+ * <p>This action should not be enabled until the following methods have
+ * been called:
+ * 
+ * <ul>
+ * <li>setNewFiles()
+ * <li>setDeletedFiles()
+ * <li>setFiles()
+ * <li>setStatusHandle()
+ * </ul>
+ * 
+ * @author Kasper
+ */
+public class CommitAction extends AbstractAction
+{
+    private Set<File> newFiles; // which files are new files
+    private Set<File> deletedFiles; // which files are to be removed
+    private Set<File> files; // files to commit (includes both of above)
+    private CommitCommentsFrame commitCommentsFrame;
+    private StatusHandle statusHandle;
+    
+    private CommitWorker worker;
+    
+    public CommitAction(CommitCommentsFrame frame)
+    {
+        super(Config.getString("team.commit"));
+        commitCommentsFrame = frame; 
+    }
+    
+    /**
+     * Set the files which are new, that is, which aren't presently under
+     * version management and which need to be added. If the version management
+     * system versions directories, the set must be ordered and new directories
+     * must precede any files they contain.
+     */
+    public void setNewFiles(Set<File> newFiles)
+    {
+        this.newFiles = newFiles;
+    }
+    
+    /**
+     * Set the files which have been deleted locally, and the deletion
+     * needs to be propagated to the repository.
+     */
+    public void setDeletedFiles(Set<File> deletedFiles)
+    {
+        this.deletedFiles = deletedFiles;
+    }
+    
+    /**
+     * Set all files which are to be committed. This should include both
+     * the new files and the deleted files, as well as any other files
+     * which have been locally modified and need to be committed.
+     */
+    public void setFiles(Set<File> files)
+    {
+        this.files = files;
+    }
+    
+    /**
+     * Set the status handle to use in order to perform the commit operation.
+     */
+    public void setStatusHandle(StatusHandle statusHandle)
+    {
+        this.statusHandle = statusHandle;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(ActionEvent event) 
+    {
+        Project project = commitCommentsFrame.getProject();
+        
+        if (project != null) {
+            commitCommentsFrame.startProgress();
+            PkgMgrFrame.displayMessage(project, Config.getString("team.commit.statusMessage"));
+            setEnabled(false);
+            
+            //doCommit(project);
+            worker = new CommitWorker(project);
+            worker.start();
+        }
+    }
+    
+    /**
+     * Cancel the commit, if it is running.
+     */
+    public void cancel()
+    {
+        setEnabled(true);
+        if(worker != null) {
+            worker.abort();
+            worker = null;
+        }
+    }
+
+    /**
+     * Worker thread to perform commit operation
+     * 
+     * @author Davin McCall
+     */
+    private class CommitWorker extends SwingWorker
+    {
+        private TeamworkCommand command;
+        private TeamworkCommandResult result;
+        private boolean aborted;
+        
+        public CommitWorker(Project project)
+        {
+            String comment = commitCommentsFrame.getComment();
+            Set<TeamStatusInfo> forceFiles = new HashSet<TeamStatusInfo>();
+            
+            //last step before committing is to add in modified diagram 
+            //layouts if selected in commit comments dialog
+            if(commitCommentsFrame.includeLayout()) {
+                forceFiles = commitCommentsFrame.getChangedLayoutInfo();
+                files.addAll(commitCommentsFrame.getChangedLayoutFiles());
+            }
+
+            Set<File> binFiles = TeamUtils.extractBinaryFilesFromSet(newFiles);
+
+            command = statusHandle.commitAll(newFiles, binFiles, deletedFiles, files,
+                    forceFiles, comment);
+        }
+        
+        public Object construct()
+        {
+            result = command.getResult();
+            return result;
+        }
+        
+        public void abort()
+        {
+            command.cancel();
+            aborted = true;
+        }
+        
+        public void finished()
+        {
+            final Project project = commitCommentsFrame.getProject();
+            
+            if (! aborted) {
+                commitCommentsFrame.stopProgress();
+                if (! result.isError() && ! result.wasAborted()) {
+                    EventQueue.invokeLater(new Runnable() {
+                        public void run() {
+                            PkgMgrFrame.displayMessage(project, Config.getString("team.commit.statusDone"));
+                        }
+                    });
+                }
+            }
+
+            TeamUtils.handleServerResponse(result, commitCommentsFrame);
+            
+            if (! aborted) {
+                setEnabled(true);
+                commitCommentsFrame.setVisible(false);
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/CommitCommentAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/CommitCommentAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ff64e744ad9a0af08225efd8bdf538828314f57
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/CommitCommentAction.java
@@ -0,0 +1,63 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import bluej.Config;
+import bluej.groupwork.ui.CommitCommentsFrame;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+
+
+/**
+ * Action to show the frame which allows commit comments to be entered.
+ * The frame has a button to make the commit.
+ * 
+ * @author Kasper
+ * @author Bruce Quig
+ */
+public class CommitCommentAction extends TeamAction
+{
+    public CommitCommentAction()
+    {
+        super("team.commit", true);
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.commit"));
+    }
+    
+   /* (non-Javadoc)
+    * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+    */
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        doCommitComment(pmf);
+    }
+    
+    private void doCommitComment(PkgMgrFrame pmf)
+    {
+        if(!pmf.isEmptyFrame()) {
+            Project project = pmf.getProject();
+            CommitCommentsFrame dialog = project.getCommitCommentsDialog();
+            
+            dialog.reset();
+            dialog.setVisible(true);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/ImportAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/ImportAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..957f692541e6720849c2b4f132af421492bde01d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/ImportAction.java
@@ -0,0 +1,133 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import java.awt.EventQueue;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import bluej.Config;
+import bluej.groupwork.Repository;
+import bluej.groupwork.TeamSettingsController;
+import bluej.groupwork.TeamUtils;
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.utility.DialogManager;
+import bluej.utility.Utility;
+
+/**
+ * An action to perform an import into a repository, i.e. to share a project.
+ * 
+ * @author Kasper
+ */
+public class ImportAction extends TeamAction 
+{
+    public ImportAction()
+    {
+        super("team.import");
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        Project project = pmf.getProject();
+        
+        if (project == null) {
+            return;
+        }
+        
+        doImport(pmf, project);
+    }
+
+    private void doImport(final PkgMgrFrame pmf, final Project project)
+    {
+        // The team settings controller is not initially associated with the
+        // project, so you can still modify the repository location
+        final TeamSettingsController tsc = new TeamSettingsController(project.getProjectDir());
+        final Repository repository = tsc.getRepository(true);
+        
+        if (repository == null) {
+            // user cancelled
+            return;
+        }
+
+        try {
+            project.saveAll();
+            project.saveAllEditors();
+        }
+        catch(IOException ioe) {
+            String msg = DialogManager.getMessage("team-error-saving-project");
+            if (msg != null) {
+                msg = Utility.mergeStrings(msg, ioe.getLocalizedMessage());
+                DialogManager.showErrorText(pmf, msg);
+                return;
+            }
+        }
+        setStatus(Config.getString("team.sharing"));
+        startProgressBar(); 
+        
+        Thread thread = new Thread() {
+            
+            TeamworkCommandResult result = null;
+            
+            public void run()
+            {
+                // boolean resetStatus = true;
+                TeamworkCommand command = repository.shareProject();
+                result = command.getResult();
+
+                if (! result.isError()) {
+                    project.setTeamSettingsController(tsc);
+                    Set<File> files = tsc.getProjectFiles(true);
+                    Set<File> newFiles = new LinkedHashSet<File>(files);
+                    Set<File> binFiles = TeamUtils.extractBinaryFilesFromSet(newFiles);
+                    command = repository.commitAll(newFiles, binFiles, Collections.<File>emptySet(),
+                            files, Config.getString("team.import.initialMessage"));
+                    result = command.getResult();
+                }
+
+                stopProgressBar();
+
+                EventQueue.invokeLater(new Runnable() {
+                    public void run()
+                    {
+                        handleServerResponse(result);
+                        if(! result.isError()) {
+                            setStatus(Config.getString("team.shared"));
+                        }
+                        else {
+                            clearStatus();
+                        }
+                    }
+                });
+            }
+        };
+        thread.start();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/ShowLogAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/ShowLogAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..5653f7ecba87af5835779cf0eba568b877bdda6b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/ShowLogAction.java
@@ -0,0 +1,48 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import bluej.Config;
+import bluej.groupwork.ui.HistoryFrame;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * An action to show the repository history.
+ * 
+ * @author Davin McCall
+ * @version $Id: ShowLogAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class ShowLogAction extends TeamAction
+{
+    public ShowLogAction()
+    {
+        super(Config.getString("team.history"), false);
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        HistoryFrame hd = new HistoryFrame(pmf);
+        hd.setLocationRelativeTo(pmf);
+        hd.setVisible(true);
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/StatusAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/StatusAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..5cf95f8b883dbee8d8fcc450f685fc8b11980d24
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/StatusAction.java
@@ -0,0 +1,61 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import bluej.Config;
+import bluej.groupwork.ui.StatusFrame;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+
+
+/**
+ * Action to show status.
+ * 
+ * @author bquig
+ * @version $Id$
+ */
+public class StatusAction extends TeamAction
+{
+    /** Creates a new instance of StatusAction */
+    public StatusAction()
+    {
+        super("team.status", false);
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.status"));
+    }
+
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        // save all bluej.pkg files first
+        Project project = pmf.getProject();
+        project.saveAll();
+        doStatus(pmf);
+    }
+
+    private void doStatus(PkgMgrFrame pmf)
+    {
+        if (pmf.getProject().getTeamSettingsController().initRepository()) {
+            StatusFrame status = pmf.getProject().getStatusWindow(pmf);
+            status.setVisible(true);
+            status.update();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/TeamAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/TeamAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..d041de96d6e3aade04f4615af418afb2bb57160d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/TeamAction.java
@@ -0,0 +1,138 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Icon;
+
+import bluej.Config;
+import bluej.groupwork.TeamUtils;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.actions.PkgMgrAction;
+
+
+/**
+ * An abstract class for team actions. 
+ * 
+ * @author fisker
+ * @version $Id: TeamAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public abstract class TeamAction extends AbstractAction
+{
+    private PkgMgrFrame pkgMgrFrame;
+
+    /**
+     * Constructor for a team action.
+     * 
+     * @param name  The key for the action name (team.xxx.yyy)
+     */
+    public TeamAction(String name)
+    {
+        this(Config.getString(name), false);
+    }
+    
+    /**
+     * Constructor for a team action which shows a dialog. An ellipsis
+     * is added to the action text.
+     * 
+     * @param name   The key for action text
+     * @param showsDialog  True if an ellipsis should be appended
+     */
+    public TeamAction(String name, boolean showsDialog)
+    {
+        super(showsDialog ? Config.getString(name) + "..." : Config.getString(name));
+        if (!Config.isMacOS()){
+        	// Mnemonic keys are against the apple gui guidelines.
+        	putValue(MNEMONIC_KEY, new Integer(Config.getMnemonicKey(name)));
+        }
+        if (Config.hasAcceleratorKey(name)){
+            putValue(ACCELERATOR_KEY, Config.getAcceleratorKey(name));
+        }
+    }
+
+    /**
+     * Constructor for a team action
+     * 
+     * @param name  The key for the action name
+     * @param icon  The icon for the action
+     */
+    public TeamAction(String name, Icon icon)
+    {
+        super(name, icon);
+    }
+
+    /* (non-Javadoc)
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        pkgMgrFrame = PkgMgrAction.frameFromEvent(e);
+        actionPerformed(pkgMgrFrame);
+    }
+    
+    /**
+     * Invoked when the action occurs.
+     * 
+     * @param pmf The PkgMgrFrame in which the action occurred.
+     */
+    public abstract void actionPerformed(PkgMgrFrame pmf);
+    
+    /**
+     * Handle a server response in an appropriate fashion, i.e. if the response
+     * indicates an error, then display an error dialog. 
+     * 
+     * @param basicServerResponse  The response to handle
+     */
+    protected void handleServerResponse(TeamworkCommandResult result)
+    {
+        TeamUtils.handleServerResponse(result, pkgMgrFrame);
+    }
+
+    /**
+     * Start the activity indicator. This can be called from any thread.
+     */
+    protected void startProgressBar()
+    {
+        pkgMgrFrame.startProgress();
+    }
+
+    /**
+     * Stop the activity indicator. This can be called from any thread.
+     */
+    protected void stopProgressBar()
+    {
+        pkgMgrFrame.stopProgress();
+    }
+    
+    protected void setStatus(String statusMessage)
+    {
+        pkgMgrFrame.setStatus(statusMessage);
+    }
+
+    protected void clearStatus()
+    {
+        pkgMgrFrame.clearStatus();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/TeamActionGroup.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/TeamActionGroup.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8e286622b4d69f9d219cae0d718b9f582d9b207
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/TeamActionGroup.java
@@ -0,0 +1,101 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+
+/**
+ * A class to group team actions for a project, and manage enable/disable
+ * of the actions.
+ * 
+ * @author Davin McCall
+ */
+public class TeamActionGroup
+{
+    private StatusAction statusAction = new StatusAction();
+    private UpdateDialogAction updateAction = new UpdateDialogAction();
+    private TeamSettingsAction teamSettingsAction = new TeamSettingsAction();
+    private CommitCommentAction commitCommentAction = new CommitCommentAction();
+    private ImportAction importAction = new ImportAction();
+    private ShowLogAction showLogAction = new ShowLogAction();
+    
+    /**
+     * Construct a new team action group, with various actions disabled
+     * or enabled depending whether we are in team mode or non-team mode.
+     */
+    public TeamActionGroup(boolean teamMode)
+    {
+        setTeamMode(teamMode);
+    }
+    
+    public StatusAction getStatusAction()
+    {
+        return statusAction;
+    }
+    
+    public UpdateDialogAction getUpdateAction()
+    {
+        return updateAction;
+    }
+    
+    public TeamSettingsAction getTeamSettingsAction()
+    {
+        return teamSettingsAction;
+    }
+    
+    public CommitCommentAction getCommitCommentAction()
+    {
+        return commitCommentAction;
+    }
+    
+    public ImportAction getImportAction()
+    {
+        return importAction;
+    }
+    
+    public ShowLogAction getShowLogAction()
+    {
+        return showLogAction;
+    }
+    
+    public void setTeamMode(boolean enabled)
+    {
+        statusAction.setEnabled(enabled);
+        updateAction.setEnabled(enabled);
+        teamSettingsAction.setEnabled(enabled);
+        commitCommentAction.setEnabled(enabled);
+        showLogAction.setEnabled(enabled);
+        
+        // import is allowed if we are not already shared
+        importAction.setEnabled(!enabled);
+    }
+    
+    public void setAllDisabled()
+    {
+        statusAction.setEnabled(false);
+        updateAction.setEnabled(false);
+        teamSettingsAction.setEnabled(false);
+        commitCommentAction.setEnabled(false);
+        importAction.setEnabled(false);
+        showLogAction.setEnabled(false);
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/TeamSettingsAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/TeamSettingsAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..803feab7a17198596257cdaa61e400731f537727
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/TeamSettingsAction.java
@@ -0,0 +1,47 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.actions.PkgMgrAction;
+
+
+/**
+ * Action to show teamwork settings dialog
+ * 
+ * @version $Id$
+ */
+public class TeamSettingsAction extends PkgMgrAction
+{
+    /** Creates a new instance of TeamSettingsAction */
+    public TeamSettingsAction()
+    {
+        super("team.settings");
+    }
+
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        Project project = pmf.getProject();
+        project.getTeamSettingsDialog().doTeamSettings();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/UpdateAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/UpdateAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..9973cc7e7db59f93f15b3681256ec92e964e44e5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/UpdateAction.java
@@ -0,0 +1,531 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import java.awt.EventQueue;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+import javax.swing.AbstractAction;
+import javax.swing.SwingUtilities;
+
+import bluej.Config;
+import bluej.groupwork.*;
+import bluej.groupwork.ui.ConflictsDialog;
+import bluej.groupwork.ui.UpdateFilesFrame;
+import bluej.pkgmgr.BlueJPackageFile;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.PackageTarget;
+import bluej.pkgmgr.target.ReadmeTarget;
+import bluej.pkgmgr.target.Target;
+import bluej.utility.DialogManager;
+import bluej.utility.JavaNames;
+import bluej.utility.SwingWorker;
+
+
+/**
+ * Action to update out-of-date files.
+ * 
+ * <p>Before this action is enabled, setFilesToUpdate(), setFilesToForceUpdate()
+ * and setStatusHandle() must each be called.
+ * 
+ * @author Kasper Fisker
+ */
+public class UpdateAction extends AbstractAction
+{
+    private Project project;
+    private boolean includeLayout = true;
+    private UpdateFilesFrame updateFrame;
+    private UpdateWorker worker;
+    
+    private Set<File> filesToUpdate;
+    private Set<File> filesToForceUpdate;
+    private StatusHandle statusHandle;
+    
+    /** A list of packages whose bluej.pkg file has been removed */
+    private List<String> removedPackages;
+    
+    public UpdateAction(UpdateFilesFrame updateFrame)
+    {
+        super(Config.getString("team.update"));
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.update"));
+        this.updateFrame = updateFrame;
+    }
+
+    /**
+     * Set the files to be updated (changes merged if necessary).
+     * @files a Set of File
+     */
+    public void setFilesToUpdate(Set<File> files)
+    {
+        filesToUpdate = files;
+    }
+    
+    /**
+     * Set the files to be updated with a clean copy of the repository
+     * @files a Set of File
+     */
+    public void setFilesToForceUpdate(Set<File> files)
+    {
+        filesToForceUpdate = files;
+    }
+    
+    /**
+     * Set the status handle (which comes from a preceeding status operation).
+     */
+    public void setStatusHandle(StatusHandle statusHandle)
+    {
+        this.statusHandle = statusHandle;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(ActionEvent event)
+    {
+        project = updateFrame.getProject();
+        
+        if (project != null) {
+            updateFrame.startProgress();
+            PkgMgrFrame.displayMessage(project, Config.getString("team.update.statusMessage"));
+            
+            worker = new UpdateWorker(project, statusHandle,
+                    filesToUpdate, filesToForceUpdate);
+            worker.start();
+        }
+    }
+
+    /**
+     * Cancel the update, if it is presently running.
+     */
+    public void cancel()
+    {
+        if (worker != null) {
+            worker.abort();
+        }
+        setEnabled(true);
+    }
+    
+    private class UpdateWorker extends SwingWorker implements UpdateListener
+    {
+        private TeamworkCommand command;
+        private TeamworkCommandResult result;
+        private boolean aborted;
+        
+        public UpdateWorker(Project project, StatusHandle statusHandle,
+                Set<File> filesToUpdate, Set<File> filesToForceUpdate)
+        {
+            command = statusHandle.updateTo(this, filesToUpdate, filesToForceUpdate);
+        }
+        
+        public Object construct()
+        {
+            removedPackages = new ArrayList<String>();
+            result = command.getResult();
+            return result;
+        }
+
+        /* (non-Javadoc)
+         * @see bluej.groupwork.UpdateListener#fileAdded(java.io.File)
+         */
+        public void fileAdded(final File f)
+        {
+            SwingUtilities.invokeLater(new Runnable() {
+                public void run()
+                {
+                    project.prepareCreateDir(f.getParentFile());
+                    
+                    String fileName = f.getName();
+                    if (! fileName.endsWith(".java") &&
+                            ! fileName.endsWith(".class") &&
+                            ! BlueJPackageFile.isPackageFileName(fileName)) {
+                        return;
+                    }
+                    
+                    // First find out the package name...
+                    String packageName = project.getPackageForFile(f);
+                    if (packageName == null) {
+                        return;
+                    }
+                    
+                    if (BlueJPackageFile.isPackageFileName(fileName)) {
+                        if (packageName.length() > 0) {
+                            // If we now have a new package, we might need to add it
+                            // as a target in an existing package
+                            String parentPackageName = JavaNames.getPrefix(packageName);
+                            Package parentPackage = project.getCachedPackage(parentPackageName);
+                            if (parentPackage != null) {
+                                Target t = parentPackage.addPackage(JavaNames.getBase(packageName));
+                                parentPackage.positionNewTarget(t);
+                            }
+                        }
+                    }
+                    else {
+                        int n = fileName.lastIndexOf(".");
+                        String name = fileName.substring(0, n);
+                        if (! JavaNames.isIdentifier(name)) {
+                            return;
+                        }
+                        
+                        Package pkg = project.getCachedPackage(packageName);
+                        if (pkg == null) {
+                            return;
+                        }
+                        Target t = pkg.getTarget(name);
+                        if (t != null && ! (t instanceof ClassTarget)) {
+                            return;
+                        }
+                        ClassTarget ct = (ClassTarget) t;
+                        if (ct == null) {
+                            ct = pkg.addClass(name);
+                            pkg.positionNewTarget(ct);
+                        }
+                        ct.reload();
+                    }
+                }
+            });
+        }
+        
+        /* (non-Javadoc)
+         * @see bluej.groupwork.UpdateListener#fileRemoved(java.io.File)
+         */
+        public void fileRemoved(final File f)
+        {
+            SwingUtilities.invokeLater(new Runnable() {
+               public void run()
+                {
+                   String fileName = f.getName();
+                   if (! fileName.endsWith(".java") &&
+                           ! fileName.endsWith(".class") &&
+                           ! BlueJPackageFile.isPackageFileName(fileName)) {
+                       return;
+                   }
+                   
+                   // First find out the package name...
+                   String packageName = project.getPackageForFile(f);
+                   if (packageName == null) {
+                       return;
+                   }
+                   
+                   if (BlueJPackageFile.isPackageFileName(fileName)) {
+                       // Delay removing the package until
+                       // after the update has finished, and only do it if there
+                       // are no files left in the package.
+                       removedPackages.add(packageName);
+                   }
+                   else {
+                       // Remove a class
+                       int n = fileName.lastIndexOf(".");
+                       String name = fileName.substring(0, n);
+                       Package pkg = project.getCachedPackage(packageName);
+                       if (pkg == null) {
+                           return;
+                       }
+                       Target t = pkg.getTarget(name);
+                       if (! (t instanceof ClassTarget)) {
+                           return;
+                       }
+                       
+                       ClassTarget ct = (ClassTarget) t;
+                       if (ct.hasSourceCode() && ! fileName.endsWith(".java")) {
+                           ct.setInvalidState();
+                       }
+                       else {
+                           ct.remove();
+                       }
+                   }
+                } 
+            });
+        }
+        
+        /* (non-Javadoc)
+         * @see bluej.groupwork.UpdateListener#fileUpdated(java.io.File)
+         */
+        public void fileUpdated(final File f)
+        {
+            SwingUtilities.invokeLater(new Runnable() {
+                public void run()
+                {
+                    String fileName = f.getName();
+                    if (! fileName.endsWith(".java") &&
+                            ! fileName.endsWith(".class") &&
+                            ! BlueJPackageFile.isPackageFileName(fileName)) {
+                        return;
+                    }
+                    
+                    // First find out the package name...
+                    String packageName = project.getPackageForFile(f);
+                    if (packageName == null) {
+                        return;
+                    }
+                    Package pkg = project.getCachedPackage(packageName);
+                    if (pkg == null) {
+                        return;
+                    }
+                    
+                    if (BlueJPackageFile.isPackageFileName(fileName)) {
+                        try {
+                            if (includeLayout) {
+                                pkg.reReadGraphLayout();
+                            }
+                        }
+                        catch (IOException ioe) {
+                            ioe.printStackTrace();
+                        }
+                    }
+                    else {
+                        int n = fileName.lastIndexOf(".");
+                        String name = fileName.substring(0, n);
+                        Target t = pkg.getTarget(name);
+                        if (! (t instanceof ClassTarget)) {
+                            return;
+                        }
+                        
+                        ClassTarget ct = (ClassTarget) t;
+                        ct.reload();
+                    }
+                }
+            });
+        }
+        
+        /* (non-Javadoc)
+         * @see bluej.groupwork.UpdateListener#dirRemoved(java.io.File)
+         */
+        public void dirRemoved(final File f)
+        {
+            SwingUtilities.invokeLater(new Runnable() {
+                public void run()
+                {
+                    String path = makeRelativePath(project.getProjectDir(), f);
+                    String pkgName = path.replace(File.separatorChar, '.');
+                    removedPackages.add(pkgName);
+                }
+            });
+        }
+        
+        /* (non-Javadoc)
+         * @see bluej.groupwork.UpdateListener#handleConflicts(bluej.groupwork.UpdateServerResponse)
+         */
+        public void handleConflicts(final UpdateResults updateServerResponse)
+        {
+            if (updateServerResponse == null) {
+                return;
+            }
+
+            if (updateServerResponse.getConflicts().size() <= 0
+                    && updateServerResponse.getBinaryConflicts().size() <= 0) {
+                return;
+            }
+
+            try {
+                EventQueue.invokeAndWait(new Runnable() {
+                    public void run()
+                    {
+                        /** A list of files to replace with repository version */
+                        Set<File> filesToOverride = new HashSet<File>();
+
+                        // Binary conflicts
+                        for (Iterator<File> i = updateServerResponse.getBinaryConflicts().iterator();
+                                i.hasNext(); ) {
+                            File f = i.next();
+
+                            if (BlueJPackageFile.isPackageFileName(f.getName())) {
+                                filesToOverride.add(f);
+                            }
+                            else {
+                                // TODO make the displayed file path relative to project
+                                int answer = DialogManager.askQuestion(PkgMgrFrame.getMostRecent(),
+                                        "team-binary-conflict", new String[] {f.getName()});
+                                if (answer == 0) {
+                                    // keep local version
+                                }
+                                else {
+                                    // use repository version
+                                    filesToOverride.add(f);
+                                }
+                            }
+                        }
+
+                        updateServerResponse.overrideFiles(filesToOverride);
+
+                        List<String> blueJconflicts = new LinkedList<String>();
+                        List<String> nonBlueJConflicts = new LinkedList<String>();
+                        List<Target> targets = new LinkedList<Target>();
+
+                        for (Iterator<File> i = updateServerResponse.getConflicts().iterator();
+                                i.hasNext();) {
+                            File file = i.next();
+
+                            // Calculate the file base name
+                            String baseName = file.getName();
+
+                            // bluej package file may come up as a conflict, but it won't cause a problem,
+                            // so it can be ignored.
+                            if (! BlueJPackageFile.isPackageFileName(baseName)) {
+                                Target target = null;
+
+                                if (baseName.endsWith(".java") || baseName.endsWith(".class")) {
+                                    String pkg = project.getPackageForFile(file);
+                                    if (pkg != null) {
+                                        String targetId = filenameToTargetIdentifier(baseName);
+                                        targetId = JavaNames.combineNames(pkg, targetId);
+                                        target = project.getTarget(targetId);
+                                    }
+                                }
+                                else if (baseName.equals("README.TXT")) {
+                                    String pkg = project.getPackageForFile(file);
+                                    if (pkg != null) {
+                                        String targetId = ReadmeTarget.README_ID;
+                                        targetId = JavaNames.combineNames(pkg, targetId);
+                                        target = project.getTarget(targetId);
+                                    }
+                                }
+
+                                String fileName = makeRelativePath(project.getProjectDir(), file);
+                                
+                                if (target == null) {
+                                    nonBlueJConflicts.add(fileName);
+                                } else {
+                                    blueJconflicts.add(fileName);
+                                    targets.add(target);
+                                }
+                            }
+                        }
+
+                        if (! blueJconflicts.isEmpty() || ! nonBlueJConflicts.isEmpty()) {
+                            project.clearAllSelections();
+                            project.selectTargetsInGraphs(targets);
+
+                            ConflictsDialog conflictsDialog = new ConflictsDialog(project,
+                                    blueJconflicts, nonBlueJConflicts);
+                            conflictsDialog.setVisible(true);
+                        }
+                    }
+                });
+            }
+            catch (InvocationTargetException ite) {
+                throw new Error(ite);
+            }
+            catch (InterruptedException ie) {
+                // Probably indicates an application exit; just ignore it.
+            }
+        }
+        
+        public void abort()
+        {
+            command.cancel();
+            aborted = true;
+        }
+        
+        public void finished()
+        {
+            handleRemovedPkgs();
+            updateFrame.stopProgress();
+
+            if (! result.isError() && ! aborted) {
+                Set<File> files = new HashSet<File>();
+                files.addAll(filesToUpdate);
+                files.addAll(filesToForceUpdate);
+                PkgMgrFrame.displayMessage(project, Config.getString("team.update.statusDone"));
+            }
+            else {
+                PkgMgrFrame.displayMessage(project, "");
+                TeamUtils.handleServerResponse(result, updateFrame);
+            }
+            
+            if (! aborted) {
+                updateFrame.setVisible(false);
+                updateFrame.dispose();
+                setEnabled(true);
+            }
+        }
+        
+        /**
+         * If packages were removed by the update, remove them from the
+         * parent package graph.
+         */
+        private void handleRemovedPkgs()
+        {
+            for (Iterator<String> i = removedPackages.iterator(); i.hasNext(); ) {
+                String packageName = i.next();
+                String parentPackage = JavaNames.getPrefix(packageName);
+                String baseName = JavaNames.getBase(packageName);
+                
+                File packageDir = JavaNames.convertQualifiedNameToFile(packageName, project.getProjectDir());
+                if (! packageDir.exists()) {
+                    // Close the package window, if open
+                    Package pkg = project.getCachedPackage(packageName);
+                    if (pkg != null) {
+                        pkg.closeAllEditors();
+                        PkgMgrFrame frame = PkgMgrFrame.findFrame(pkg);
+                        if (frame != null) {
+                            frame.doClose(true, false);
+                        }
+                        project.removePackage(packageName);
+                    }
+                    
+                    // Get the parent package so we can remove the child.
+                    pkg = project.getCachedPackage(parentPackage);
+                    if (pkg != null) {
+                        Target target = pkg.getTarget(baseName);
+                        if (target instanceof PackageTarget) {
+                            pkg.removeTarget(target);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Strip the dot-suffix from a file name.
+     * @param filename
+     * @return
+     */
+    private String filenameToTargetIdentifier(String filename)
+    {
+        int lastDot = filename.lastIndexOf('.');
+        return filename.substring(0, lastDot);
+    }
+    
+    /**
+     * Make a relative path between a file and containing directory. 
+     */
+    private static String makeRelativePath(File parent, File file)
+    {
+        String parentStr = parent.getAbsolutePath();
+        String filePath = file.getAbsolutePath();
+        
+        if (filePath.startsWith(parentStr)) {
+            // remove parent, plus path separator character
+            filePath = filePath.substring(parentStr.length() + 1);
+        }
+        
+        return filePath;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/UpdateDialogAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/UpdateDialogAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..290eeb1d0882c906ab229bd2fefc3db41f33cd7d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/UpdateDialogAction.java
@@ -0,0 +1,54 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+
+
+/**
+ * Action to show dialog for updating out-of-date files.
+ * 
+ * @author Davin McCall
+ */
+public class UpdateDialogAction extends TeamAction
+{
+    private Project project;
+    
+    public UpdateDialogAction()
+    {
+        super("team.update", true);
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.update"));
+    }
+
+    /* (non-Javadoc)
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        project = pmf.getProject();
+        if (project != null) {
+            project.getUpdateDialog().setVisible(true);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/ValidateConnectionAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/ValidateConnectionAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..b758daec5faeda03ac32d16021cc535e399a049c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/actions/ValidateConnectionAction.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.actions;
+
+import java.awt.Dialog;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import bluej.groupwork.TeamSettings;
+import bluej.groupwork.TeamworkProvider;
+import bluej.groupwork.ui.CheckConnectionDialog;
+import bluej.groupwork.ui.TeamSettingsPanel;
+
+/**
+ * Test the username, password, host, etc. settings to make sure they are valid
+ * 
+ * @author fisker
+ */
+public class ValidateConnectionAction extends AbstractAction
+{
+    private TeamSettingsPanel teamSettingsPanel;
+    private Dialog owner;
+    
+    public ValidateConnectionAction(String name, TeamSettingsPanel teamSettingsPanel,
+            Dialog owner)
+    {
+        super(name);
+        this.teamSettingsPanel = teamSettingsPanel;
+        this.owner = owner;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        TeamworkProvider provider = teamSettingsPanel.getSelectedProvider();
+        TeamSettings settings = teamSettingsPanel.getSettings();
+        
+        new CheckConnectionDialog(owner, provider, settings).setVisible(true);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BasicServerResponse.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BasicServerResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc2413a3f0805913f37bcce21bdd2517ffc0ecf4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BasicServerResponse.java
@@ -0,0 +1,195 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import org.netbeans.lib.cvsclient.event.BinaryMessageEvent;
+import org.netbeans.lib.cvsclient.event.CVSListener;
+import org.netbeans.lib.cvsclient.event.FileAddedEvent;
+import org.netbeans.lib.cvsclient.event.FileInfoEvent;
+import org.netbeans.lib.cvsclient.event.FileRemovedEvent;
+import org.netbeans.lib.cvsclient.event.FileToRemoveEvent;
+import org.netbeans.lib.cvsclient.event.FileUpdatedEvent;
+import org.netbeans.lib.cvsclient.event.MessageEvent;
+import org.netbeans.lib.cvsclient.event.ModuleExpansionEvent;
+import org.netbeans.lib.cvsclient.event.TerminationEvent;
+
+
+/**
+ * This class is used by registering it with the EventManager of the client
+ * which is to execute a command.
+ * client.getEventManager().addCVSListener(updateServerResponse);
+ * The BasicServerResponse will record the messages from the server that the
+ * server wants the user to see in response to the command. It also offers a way
+ * to wait for the command to finish.
+ * @author fisker
+ *
+ */
+public class BasicServerResponse implements CVSListener
+{
+    /**
+     * Stores a tagged line
+     */
+    private final StringBuffer taggedLine = new StringBuffer();
+    private StringBuffer message = new StringBuffer();
+    boolean isTerminated = false;
+    private TerminationEvent terminationEvent;
+    private String newline = System.getProperty("line.separator");
+
+    /**
+     * Called when the server wants to send a message to be displayed to
+     * the user. The message is only for information purposes and clients
+     * can choose to ignore these messages if they wish.
+     * @param e the event
+     */
+    public void messageSent(MessageEvent e)
+    {
+        String line = e.getMessage();
+        // PrintStream stream = e.isError() ? System.err : System.out;
+
+        if (e.isTagged()) {
+            String message = MessageEvent.parseTaggedMessage(taggedLine, line);
+
+            // if we get back a non-null line, we have something
+            // to output. Otherwise, there is more to come and we
+            // should do nothing yet.
+            if (message != null) {
+                // this.message.append(message);
+                if (e.isError()) {
+                    System.err.println("CVS: " + message);
+                }
+                //else {
+                //    System.out.println("CVS: " + message);
+                //}
+            }
+        } else {
+            if (e.isError()) {
+                System.err.println("CVS: " + line);
+                message.append(line + newline);
+            }
+            //else {
+            //    System.out.println("CVS: " + line);
+            //}
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.netbeans.lib.cvsclient.event.CVSListener#messageSent(org.netbeans.lib.cvsclient.event.BinaryMessageEvent)
+     */
+    public void messageSent(BinaryMessageEvent e)
+    {
+        //System.out.println("BasicServerResponse: 68: " + e.getMessage());
+    }
+
+    /* (non-Javadoc)
+     * @see org.netbeans.lib.cvsclient.event.CVSListener#fileAdded(org.netbeans.lib.cvsclient.event.FileAddedEvent)
+     */
+    public void fileAdded(FileAddedEvent arg0)
+    {
+        //Debug.message("BasicServerResponse: fileAdded: " + arg0.getFilePath());
+    }
+
+    /* (non-Javadoc)
+     * @see org.netbeans.lib.cvsclient.event.CVSListener#fileRemoved(org.netbeans.lib.cvsclient.event.FileRemovedEvent)
+     */
+    public void fileRemoved(FileRemovedEvent arg0)
+    {
+        //Debug.message("BasicServerResponse: fileRemoved: " + arg0.getFilePath());
+    }
+
+    /* (non-Javadoc)
+     * @see org.netbeans.lib.cvsclient.event.CVSListener#fileUpdated(org.netbeans.lib.cvsclient.event.FileUpdatedEvent)
+     */
+    public void fileUpdated(FileUpdatedEvent arg0)
+    {
+        //Debug.message("BasicServerResponse: fileUpdated: " + arg0.getFilePath());
+    }
+
+    /* (non-Javadoc)
+     * @see org.netbeans.lib.cvsclient.event.CVSListener#fileInfoGenerated(org.netbeans.lib.cvsclient.event.FileInfoEvent)
+     */
+    public void fileInfoGenerated(FileInfoEvent arg0)
+    {
+        //FileInfoContainer fic = arg0.getInfoContainer();
+        //Debug.message("BasicServerResponse: fileInfoGenerated: " + fic.getClass() + ": " + arg0.getInfoContainer().getFile());
+    }
+
+    public void fileToRemove(FileToRemoveEvent ftre)
+    {
+        //Debug.message("BasicServerResponse: fileToRemove: " + ftre.getFilePath());
+    }
+
+    /* (non-Javadoc)
+     * @see org.netbeans.lib.cvsclient.event.CVSListener#commandTerminated(org.netbeans.lib.cvsclient.event.TerminationEvent)
+     */
+    public void commandTerminated(TerminationEvent terminationEvent)
+    {
+        isTerminated = true;
+
+        this.terminationEvent = terminationEvent;
+
+        synchronized (this) {
+            notifyAll();
+        }
+    }
+
+    /**
+     * When this method is called, it blocks the caller until the command being
+     * executed is finished.
+     */
+    public synchronized void waitForExecutionToFinish()
+    {
+        while (!isTerminated) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                // nothing to do
+            }
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.netbeans.lib.cvsclient.event.CVSListener#moduleExpanded(org.netbeans.lib.cvsclient.event.ModuleExpansionEvent)
+     */
+    public void moduleExpanded(ModuleExpansionEvent arg0)
+    {
+    }
+
+    /**
+     * Returns whether the command was executed succesfully.
+     * @return True if the command was executed succesfully
+     */
+    public boolean isError()
+    {
+        waitForExecutionToFinish();
+
+        return terminationEvent != null && terminationEvent.isError();
+    }
+
+    /**
+     * Get the message from the server.
+     * @return String contaning the message
+     */
+    public String getMessage()
+    {
+        return message.toString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BlueJAdminHandler.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BlueJAdminHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..a35072aac5d587e464af9973b5933561aaa481ee
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BlueJAdminHandler.java
@@ -0,0 +1,329 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.netbeans.lib.cvsclient.admin.Entry;
+import org.netbeans.lib.cvsclient.admin.StandardAdminHandler;
+import org.netbeans.lib.cvsclient.command.GlobalOptions;
+
+import bluej.utility.Debug;
+import bluej.utility.FileUtility;
+
+/**
+ * A CVS admin handler for BlueJ. The main difference between this and the
+ * standard admin handler is that the BlueJ handler knows that deleted packages
+ * have their metadata (CVS/Entries file) stored in an alternate location
+ * (project_root/CVS/deleted).<p>
+ * 
+ * This admin handler also has a "mild-mannered mode" which pretends that all
+ * directories exist. This is useful for certain commands when we want to find
+ * out about what exists in the repository, even if it doesn't exist locally.
+ * 
+ * @author Davin McCall
+ */
+public class BlueJAdminHandler extends StandardAdminHandler
+{
+    File projectDir;
+    
+    /** "mild-mannered" mode */
+    private boolean mode = false;
+    
+    public BlueJAdminHandler(File projectDir)
+    {
+        this.projectDir = projectDir;
+    }
+    
+    /**
+     * Switch the admin handler between mild-mannered mode and
+     * standard mode. In mild-mannered mode, directories are reported as
+     * existing even if they are not present locally. This can be used to
+     * convince the CVS library to give us information about what might
+     * be contained within such directories.
+     * 
+     * @param mode  true for mild-mannered mode
+     */
+    public void setMildManneredMode(boolean mode)
+    {
+        this.mode = mode;
+    }
+
+    /**
+     * Prepare for the deletion of a directory. This is called just before
+     * the directory is deleted. For CVS, we move the metadata to the
+     * "CVS/deleted" subdirectory of the project so as not to lose it.
+     */
+    public void prepareDeleteDir(File dir)
+    {
+        File cvsDir = new File(dir, "CVS");
+        if (cvsDir.isDirectory()) {
+            String relPath = getRelativePath(dir.getAbsolutePath());
+            
+            File newMetaDir = new File(projectDir, "CVS");
+            newMetaDir = new File(newMetaDir, "deleted");
+            newMetaDir = new File(newMetaDir, relPath);
+            
+            newMetaDir.mkdirs();
+            
+            if (! cvsDir.renameTo(new File(newMetaDir, "CVS"))) {
+                Debug.message("Rename of meta-data directory failed: " + cvsDir);
+            }
+        }
+    }
+    
+    /**
+     * Prepare for creation of new directory. This is called just after the
+     * directory has actually been created.
+     * 
+     * If we have metadata for the named directory stored under the
+     * "CVS/deleted" hierarchy, we move it back to the "normal" place.
+     */
+    public void prepareCreateDir(File dir)
+    {
+        String relPath = getRelativePath(dir.getAbsolutePath());
+        
+        File newMetaDir = new File(projectDir, "CVS");
+        newMetaDir = new File(newMetaDir, "deleted");
+        newMetaDir = new File(newMetaDir, relPath);
+
+        if (newMetaDir.exists()) {
+            File cvsDir = new File(newMetaDir, "CVS");
+            if (! cvsDir.renameTo(new File(dir, "CVS"))) {
+                Debug.message("Rename of meta-data directory failed: " + cvsDir);
+            }
+            
+            while (newMetaDir.delete()) {
+                newMetaDir = newMetaDir.getParentFile();
+            }
+        }
+    }
+        
+    /**
+     * Get the relative path (from the project directory) to an absolute directory
+     * within. Returns null if the directory is not within the project.
+     */
+    private String getRelativePath(String directory)
+    {
+        String projDirString = projectDir.toString();
+        if (! directory.startsWith(projDirString)) {
+            return null;
+        }
+        
+        directory = directory.substring(projDirString.length());
+        if (directory.startsWith(File.pathSeparator)) {
+            directory = directory.substring(1);
+        }
+        
+        return directory;
+    }
+    
+    /**
+     * Get the directory which actually contains the "CVS" subfolder with metadata
+     * for files in the given directory.
+     */
+    public String getMetaDataPath(String directory)
+    {
+        String relativeDir = getRelativePath(directory);
+        if (relativeDir == null) {
+            // On initial checkout, the "project" directory is not actually any
+            // specific directory.
+            return directory;
+        }
+        
+        File deletedFile = new File(projectDir, "CVS");
+        deletedFile = new File(deletedFile, "deleted");
+        deletedFile = new File(deletedFile, relativeDir);
+        File deletedFileMd = new File(deletedFile, "CVS");
+        
+        if (deletedFileMd.exists()) {
+            return deletedFile.getPath();
+        }
+        else {
+            return directory;
+        }
+    }
+    
+    /**
+     * Get the translated file location for a file. I.e. If the file resides in a deleted
+     * directory, which has been moved to "CVS/deleted", adjust the path accordingly.
+     */
+    private String getMetaDataPathForFile(String absFilePath)
+    {
+        String relativeDir = getRelativePath(absFilePath);
+        if (relativeDir == null) {
+            // On initial checkout, the "project" directory is not actually any
+            // specific directory.
+            return absFilePath;
+        }
+        
+        File deletedFile = new File(projectDir, "CVS");
+        deletedFile = new File(deletedFile, "deleted");
+        deletedFile = new File(deletedFile, relativeDir);
+        File deletedFileMd = new File(deletedFile.getParentFile(), "CVS");
+        
+        if (deletedFileMd.exists()) {
+            return deletedFile.getPath();
+        }
+        else {
+            return absFilePath;
+        }
+    }
+    
+    public void updateAdminData(String localDirectory, String repositoryPath,
+            Entry entry, GlobalOptions globalOptions)
+        throws IOException
+    {
+        localDirectory = getMetaDataPath(localDirectory);
+        super.updateAdminData(localDirectory, repositoryPath, entry, globalOptions);
+    }
+    
+    public boolean exists(File file)
+    {
+        File nFile = new File(getMetaDataPath(file.getAbsolutePath()));
+        boolean result = super.exists(nFile);
+        if (!result) {
+            result = super.exists(file);
+        }
+        return result;
+    }
+
+    public Entry getEntry(File file) throws IOException
+    {
+        file = new File(getMetaDataPathForFile(file.getAbsolutePath()));
+        try {
+            return super.getEntry(file);
+        }
+        catch (IOException ioe) {
+            if (mode) {
+                return null;
+            }
+            else {
+                throw ioe;
+            }
+        }
+    }
+    
+    public Entry[] getEntriesAsArray(File directory) throws IOException
+    {
+        directory = new File(getMetaDataPath(directory.getAbsolutePath()));
+        return super.getEntriesAsArray(directory);
+    }
+
+    @SuppressWarnings("unchecked")
+    public Iterator<Entry> getEntries(File directory) throws IOException
+    {
+        directory = new File(getMetaDataPath(directory.getAbsolutePath()));
+        try {
+            return super.getEntries(directory);
+        }
+        catch (IOException ioe) {
+            if (mode) {
+                return Collections.EMPTY_LIST.iterator();
+            }
+            else {
+                throw ioe;
+            }
+        }
+    }
+    
+    public void setEntry(File file, Entry entry)
+        throws IOException
+    {
+        file = new File(getMetaDataPathForFile(file.getAbsolutePath()));
+        super.setEntry(file, entry);
+    }
+
+    public void removeEntry(File file) throws IOException
+    {
+        file = new File(getMetaDataPathForFile(file.getAbsolutePath()));
+        super.removeEntry(file);
+        
+        // If there are no entries left, we can remove the metadata altogether.
+        if (! super.getEntries(file.getParentFile()).hasNext()) {
+            File pDir = file.getParentFile();
+            File cvsDir = new File(pDir, "CVS");
+            FileUtility.deleteDir(cvsDir);
+            
+            while (pDir.delete()) {
+                pDir = pDir.getParentFile();
+            }
+        }
+    }
+
+    public String getRepositoryForDirectory(String directory,
+            String repository) throws IOException
+    {
+        directory = getMetaDataPath(directory);
+        try {
+            return super.getRepositoryForDirectory(directory, repository);
+        }
+        catch (IOException ioe) {
+            if (mode) {
+                File f = new File(directory);
+                String parentFile = f.getParent();
+                if (parentFile == null) {
+                    throw ioe;
+                }
+                String parentRepository = getRepositoryForDirectory(f.getParent(), repository);
+                return parentRepository + "/" + f.getName();
+            }
+            else {
+                throw ioe;
+            }
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    public Set<File> getAllFiles(File directory) throws IOException
+    {
+        directory = new File(getMetaDataPath(directory.getAbsolutePath()));
+        
+        if (mode && ! directory.exists()) {
+            return Collections.emptySet();
+        }
+
+        Set<File> s = super.getAllFiles(directory);
+        Set<File> newSet = new TreeSet<File>();
+        
+        // Now we need to convert the path back to the correct path.
+        Iterator<File> i = s.iterator();
+        while (i.hasNext()) {
+            File f = (File) i.next();
+            f = new File(directory, f.getName());
+            newSet.add(f);
+        }
+        
+        return newSet;
+    }
+    
+    public String getStickyTagForDirectory(File directory)
+    {
+        directory = new File(getMetaDataPath(directory.getAbsolutePath()));
+        return super.getStickyTagForDirectory(directory);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BlueJCvsClient.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BlueJCvsClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..92dfd343a514187c941a24bf9eeda0a3f330540d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BlueJCvsClient.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.util.Map;
+
+import org.netbeans.lib.cvsclient.Client;
+import org.netbeans.lib.cvsclient.admin.AdminHandler;
+import org.netbeans.lib.cvsclient.connection.Connection;
+
+/**
+ * Provide some additional mechanism over the standard CVS library "Client" class.
+ * Specifically we need to track binary conflicts.
+ * 
+ * @author Davin McCall
+ */
+public class BlueJCvsClient extends Client
+{
+    BlueJFileHandler fileHandler;
+    
+    public BlueJCvsClient(Connection connection, AdminHandler adminHandler)
+    {
+        super(connection, adminHandler);
+        fileHandler = new BlueJFileHandler();
+        setUncompressedFileHandler(fileHandler);
+    }
+    
+    /**
+     * Get the map of conflicting files. The return maps (File to File) the
+     * original file name (repository version) to its backup (local version).
+     */
+    public Map<File,File> getConflictFiles()
+    {
+        return fileHandler.getConflicts();
+    }
+    
+    /**
+     * Inform the BlueJCvsClient that the next conflict detected is a non-binary
+     * conflict.
+     */
+    public void nextConflictNonBinary()
+    {
+        fileHandler.nextConflictNonBinary();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BlueJFileHandler.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BlueJFileHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..cbdd8336767f49226027144e28ed6a8421477f5d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/BlueJFileHandler.java
@@ -0,0 +1,83 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.netbeans.lib.cvsclient.file.DefaultFileHandler;
+
+/**
+ * A file handler which captures file rename operations requested by the server.
+ * Renames are used to make backups of conflicting files; if we capture them
+ * we can give the user the option of keeping one or the other (the local
+ * version, or the repository version).
+ * 
+ * @author Davin McCall
+ */
+public class BlueJFileHandler extends DefaultFileHandler 
+{
+    /** Map a file name to it's backed-up local version */
+    private Map<File,File> conflicts = new HashMap<File,File>();
+    
+    private boolean ignoreNextConflict = false;
+    
+    /**
+     * Inform the file handler that the next conflict is a non-binary
+     * conflict (it doesn't need to be tracked).
+     */
+    public void nextConflictNonBinary()
+    {
+        ignoreNextConflict = true;
+    }
+    
+    /**
+     * Get the conflicts map. This is a map (File to File) which maps the
+     * original file name to the backup file name for each file for which
+     * a backup was created.
+     */
+    public Map<File,File> getConflicts()
+    {
+        return conflicts;
+    }
+    
+    public void renameLocalFile(String pathname, String newName)
+        throws IOException
+    {
+        File path = new File(pathname);
+        File parent = path.getParentFile();
+        File backup = new File(parent, newName);
+        
+        // The backup shouldn't exist; the cvs library explicitly deletes it if
+        // it does, before calling this method. But we'll check for safety.
+        if (! backup.exists()) {
+            if (! ignoreNextConflict) {
+                conflicts.put(path, backup);
+            }
+            super.renameLocalFile(pathname, newName);
+        }
+        
+        ignoreNextConflict = false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCheckoutCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCheckoutCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f11cc6c00238083d932d34be9f3e109ca231a6f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCheckoutCommand.java
@@ -0,0 +1,52 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.command.CommandException;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+
+
+/**
+ * Command to check out a project from a CVS repository.
+ * 
+ * @author Davin McCall
+ */
+public class CvsCheckoutCommand extends CvsCommand
+{
+    private File projectPath;
+    
+    public CvsCheckoutCommand(CvsRepository repository, File projectPath)
+    {
+        super(repository);
+        this.projectPath = projectPath;
+    }
+    
+    protected BasicServerResponse doCommand()
+        throws CommandAbortedException, CommandException, AuthenticationException
+    {
+        BlueJCvsClient client = getClient();
+        return repository.doCheckout(client, projectPath);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..aff3103cd0277a77b531ef1aac0c6877c495cd9d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCommand.java
@@ -0,0 +1,109 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.command.CommandException;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+
+import bluej.groupwork.*;
+
+/**
+ * Base class for Cvs commands. Provides functionality to allow cancelling CVS
+ * operations, and converting CVS library errors (exceptions) to appropriate
+ * teamwork result objects.
+ * 
+ * @author Davin McCall
+ */
+public abstract class CvsCommand
+    implements TeamworkCommand
+{
+    protected CvsRepository repository;
+    private BlueJCvsClient client;
+    private boolean cancelled;
+    
+    protected CvsCommand(CvsRepository repository)
+    {
+        this.repository = repository;
+        cancelled = false;
+    }
+    
+    /**
+     * Get a new client to be used for command processing.
+     */
+    protected synchronized BlueJCvsClient getClient()
+        throws CommandAbortedException, AuthenticationException
+    {
+        if (cancelled) {
+            throw new CommandAbortedException("","");
+        }
+        client = repository.getClient();
+        return client;
+    }
+    
+    public synchronized void cancel()
+    {
+        if (! cancelled) {
+            cancelled = true;
+            if (client != null) {
+                client.abort();
+            }
+        }
+    }
+    
+    public TeamworkCommandResult getResult()
+    {
+        try {
+            BasicServerResponse response = doCommand();
+
+            if (response.isError()) {
+                return new TeamworkCommandError(response.getMessage(), null);
+            }
+
+            // command completed successfully
+            return new TeamworkCommandResult();
+        }
+        catch (CommandAbortedException cae) {
+            return new TeamworkCommandAborted();
+        }
+        catch (CommandException ce) {
+            return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
+        }
+        catch (AuthenticationException ae) {
+            return new TeamworkCommandAuthFailure();
+        }
+    }
+    
+    /**
+     * Actually peform the command and return a response object.
+     * 
+     * @param client  A client, with connection established, for use in processing the
+     *                command.
+     * 
+     * @throws CommandAbortedException
+     * @throws CommandException
+     * @throws AuthenticationException
+     * @throws InvalidCvsRootException
+     */
+    protected abstract BasicServerResponse doCommand()
+        throws CommandAbortedException, CommandException, AuthenticationException;
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCommitAllCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCommitAllCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..4638e3464f05faee6a0ae587f0908bf7403835ba
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCommitAllCommand.java
@@ -0,0 +1,148 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.Set;
+
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.command.CommandException;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+
+
+/**
+ * Command to commit all local changes to the repository. 
+ * 
+ * @author Davin McCall
+ */
+public class CvsCommitAllCommand extends CvsCommand
+{
+    private Set<File> newFiles;
+    private Set<File> binaryNewFiles;
+    private Set<File> deletedFiles;
+    private Set<File> files;
+    private String commitComment;
+    
+    public CvsCommitAllCommand(CvsRepository repository, Set<File> newFiles, Set<File> binaryNewFiles,
+            Set<File> deletedFiles, Set<File> files, String commitComment)
+    {
+        super(repository);
+        this.newFiles = newFiles;
+        this.binaryNewFiles = binaryNewFiles;
+        this.deletedFiles = deletedFiles;
+        this.files = files;
+        this.commitComment = commitComment;
+    }
+    
+    protected BasicServerResponse doCommand()
+        throws CommandAbortedException, CommandException, AuthenticationException
+    {
+        BlueJCvsClient client = getClient();
+        File projectPath = repository.getProjectPath();
+        
+        // First we need to do "cvs add" to put files and directories
+        // under version control if they are not already. Start by building
+        // a list of directories to add.
+        
+        // Note, we need to use a LinkedHashSet to preserve order.
+        Set<File> dirs = new LinkedHashSet<File>();
+        LinkedList<File> stack = new LinkedList<File>();
+        for (Iterator<File> i = newFiles.iterator(); i.hasNext(); ) {
+            File file = i.next();
+            
+            File parent = file.getParentFile();
+            while (! repository.isDirectoryUnderCVS(parent) && ! dirs.contains(parent)) {
+                stack.addLast(parent);
+                if (parent.equals(projectPath)) {
+                    break;
+                }
+                parent = parent.getParentFile();
+            }
+            while (! stack.isEmpty()) {
+                dirs.add(stack.removeLast());
+            }
+        }
+        
+        // The list of directories must include those containing binary files
+        for (Iterator<File> i = binaryNewFiles.iterator(); i.hasNext(); ) {
+            File file = (File) i.next();
+            
+            File parent = file.getParentFile();
+            while (! repository.isDirectoryUnderCVS(parent) && ! dirs.contains(parent)) {
+                stack.addLast(parent);
+                if (parent.equals(projectPath)) {
+                    break;
+                }
+                parent = parent.getParentFile();
+            }
+            while (! stack.isEmpty()) {
+                dirs.add(stack.removeLast());
+            }
+        }
+        
+        // we also add the files which need to be added
+        dirs.addAll(newFiles);
+        
+        // "cvs remove" files which need to be removed
+        BasicServerResponse basicServerResponse =
+            repository.removeFromRepository(client, deletedFiles);
+        if (basicServerResponse.isError()) {
+            return basicServerResponse;
+        }
+        
+        client = getClient();
+        
+        // "cvs add" new directories and text files
+        basicServerResponse = repository.addToRepository(client, listToFileArray(dirs), false);
+        if (basicServerResponse.isError()) {
+            return basicServerResponse;
+        }
+        
+        client = getClient();
+        
+        // add the binary files
+        basicServerResponse = repository.addToRepository(client, listToFileArray(binaryNewFiles), true);
+        if (basicServerResponse.isError()) {
+            return basicServerResponse;
+        }
+
+        client = getClient();
+        
+        // Now perform the commit.
+        basicServerResponse = repository.commitToRepository(client, files, commitComment);
+        return basicServerResponse;
+    }
+
+    /**
+     * Convert a List of Files to an array of Files.
+     *
+     * @param fileList
+     */
+    private static File[] listToFileArray(Collection<? extends File> fileList)
+    {
+        return fileList.toArray(new File[fileList.size()]);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCommitCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCommitCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..52ce727d3ebb952a914376d5c3959c76fde59820
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsCommitCommand.java
@@ -0,0 +1,71 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.command.CommandException;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+
+import bluej.groupwork.TeamStatusInfo;
+
+/**
+ * A CVS commit operation which supports "forced commit".
+ * 
+ * @author Davin McCall
+ */
+public class CvsCommitCommand extends CvsCommitAllCommand
+{
+    private Set<TeamStatusInfo> forceFiles;
+    
+    public CvsCommitCommand(CvsRepository repository, Set<File> newFiles,
+            Set<File> binaryNewFiles, Set<File> deletedFiles, Set<File> files,
+            Set<TeamStatusInfo> forceFiles, String commitComment)
+    {
+        super(repository, newFiles, binaryNewFiles, deletedFiles, files, commitComment);
+        this.forceFiles = forceFiles;
+    }
+    
+    protected BasicServerResponse doCommand() throws CommandAbortedException,
+            CommandException, AuthenticationException
+    {
+        // First "update" all forced files to current revisions
+        for (Iterator<TeamStatusInfo> i = forceFiles.iterator(); i.hasNext(); ) {
+            TeamStatusInfo info = i.next();
+            String reposVer = info.getRepositoryVersion();
+            if (reposVer != null && reposVer.length() != 0) {
+                try {
+                    repository.setFileVersion(info.getFile(), reposVer);
+                }
+                catch (IOException ioe) {
+                    throw new CommandException(ioe, "Can't set file version");
+                }
+            }
+        }
+        
+        return super.doCommand();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsLogCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsLogCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..912fe01cda7c16742df679f72dc1b7477bc900bc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsLogCommand.java
@@ -0,0 +1,108 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.netbeans.lib.cvsclient.Client;
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.command.CommandException;
+import org.netbeans.lib.cvsclient.command.log.LogInformation;
+import org.netbeans.lib.cvsclient.command.log.LogInformation.Revision;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+
+import bluej.groupwork.HistoryInfo;
+import bluej.groupwork.LogHistoryListener;
+import bluej.utility.FileUtility;
+
+/**
+ * An implementation of the log/history function.
+ * 
+ * @author Davin McCall
+ */
+public class CvsLogCommand extends CvsCommand
+{
+    private LogHistoryListener listener;
+    
+    public CvsLogCommand(CvsRepository repository, LogHistoryListener listener)
+    {
+        super(repository);
+        this.listener = listener;
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected BasicServerResponse doCommand()
+        throws CommandAbortedException, CommandException, AuthenticationException
+    {
+        Client client = getClient();
+        LogServerResponse response = repository.doGetLogHistory(client);
+        
+        if (! response.isError()) {
+            // We have to translate the responses from the netbeans library format
+            // to the internal structure used by BlueJ
+            
+            // map revision to List of files
+            Map<bluej.groupwork.Revision,List<String>> commits = new HashMap<bluej.groupwork.Revision,
+                    List<String>>();
+            
+            List<LogInformation> infoList = response.getInfoList();
+            for (Iterator<LogInformation> i = infoList.iterator(); i.hasNext(); ) {
+                LogInformation cvsInfo = i.next();
+                
+                // Translate the revision list
+                List<Revision> cvsRevisionList = cvsInfo.getRevisionList();
+                for (Iterator<Revision> j = cvsRevisionList.iterator(); j.hasNext(); ) {
+                    Revision cvsRev = j.next();
+                    bluej.groupwork.Revision rev = new bluej.groupwork.Revision(
+                            cvsRev.getAuthor(), cvsRev.getDateString(),
+                            cvsRev.getMessage());
+                    // cvsRev.getNumber(); // revision number
+                    
+                    List<String> files = commits.get(rev);
+                    if (files == null) {
+                        files = new ArrayList<String>();
+                    }
+                    files.add(FileUtility.makeRelativePath(repository.getProjectPath(),
+                            cvsInfo.getFile()));
+                    
+                    commits.put(rev, files);
+                }
+            }
+            
+            for (Iterator<Map.Entry<bluej.groupwork.Revision,List<String>>> i = commits.entrySet().iterator(); i.hasNext(); ) {
+                Map.Entry<bluej.groupwork.Revision,List<String>> entry = i.next();
+                bluej.groupwork.Revision rev = (bluej.groupwork.Revision) entry.getKey();
+                List<String> filesList = entry.getValue();
+                String [] files = (String []) filesList.toArray(new String[filesList.size()]);
+                HistoryInfo hinfo = new HistoryInfo(files, "", rev.getDateString(), rev.getAuthor(), rev.getMessage());
+                listener.logInfoAvailable(hinfo);
+            }
+        }
+        
+        return response;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsModulesCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsModulesCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..71ce8223b76db56a4198c6ac8e3deb8021202c4d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsModulesCommand.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.util.List;
+
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.command.CommandException;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+
+/**
+ * Command to list modules available in a Cvs repository.
+ * 
+ * @author Davin McCall
+ */
+public class CvsModulesCommand extends CvsCommand
+{
+    private List<String> modules;
+    
+    public CvsModulesCommand(CvsRepository repository, List<String> modules)
+    {
+        super(repository);
+        this.modules = modules;
+    }
+
+    protected BasicServerResponse doCommand()
+        throws CommandAbortedException, CommandException, AuthenticationException
+    {
+        return repository.doGetModules(getClient(), modules);
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsRepository.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6aaa17b001838bee023d846986905f428f1d059
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsRepository.java
@@ -0,0 +1,1127 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.*;
+
+import javax.net.SocketFactory;
+
+import org.netbeans.lib.cvsclient.CVSRoot;
+import org.netbeans.lib.cvsclient.Client;
+import org.netbeans.lib.cvsclient.admin.Entry;
+import org.netbeans.lib.cvsclient.command.Command;
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.command.CommandException;
+import org.netbeans.lib.cvsclient.command.GlobalOptions;
+import org.netbeans.lib.cvsclient.command.KeywordSubstitutionOptions;
+import org.netbeans.lib.cvsclient.command.add.AddCommand;
+import org.netbeans.lib.cvsclient.command.checkout.CheckoutCommand;
+import org.netbeans.lib.cvsclient.command.commit.CommitCommand;
+import org.netbeans.lib.cvsclient.command.importcmd.ImportCommand;
+import org.netbeans.lib.cvsclient.command.log.LogCommand;
+import org.netbeans.lib.cvsclient.command.remove.RemoveCommand;
+import org.netbeans.lib.cvsclient.command.status.StatusCommand;
+import org.netbeans.lib.cvsclient.command.update.UpdateCommand;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+import org.netbeans.lib.cvsclient.connection.Connection;
+import org.netbeans.lib.cvsclient.connection.PServerConnection;
+
+import bluej.groupwork.*;
+import bluej.utility.Debug;
+import bluej.utility.filefilter.DirectoryFilter;
+
+
+/**
+ * This class handles communication with the repository.
+ *
+ * @author fisker
+ */
+public class CvsRepository implements Repository
+{
+    /*
+     * A little about CVS.
+     * 
+     * CVS "status" command refuses to give any information about files which
+     * exist in the repository but not locally, *unless* you specify their name
+     * and path as an argument (AND you don't also specify a directory argument).
+     * So this means you need some way of finding the names first.
+     * 
+     * It turns out we can find out the names of files which only exist remotely
+     * by using "cvs -n update". However, this won't recurse into directories which
+     * only exist remotely, though it does print a warning for each one that it
+     * comes across at the current level.
+     * 
+     * So, the overall solution is to perform "cvs -n update" recursively each
+     * time we find out about a new directory. We can pretend (by using a
+     * MildManneredAdminHandler instead of the StandardAdminHandler) that the
+     * directory does exist locally (i.e. has been checked out) while we do this.
+     *  
+     */
+    
+    private boolean reconnectBetweenCommands = true;
+
+    //CVS specific members
+    private CVSRoot cvsroot;
+    private String protocol; // Only for data collection
+    private GlobalOptions globalOptions;
+    private boolean printCommand = true;
+    private File projectPath;
+    private BlueJAdminHandler adminHandler;
+
+    // ** static declaration end
+
+    /**
+     * constructor
+     */
+    public CvsRepository(File projectPath, String protocol, String cvsrootString, BlueJAdminHandler adminHandler)
+    {
+        // this.project = project;
+        this.protocol = protocol;
+        this.projectPath = projectPath;
+        globalOptions = new GlobalOptions();
+        setCvsRoot(cvsrootString);
+
+        // The client is created without a connection
+        this.adminHandler = adminHandler;
+        
+        // System.setProperty("javacvs.multiple_commands_warning", "false");
+    }
+
+    // **** static declarations 
+
+    /**
+     * Convert a List of Files to an array of Files.
+     *
+     * @param fileList
+     */
+    static File[] listToFileArray(Collection<File> fileList)
+    {
+        File[] files = new File[fileList.size()];
+        int j = 0;
+
+        for (Iterator<File> i = fileList.iterator(); i.hasNext();) {
+            File file = (File) i.next();
+            files[j++] = file;
+        }
+
+        return files;
+    }
+
+    // setup start
+
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#setPassword(bluej.groupwork.TeamSettings)
+     */
+    public void setPassword(TeamSettings newSettings)
+    {
+    try {
+    setCvsRoot(CvsProvider.makeCvsRoot(newSettings));
+    }
+    catch (UnsupportedSettingException e) {
+    Debug.reportError("CvsRepository.setPassword error", e);
+    }
+    }
+    
+    /**
+     * Get the project path for this repository.
+     */
+    public File getProjectPath()
+    {
+        return projectPath;
+    }
+    
+    /**
+     * Set the repository root location (including server, protocol, username etc)
+     * Used at setup and when the cvsroot changes due to user interaction.
+     */
+    private void setCvsRoot(String cvsrootString)
+    {
+        cvsroot = CVSRoot.parse(cvsrootString);
+        globalOptions.setCVSRoot(cvsroot.toString());
+    }
+    
+    /**
+     * Get a client object which can be used to execute commands.
+     * <p>
+     * It's necessary to get a fresh client for each command because once
+     * the client is put in the "aborted" state there's no way to undo
+     * that effect.
+     * 
+     * @return A client (without connection established)
+     */
+    BlueJCvsClient getClient()
+    {
+        BlueJCvsClient client = new BlueJCvsClient(null, adminHandler);
+        client.dontUseGzipFileHandler();
+        return client;
+    }
+
+    /**
+     * Create the connection, open it and associate it with the client.
+     *
+     * @throws AuthenticationException
+     * @throws CommandAbortedException
+     * @throws AuthenticationException
+     * @throws CommandAbortedException
+     * @throws InvalidCvsRootException
+     */
+    void setupConnection(Client client)
+        throws CommandAbortedException, AuthenticationException 
+    {
+        Connection connection = getConnection(cvsroot);
+
+        if (connection != null) {
+            connection.open();
+            client.setConnection(connection);
+        } else {
+            Debug.message("Repository.setupConnection: connection is null");
+        }
+    }
+    
+    /**
+     * If the attribute 'reconnectBetweenCommands' is true the connection is
+     * closed.
+     */
+    private void disconnect(Client client)
+    {
+        if (reconnectBetweenCommands) {
+            try {
+                client.getConnection().close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#versionsDirectories()
+     */
+    public boolean versionsDirectories()
+    {
+        return false;
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#checkout(java.io.File)
+     */
+    public TeamworkCommand checkout(File projectPath)
+    {
+        return new CvsCheckoutCommand(this, projectPath);
+    }
+    
+    /**
+     * Checkout project from repostitory to local project.
+     *
+     * @throws CommandException
+     * @throws CommandAbortedException
+     * @throws AuthenticationException
+     * @throws InvalidCvsRootException
+     */
+    public synchronized BasicServerResponse doCheckout(Client client, File projectPath)
+        throws AuthenticationException, CommandAbortedException, CommandException
+    {
+        // Client client = getClient();
+        // setupConnection();
+        setupConnection(client);
+
+        CheckoutCommand checkoutCommand = new CheckoutCommand(true,
+                projectPath.getName());
+        checkoutCommand.setRecursive(true);
+        checkoutCommand.setPruneDirectories(false);
+
+        BasicServerResponse basicServerResponse = new BasicServerResponse();
+        client.getEventManager().addCVSListener(basicServerResponse);
+        client.setLocalPath(projectPath.getParent());
+
+        printCommand(checkoutCommand, client);
+        try {
+            client.executeCommand(checkoutCommand, globalOptions);
+            basicServerResponse.waitForExecutionToFinish();
+        }
+        finally {
+            client.getEventManager().removeCVSListener(basicServerResponse);
+            disconnect(client);
+        }
+
+        return basicServerResponse;
+    }
+
+    /**
+     * Add an array of Files/directories to the repository. Parent directories
+     * must be specified before the sub-directories/files they contain.
+     *
+     * @param files the files to add
+     * @param binary true if the added files should be treated as binary
+     *
+     * @throws CommandException
+     * @throws CommandAbortedException
+     * @throws AuthenticationException
+     * @throws InvalidCvsRootException
+     */
+    BasicServerResponse addToRepository(Client client, File [] files, boolean binary)
+        throws CommandException, CommandAbortedException, 
+            AuthenticationException
+    {
+        BasicServerResponse basicServerResponse = new BasicServerResponse();
+        
+        // If there's nothing to add, return immediately
+        if (files.length < 1) {
+            basicServerResponse.commandTerminated(null);
+            return basicServerResponse;
+        }
+
+        setupConnection(client);
+        // setupConnection();
+        // Client client = getClient();
+
+        AddCommand addCommand = new AddCommand();
+        addCommand.setFiles(files);
+        
+        KeywordSubstitutionOptions kso;
+        if (binary) {
+            kso = KeywordSubstitutionOptions.BINARY;
+        }
+        else {
+            kso = KeywordSubstitutionOptions.DEFAULT;
+        }
+        addCommand.setKeywordSubst(kso);
+
+        client.getEventManager().addCVSListener(basicServerResponse);
+        client.setLocalPath(projectPath.toString());
+
+        printCommand(addCommand, client);
+        try {
+            client.executeCommand(addCommand, globalOptions);
+            basicServerResponse.waitForExecutionToFinish();
+        }
+        finally {
+            client.getEventManager().removeCVSListener(basicServerResponse);
+            disconnect(client);
+        }
+        
+        return basicServerResponse;
+    }
+
+    /**
+     * Commit an array of Files to the repository
+     *
+     * @param files the files to commit
+     *
+     * @throws CommandException
+     * @throws CommandAbortedException
+     * @throws AuthenticationException
+     * @throws InvalidCvsRootException
+     */
+    BasicServerResponse commitToRepository(Client client, Collection<File> files, String comment)
+        throws CommandException, CommandAbortedException, 
+            AuthenticationException
+    {
+        BasicServerResponse basicServerResponse = new BasicServerResponse();
+        
+        if (files.size() < 1) {
+            basicServerResponse.commandTerminated(null);
+            return basicServerResponse;
+        }
+
+        setupConnection(client);
+        // setupConnection();
+        // Client client = getClient();
+
+        CommitCommand commitCommand = new CommitCommand();
+        commitCommand.setMessage(comment);
+        commitCommand.setFiles(listToFileArray(files));
+
+        client.getEventManager().addCVSListener(basicServerResponse);
+        client.setLocalPath(projectPath.getAbsolutePath());
+
+        printCommand(commitCommand, client);
+        try {
+            client.executeCommand(commitCommand, globalOptions);
+            basicServerResponse.waitForExecutionToFinish();
+        }
+        finally {
+            client.getEventManager().removeCVSListener(basicServerResponse);
+            disconnect(client);
+        }
+
+        return basicServerResponse;
+    }
+
+    /**
+     * Import a project into the repository. The project will be put in the
+     * repository in a module named after the project.
+     *
+     * @throws CommandException
+     * @throws CommandAbortedException
+     * @throws AuthenticationException
+     * @throws InvalidCvsRootException
+     */
+    BasicServerResponse importInRepository(Client client)
+        throws CommandException, CommandAbortedException, 
+            AuthenticationException
+    {
+        // setupConnection();
+        // Client client = getClient();
+        setupConnection(client);
+
+        ImportCommand importCommand = new ImportCommand();
+
+        //importCommand.addWrapper(localPath + "/TestProject/simplePackage/SimpleClass.java", KeywordSubstitutionOptions.DEFAULT);
+        //importCommand.addWrapper(localPath + "/TestProject/simplePackage/added.txt", KeywordSubstitutionOptions.DEFAULT);
+        importCommand.setModule(projectPath.getName());
+        importCommand.setReleaseTag("init");
+        importCommand.setLogMessage("logMessage");
+        importCommand.setVendorTag("vendor");
+        
+        // Ignore all files during checkout. Then we can just commit them in-place.
+        importCommand.addIgnoredFile("*");
+
+        BasicServerResponse basicServerResponse = new BasicServerResponse();
+        client.getEventManager().addCVSListener(basicServerResponse);
+        client.setLocalPath(projectPath.getAbsolutePath());
+        printCommand(importCommand, client);
+
+        try {
+            client.executeCommand(importCommand, globalOptions);
+            basicServerResponse.waitForExecutionToFinish();
+        }
+        finally {
+            client.getEventManager().removeCVSListener(basicServerResponse);
+            disconnect(client);
+        }
+
+        return basicServerResponse;
+    }
+
+    /**
+     * Remove the files in an array of Files from the repository.
+     *
+     * @param files the files to remove.
+     *
+     * @throws CommandException
+     * @throws CommandAbortedException
+     * @throws AuthenticationException
+     * @throws InvalidCvsRootException
+     */
+    BasicServerResponse removeFromRepository(Client client, Collection<File> files)
+        throws CommandException, CommandAbortedException, 
+            AuthenticationException
+    {
+        BasicServerResponse basicServerResponse = new BasicServerResponse();
+        
+        if (files.size() < 1) {
+            basicServerResponse.commandTerminated(null);
+            return basicServerResponse;
+        }
+
+        setupConnection(client);
+        // setupConnection();
+        // Client client = getClient();
+
+        RemoveCommand removeCommand = new RemoveCommand();
+        removeCommand.setFiles(listToFileArray(files));
+
+        client.getEventManager().addCVSListener(basicServerResponse);
+        client.setLocalPath(projectPath.getAbsolutePath());
+        
+        printCommand(removeCommand, client);
+        try {
+            adminHandler.setMildManneredMode(true);
+            client.executeCommand(removeCommand, globalOptions);
+            basicServerResponse.waitForExecutionToFinish();
+        }
+        finally {
+            client.getEventManager().removeCVSListener(basicServerResponse);
+            disconnect(client);
+            adminHandler.setMildManneredMode(false);
+        }
+        
+        return basicServerResponse;
+    }
+
+    // basic cvs commands end
+    // util methods begin
+    
+    /**
+     * Get the response of a "dummy run" update command. The response contains a
+     * list of files, which need to be updated or are locally modified etc.
+     */
+    private UpdateServerResponse getUpdateServerResponse(Client client, String path)
+        throws CommandException, CommandAbortedException, 
+            AuthenticationException
+    {
+        // setupConnection();
+        // Client client = getClient();
+        setupConnection(client);
+
+        UpdateCommand updateCommand = new UpdateCommand();
+        UpdateServerResponse updateServerResponse = new UpdateServerResponse(null, null);
+        GlobalOptions globalOptions = new GlobalOptions();
+
+        updateCommand.setRecursive(true);
+        updateCommand.setBuildDirectories(true);
+        updateCommand.setPruneDirectories(true);
+        updateCommand.setCleanCopy(false);
+        globalOptions.setCVSRoot(cvsroot.toString());
+
+        globalOptions.setDoNoChanges(true); // -n
+        globalOptions.setModeratelyQuiet(true); // -q
+        client.setLocalPath(path);
+        client.getEventManager().addCVSListener(updateServerResponse);
+
+        //System.out.println("dir: " + client.getLocalPath());
+        //System.out.println("globalOptions: " + globalOptions.getCVSCommand());
+        printCommand(updateCommand, client);
+
+        //Debug.message("Update command = " + updateCommand.getCVSCommand());
+        try {
+            client.executeCommand(updateCommand, globalOptions);
+            updateServerResponse.waitForExecutionToFinish();
+        }
+        finally {
+            client.getEventManager().removeCVSListener(updateServerResponse);
+            disconnect(client);
+        }
+
+        return updateServerResponse;
+    }
+    
+    /**
+     * if the attribute 'printCommand' the command is printed as it would look
+     * on the command line
+     *
+     * @param command the command to print
+     */
+    private void printCommand(Command command, Client client)
+    {
+        if (printCommand) {
+            System.out.println("cvsCommand: " + command.getCVSCommand() +
+                " localpath: " + client.getLocalPath());
+        }
+    }
+
+    /**
+     * Check whether a directory is under CVS control.
+     */
+    boolean isDirectoryUnderCVS(File dir)
+    {
+        String apath = adminHandler.getMetaDataPath(dir.getAbsolutePath());
+        dir = new File(apath);
+        return (new File(dir, "CVS").isDirectory());
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#commitAll(java.util.Set, java.util.Set, java.util.Set, java.util.Set, java.lang.String)
+     */
+    public TeamworkCommand commitAll(Set<File> newFiles, Set<File> binaryNewFiles, Set<File> deletedFiles,
+            Set<File> files, String commitComment)
+    {
+        return new CvsCommitAllCommand(this, newFiles, binaryNewFiles, deletedFiles, files,
+                commitComment);
+    }
+
+    /**
+     * Get a command to update the given sets of files.
+     * 
+     * @param listener  The listener to receive notification of update progress, conflicts
+     * @param theFiles   The set of files to update normally
+     * @param forceFiles The set of files to update forcefully (to a clean version from
+     *                   the repository)
+     * @return
+     */
+    public TeamworkCommand updateFiles(UpdateListener listener, Set<File> theFiles,
+            Set<File> forceFiles)
+    {
+        return new CvsUpdateCommand(this, listener, theFiles, forceFiles);
+    }
+    
+   /**
+    * Update the listed files from the repository
+    *
+    * @param client  The client to use to perform the update with
+    * @param listener  The listener to receive notifications of updated files
+    * @param theFiles  The set of files to update
+    * @param force  Whether to do a forced "clean copy" update (override
+    *           local changes)
+    *
+    * @return UpdateServerResponse with information about the update
+    *
+    * @throws CommandAbortedException
+    * @throws CommandException
+    * @throws AuthenticationException
+    * @throws InvalidCvsRootException
+    */
+    synchronized UpdateServerResponse doUpdateFiles(BlueJCvsClient client,
+            UpdateListener listener, Set<File> theFiles, boolean force)
+        throws CommandAbortedException, CommandException, 
+            AuthenticationException
+    {
+        UpdateCommand command = new UpdateCommand();
+        command.setFiles(listToFileArray(theFiles));
+        
+        command.setCleanCopy(force);
+        command.setRecursive(false);
+        command.setBuildDirectories(true);
+        command.setPruneDirectories(true);
+
+        UpdateServerResponse updateServerResponse = new UpdateServerResponse(listener,
+                client);
+        client.getEventManager().addCVSListener(updateServerResponse);
+        client.setLocalPath(projectPath.getAbsolutePath());
+        
+        printCommand(command, client);
+        setupConnection(client);
+
+        try {
+            adminHandler.setMildManneredMode(true);
+            client.executeCommand(command, globalOptions);
+            updateServerResponse.waitForExecutionToFinish();
+        }
+        finally {
+            // restore previous excludes setting
+            client.getEventManager().removeCVSListener(updateServerResponse);
+            disconnect(client);
+            adminHandler.setMildManneredMode(false);
+        }
+
+        updateServerResponse.setConflictMap(client.getConflictFiles());
+        return updateServerResponse;
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#shareProject()
+     */
+    public TeamworkCommand shareProject()
+    {
+        return new CvsShareProjectCmd(this);
+    }
+
+    /**
+     * See if we can connect to the server specified by the parameter
+     * cvsRootStr
+     *
+     * @param cvsrootStr
+     *
+     * @return true if the connection could be made
+     */
+    public static TeamworkCommandResult validateConnection(String cvsrootStr)
+    {
+        TeamworkCommandResult status = null;
+        Connection connection = null;
+
+        try {
+            CVSRoot cvsroot = CVSRoot.parse(cvsrootStr);
+            connection = getConnection(cvsroot);
+
+            if (connection != null) {
+                connection.verify();
+                status = new TeamworkCommandResult();
+            }
+        } catch (AuthenticationException e) {
+            // problem verifying connection
+            status = new TeamworkCommandError(e.getMessage(), e.getLocalizedMessage());
+        } catch (IllegalArgumentException iae) {
+            // problem parsing CVSRoot
+            status = new TeamworkCommandError(iae.getMessage(), iae.getLocalizedMessage());
+        }
+
+        return status;
+    }
+
+    /**
+     * Get the applicable Connection type for the given CVSRoot object.
+     * At present this can only be either pserver or ext using internal ssh.
+     * @return a Connection object for the cvsroot or null if invalid
+     */
+    private static Connection getConnection(CVSRoot cvsRoot)
+    {
+        SocketFactory socketFactory = SocketFactory.getDefault();
+
+        if (CVSRoot.METHOD_EXT.equals(cvsRoot.getMethod())) {
+            // set port to 22 unless it is already set to something other than 0
+            int port = 22;
+
+            if (cvsRoot.getPort() != 0) {
+                port = cvsRoot.getPort();
+            }
+
+            GSSHConnection sshConnection = new GSSHConnection(socketFactory,
+                    cvsRoot.getHostName(), port, cvsRoot.getUserName(),
+                    cvsRoot.getPassword());
+            sshConnection.setRepository(cvsRoot.getRepository());
+
+            return sshConnection;
+        } else if (CVSRoot.METHOD_PSERVER.equals(cvsRoot.getMethod())) {
+            PServerConnection pConnection = new PServerConnection(cvsRoot, socketFactory);
+
+            //pServerConnection.setRepository(cvsRoot.getRepository());
+            return pConnection;
+        }
+
+        return null;
+    }
+
+    /**
+     * Get a list of files which are in the repository, but which are
+     * not in the local project. This includes both files which have been
+     * locally deleted, and files which have been added to the repository
+     * from another location.
+     * 
+     * @param remoteDirs  This set will have all remote directories which
+     *                    are found added to it.
+     * 
+     * @throws InvalidCvsRootException
+     * @throws AuthenticationException
+     * @throws CommandException
+     */
+    public synchronized List<File> getRemoteFiles(Client client, Set<File> remoteDirs) throws
+        AuthenticationException, CommandException
+    {
+        List<File> files = new LinkedList<File>();
+        adminHandler.setMildManneredMode(true);
+        try {
+            getRemoteFiles(client, files, projectPath, remoteDirs, false);
+        }
+        finally {
+            adminHandler.setMildManneredMode(false);
+        }
+        return files;
+    }
+    
+    /**
+     * Find the remote directories which also exist locally, but are not
+     * locally under version control.
+     */
+    public synchronized Set<File> getRemoteDirs(Client client)
+        throws AuthenticationException, CommandException
+    {
+        adminHandler.setMildManneredMode(true);
+        Set<File> remoteDirs = new HashSet<File>();
+        try {
+            getRemoteFiles(client, null, projectPath, remoteDirs, true);
+        }
+        finally {
+            adminHandler.setMildManneredMode(false);
+        }
+        return remoteDirs; 
+    }
+    
+    /**
+     * Get a list of files which are in the repository, but which are
+     * not in the local project. This includes both files which have been
+     * locally deleted, and files which have been added to the repository
+     * from another location.
+     * 
+     * Throws CommandAbortedException if command aborted.
+     * 
+     * @param client the client for processing the commands
+     * @param files  the list to store the discovered files in (may be null)
+     * @param path  the path to look at
+     * @param remoteDirs  a set to store all encountered remote directories in
+     * @param localDirs  whether to only look at directories which also exist locally
+     * 
+     * @throws InvalidCvsRootException
+     * @throws AuthenticationException
+     * @throws CommandException
+     */
+    private void getRemoteFiles(Client client, List<File> files, File path, Set<File> remoteDirs,
+            boolean localDirs)
+        throws AuthenticationException, CommandAbortedException, CommandException
+    {        
+        UpdateServerResponse updateResponse = getUpdateServerResponse(client,
+                path.getAbsolutePath());
+        List<CvsUpdateResult> updated = updateResponse.getUpdated();
+        Iterator<CvsUpdateResult> i = updated.iterator();
+        while (i.hasNext()) {
+            CvsUpdateResult ur = i.next();
+            File f = new File(path, ur.getFilename());
+            remoteDirs.add(f.getParentFile());
+            if (files != null && ! f.exists()) {
+                files.add(f);
+            }
+        }
+        
+        // Now recurse into any new directories which were discovered.
+        List<String> newDirs = updateResponse.getNewDirectoryNames();
+        for (String newDirName : newDirs) {
+            File localPath = new File(path, newDirName);
+            if (! localDirs || localPath.isDirectory()) {
+                remoteDirs.add(localPath);
+                getRemoteFiles(client, files, localPath, remoteDirs, localDirs);
+            }
+        }
+    }
+    
+    /**
+     * Get the status of the given set of files 
+     * @param listener
+     * @param files
+     * @param includeRemote
+     * @return
+     */
+    public TeamworkCommand getStatus(StatusListener listener, Set<File> files, boolean includeRemote)
+    {
+        return new CvsStatusCommand(this, listener, files, includeRemote);
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#getStatus(bluej.groupwork.StatusListener, java.io.FileFilter, boolean)
+     */
+    public TeamworkCommand getStatus(StatusListener listener, FileFilter filter, boolean includeRemote)
+    {
+        Set<File> files = new HashSet<File>();
+        traverseDirsForFiles(files, projectPath, filter);
+        return getStatus(listener, files, includeRemote);
+    }
+
+    /**
+     * Traverse the directory tree starting in dir and add all the encountered 
+     * files to the Set allFiles. 
+     */
+    private void traverseDirsForFiles(Set<File> allFiles, File dir, FileFilter filter)
+    {
+        if (! filter.accept(dir)) {
+            return;
+        }
+        if (dir.isFile()) {
+            allFiles.add(dir);
+            return;
+        }
+        
+        File[] files = dir.listFiles(filter);
+        if (files==null){
+            return;
+        }
+
+        try {
+            getLocallyDeletedFiles(allFiles, dir);
+        }
+        catch (IOException ioe) {
+            Debug.message("CVS error determining locally deleted files: " + ioe.getLocalizedMessage());
+            // TODO: should probably propagate and cause the command to fail.
+        }
+        for(int i=0; i< files.length; i++ ){
+            if (files[i].isFile()) {
+                allFiles.add(files[i]);
+            } else {
+                traverseDirsForFiles(allFiles, files[i], filter);
+            }
+        }
+    }
+    
+    /**
+     * Get status of all the given files.
+     * Returns a List of TeamStatusInfo.
+     * 
+     * @param files  The files whose status to retrieve
+     * @param remoteDirs  These are the directories which we know are in the
+     *                    repository. Any file in the files list which does not
+     *                    exist locally but for which the containing directory is
+     *                    in the repository,  should have that directory listed here.
+     * 
+     * @throws CommandAbortedException
+     * @throws CommandException
+     * @throws AuthenticationException
+     * @throws InvalidCvsRootException
+     */
+    public synchronized StatusServerResponse getStatus(Client client, Set<File> files, Set<File> remoteDirs)
+        throws CommandAbortedException, CommandException, AuthenticationException
+    {
+        // setupConnection();
+        // Client client = getClient();
+        setupConnection(client);
+        
+        // Now we can use the cvs "status" command to get status on the
+        // remaining files.
+        
+        StatusCommand statusCommand = new StatusCommand();
+        statusCommand.setFiles(listToFileArray(files));
+
+        StatusServerResponse statusServerResponse = new StatusServerResponse();
+        client.getEventManager().addCVSListener(statusServerResponse);
+
+        client.setLocalPath(projectPath.getAbsolutePath());
+        printCommand(statusCommand, client);
+        adminHandler.setMildManneredMode(true);
+        
+        try {
+            client.executeCommand(statusCommand, globalOptions);
+            statusServerResponse.waitForExecutionToFinish();
+        }
+        finally {
+            adminHandler.setMildManneredMode(false);
+            client.getEventManager().removeCVSListener(statusServerResponse);
+            disconnect(client);
+        }
+
+        return statusServerResponse;
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#getModules(java.util.List)
+     */
+    public TeamworkCommand getModules(List<String> modules)
+    {
+        return new CvsModulesCommand(this, modules);
+    }
+    
+    /**
+     * Get a list of modules in the repository.
+     * 
+     * @throws InvalidCvsRootException
+     * @throws AuthenticationException
+     * @throws CommandAbortedException
+     * @throws CommandException
+     */
+    public synchronized UpdateServerResponse doGetModules(Client client, List<String> modules) throws
+            AuthenticationException, CommandAbortedException, CommandException
+    {
+        // Client client = getClient();
+        setupConnection(client);
+        client.setAdminHandler(new EmptyAdminHandler());
+
+        CheckoutCommand checkoutCommand = new CheckoutCommand(true, ".");
+        checkoutCommand.setRecursive(true);
+        checkoutCommand.setPruneDirectories(false);
+        globalOptions.setDoNoChanges(true);
+
+        UpdateServerResponse updateServerResponse = new UpdateServerResponse(null, null);
+        client.getEventManager().addCVSListener(updateServerResponse);
+        client.setLocalPath(projectPath.getAbsolutePath());
+        printCommand(checkoutCommand, client);
+        
+        try {
+            client.executeCommand(checkoutCommand, globalOptions);
+            updateServerResponse.waitForExecutionToFinish();
+        }
+        finally {
+            client.getEventManager().removeCVSListener(updateServerResponse);
+            disconnect(client);
+            client.setAdminHandler(adminHandler);
+            globalOptions.setDoNoChanges(false);
+        }
+        
+        List<String> projects = updateServerResponse.getNewDirectoryNames();
+        for (Iterator<String> i = projects.iterator(); i.hasNext(); ) {
+            String projectName = i.next();
+            if (! projectName.equals("CVSROOT")) {
+                modules.add(projectName);
+            }
+        }
+        
+        return updateServerResponse;
+    }
+    
+    /**
+     * Get the locally deleted files (files which are under version control,
+     * and which existed locally, but which have been deleted locally).
+     * 
+     * @param set  The set to store the locally deleted files in
+     * @param dir  The directory to look for deleted files in (non-recursively)
+     * @throws IOException
+     */
+    public void getLocallyDeletedFiles(Set<File> set, File dir) throws IOException
+    {
+        Iterator<Entry> i = adminHandler.getEntries(dir);
+        while (i.hasNext()) {
+            Entry entry = i.next();
+            File file = new File(dir, entry.getName());
+            if (! file.exists() && ! entry.isDirectory()) {
+                set.add(new File(dir, entry.getName()));
+            }
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#getLogHistory(bluej.groupwork.LogHistoryListener)
+     */
+    public TeamworkCommand getLogHistory(LogHistoryListener listener)
+    {
+        return new CvsLogCommand(this, listener);
+    }
+    
+    /**
+     * Get the history of the repository - all commits, including file, date,
+     * revision, user, and comment.
+     * 
+     * @throws AuthenticationException
+     * @throws InvalidCvsRootException
+     * @throws CommandAbortedException
+     * @throws CommandException
+     */
+    public synchronized LogServerResponse doGetLogHistory(Client client)
+        throws AuthenticationException, CommandAbortedException, CommandException
+    {
+        // Client client = getClient();
+        setupConnection(client);
+
+        LogCommand logCommand = new LogCommand();
+        
+        LogServerResponse logServerResponse = new LogServerResponse();
+        client.getEventManager().addCVSListener(logServerResponse);
+        client.setLocalPath(projectPath.getAbsolutePath());
+        
+        printCommand(logCommand, client);
+        try {
+            client.executeCommand(logCommand, globalOptions);
+            logServerResponse.waitForExecutionToFinish();
+        }
+        finally {
+            client.getEventManager().removeCVSListener(logServerResponse);
+            disconnect(client);
+        }
+
+        return logServerResponse;
+    }
+    
+    /**
+     * Get the repository root path (the directory path on the server to the
+     * repository).
+     */
+    String getRepositoryRoot()
+    {
+        return cvsroot.getRepository();
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see bluej.groupwork.Repository#prepareDeleteDir(java.io.File)
+     */
+    public boolean prepareDeleteDir(File dir)
+    {
+        /* Move the CVS metadata into a new location */
+        adminHandler.prepareDeleteDir(dir);
+        return true;
+    }
+    
+    /**
+     * Prepare a newly created directory for version control.
+     */
+    public void prepareCreateDir(File dir)
+    {
+        adminHandler.prepareCreateDir(dir);
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see bluej.groupwork.Repository#getMetadataFilter()
+     */
+    public FileFilter getMetadataFilter()
+    {
+        return new FileFilter() {
+            public boolean accept(File pathname)
+            {
+                return ! pathname.getName().equals("CVS"); 
+            }
+        };
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see bluej.groupwork.Repository#getAllLocallyDeletedFiles()
+     */
+    public void getAllLocallyDeletedFiles(Set<File> files)
+    {
+        LinkedList<File> stack = new LinkedList<File>();
+        stack.add(projectPath);
+        Set<File> tempSet = new HashSet<File>();
+        FileFilter reposFilter = getMetadataFilter();
+
+        while (! stack.isEmpty()) {
+            File dir = (File) stack.remove(0);
+            File [] subDirs = dir.listFiles(new DirectoryFilter());
+            for (int i = 0; i < subDirs.length; i++) {
+                if (reposFilter.accept(subDirs[i])) {
+                    stack.add(subDirs[i]);
+                }
+            }
+            try {
+                getLocallyDeletedFiles(files, dir);
+            }
+            catch (IOException ioe) { }
+        }
+
+        File delDir = new File(projectPath, "CVS");
+        delDir = new File(delDir, "deleted");
+        if (delDir.exists()) {
+            stack.add(delDir);
+        }
+        
+        while (! stack.isEmpty()) {
+            File dir = (File) stack.remove(0);
+            File [] subDirs = dir.listFiles(new DirectoryFilter());
+            for (int i = 0; i < subDirs.length; i++) {
+                if (reposFilter.accept(subDirs[i])) {
+                    stack.add(subDirs[i]);
+                }
+            }
+            try {
+                getLocallyDeletedFiles(tempSet, dir);
+                for (Iterator<File> i = tempSet.iterator(); i.hasNext(); ) {
+                    File file = (File) i.next();
+                    // map the file back to the real directory
+                    String fileStr = file.getPath();
+                    fileStr = fileStr.substring(delDir.getPath().length());
+                    file = new File(projectPath, fileStr);
+                    files.add(file);
+                }
+                tempSet.clear();
+            }
+            catch (IOException ioe) { }
+        }
+    }
+    
+    /**
+     * Set the revision of a versioned file to the given revision, without altering
+     * the file contents. (This is a way to "update" but keep the current file
+     * contents. The server doesn't need to be contacted).
+     */
+    public synchronized void setFileVersion(File file, String revision) throws IOException
+    {
+        Entry cvsEntry = adminHandler.getEntry(file);
+        if (cvsEntry != null) {
+            cvsEntry.setRevision(revision);
+        }
+        else {
+            cvsEntry = new Entry();
+            cvsEntry.setName(file.getName());
+            cvsEntry.setRevision(revision);
+        }
+        adminHandler.setEntry(file, cvsEntry);
+    }
+
+    @Override
+    public String getVCSType()
+    {
+        return "CVS";
+    }
+
+    @Override
+    public String getVCSProtocol()
+    {
+        return protocol;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsShareProjectCmd.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsShareProjectCmd.java
new file mode 100644
index 0000000000000000000000000000000000000000..3bdfe2adfff4676e6af47cc0ff096eaf02a96112
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsShareProjectCmd.java
@@ -0,0 +1,67 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.command.CommandException;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+
+
+/**
+ * Command to share a project to a CVS repository.
+ * 
+ * @author Davin McCall
+ */
+public class CvsShareProjectCmd extends CvsCommand
+{
+    public CvsShareProjectCmd(CvsRepository repository)
+    {
+        super(repository);
+    }
+    
+    protected BasicServerResponse doCommand()
+        throws CommandAbortedException, CommandException, AuthenticationException
+    {
+        BasicServerResponse importResponse;
+        BasicServerResponse checkoutResponse;
+     
+        BlueJCvsClient client = getClient();
+        importResponse = repository.importInRepository(client);
+
+        if (importResponse.isError()) {
+            return importResponse;
+        } else {
+            // We need a fresh client
+            client = getClient();
+            
+            if (client != null) {
+                checkoutResponse = repository.doCheckout(client, repository.getProjectPath());
+            }
+            else {
+                throw new CommandAbortedException("","");
+            }
+        }
+
+        return checkoutResponse;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsStatusCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsStatusCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..4144706339bfcfdc718b13aff0f222a648e68264
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsStatusCommand.java
@@ -0,0 +1,262 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.netbeans.lib.cvsclient.Client;
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.command.CommandException;
+import org.netbeans.lib.cvsclient.command.status.StatusInformation;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+import org.netbeans.lib.cvsclient.file.FileStatus;
+
+import bluej.groupwork.StatusListener;
+import bluej.groupwork.TeamStatusInfo;
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.UpdateListener;
+
+/**
+ * A command to get status of files in a CVS repository.
+ * 
+ * @author Davin McCall
+ */
+public class CvsStatusCommand extends CvsCommand
+{
+    private StatusListener listener;
+    private Set<File> files;
+    private boolean includeRemote;
+    
+    public CvsStatusCommand(CvsRepository repository, StatusListener listener,
+            Set<File> files, boolean includeRemote)
+    {
+        super(repository);
+        this.listener = listener;
+        this.files = files;
+        this.includeRemote = includeRemote;
+    }
+    
+    protected BasicServerResponse doCommand()
+        throws CommandAbortedException, CommandException, AuthenticationException
+    {
+        LinkedList<TeamStatusInfo> returnInfo = new LinkedList<TeamStatusInfo>();
+        File projectPath = repository.getProjectPath();
+        Set<File> remoteDirs;
+        
+        Client client = getClient();
+        
+        // First we need to figure out remote directories
+        if (includeRemote) {
+            remoteDirs = new HashSet<File>();
+            List<File> remoteFiles = repository.getRemoteFiles(client, remoteDirs);
+            files.addAll(remoteFiles);
+        }
+        else {
+            remoteDirs = repository.getRemoteDirs(client);
+        }
+        client = null;
+        
+        // First, it's necessary to filter out files which are in
+        // directories not in the repository. Otherwise the
+        // CVS status command barfs when it hits such a file.
+        for (Iterator<File> i = files.iterator(); i.hasNext(); ) {
+            File file = i.next();
+            File parent = file.getParentFile();
+            if (! remoteDirs.contains(parent) && ! repository.isDirectoryUnderCVS(parent)) {
+                i.remove();
+                // All such files have status NEEDSADD.
+                TeamStatusInfo teamInfo = new TeamStatusInfo(file,
+                        "",
+                        null,
+                        TeamStatusInfo.STATUS_NEEDSADD);
+                returnInfo.add(teamInfo);
+            }
+        }
+        
+        StatusServerResponse statusServerResponse =
+            repository.getStatus(getClient(), files, remoteDirs);
+        
+        List<StatusInformation> statusInfo = statusServerResponse.getStatusInformation();
+        for (Iterator<StatusInformation> i = statusInfo.iterator(); i.hasNext(); ) {
+            StatusInformation sinfo = i.next();
+            int status;
+            boolean deletedInRepos = false;
+            
+            FileStatus fstatus = sinfo.getStatus();
+            String workingRev = sinfo.getWorkingRevision();
+            if (workingRev == null || workingRev.startsWith("No entry")) {
+                workingRev = "";
+            }
+            
+            // There's a bug in the netbeans CVS library which can cause files
+            // with the same base name (eg. multiple "bluej.pkg" files) to sometimes
+            // get mixed up. However the repository file name will always
+            // be correct, so we'll use that instead.
+            File file;
+            String reposName = sinfo.getRepositoryFileName();
+            if (reposName != null) {
+                if (reposName.endsWith(",v")) {
+                    reposName = reposName.substring(0, reposName.length() - 2);
+                }
+                String reposRoot = repository.getRepositoryRoot();
+                if (! reposRoot.endsWith("/")) {
+                    reposRoot += "/";
+                }
+                reposRoot += projectPath.getName() + "/";
+                String fname = reposName.substring(reposRoot.length());
+                
+                file = new File(projectPath, fname);
+
+                // Files are in "Attic" if they were deleted in the repository
+                File parentDir = file.getParentFile();
+                if (parentDir.getName().equals("Attic")) {
+                    file = new File(parentDir.getParentFile(), file.getName());
+                    deletedInRepos = true;
+                }
+            }
+            else {
+                // Of course, for files not in the repository, no repository
+                // version is available.
+                file = sinfo.getFile();
+            }
+            
+            if (fstatus == FileStatus.NEEDS_CHECKOUT) {
+                // For deleted files, CVS returns NEEDS_CHECKOUT because
+                // we haven't executed "cvs remove" yet.
+                if (workingRev.length() > 0) {
+                    String reposRev = sinfo.getRepositoryRevision();
+                    if (workingRev.equals(reposRev)) {
+                        status = TeamStatusInfo.STATUS_DELETED;    
+
+                    }
+                    else {
+                        // Not up-to-date, but locally deleted
+                        status = TeamStatusInfo.STATUS_CONFLICT_LDRM;
+                    }
+                }
+                else {
+                    status = TeamStatusInfo.STATUS_NEEDSCHECKOUT;
+                }
+            }
+            else if (fstatus == FileStatus.NEEDS_PATCH) {
+                status = TeamStatusInfo.STATUS_NEEDSUPDATE;
+            }
+            else if (fstatus == FileStatus.NEEDS_MERGE) {
+                status = TeamStatusInfo.STATUS_NEEDSMERGE;
+            }
+            else if (fstatus == FileStatus.MODIFIED || fstatus == FileStatus.ADDED) {
+                // We only get status "ADDED" if a commit was cancelled
+                // (after the "cvs add", but before "cvs commit"). It's easiest
+                // in that case to pretend that the file is actually in the
+                // repository (otherwise we'd need to special case the commit handling,
+                // to prevent attempting to "cvs add" a file which had already been
+                // added)
+                status = TeamStatusInfo.STATUS_NEEDSCOMMIT;
+            }
+            else if (fstatus == FileStatus.UNKNOWN) {
+                // present locally, not present in repository
+                status = TeamStatusInfo.STATUS_NEEDSADD;
+            }
+            else if (fstatus == FileStatus.UP_TO_DATE) {
+                status = TeamStatusInfo.STATUS_UPTODATE;
+            }
+            else if (fstatus == FileStatus.INVALID) {
+                status = TeamStatusInfo.STATUS_REMOVED;
+            }
+            else if (fstatus == FileStatus.UNRESOLVED_CONFLICT) {
+                if (deletedInRepos) {
+                    // There's been a local modification, but the file has been
+                    // removed in the repository
+                    status = TeamStatusInfo.STATUS_CONFLICT_LMRD;
+                }
+                else {
+                    if (workingRev.length() == 0) {
+                        // File has been added locally. This can only be a conflict
+                        // if the file has also been added in the repository.
+                        status = TeamStatusInfo.STATUS_CONFLICT_ADD;
+                    }
+                    else {
+                        status = TeamStatusInfo.STATUS_UNRESOLVED;
+                    }
+                }
+            }
+            else if (fstatus == FileStatus.HAS_CONFLICTS) {
+                // The local file still has conflicts in it from the last update.
+                // The file needs to modified before this status will change.
+                status = TeamStatusInfo.STATUS_HASCONFLICTS;
+            }
+            else if (fstatus == FileStatus.REMOVED) {
+                // "cvs remove" command has been run for this file. This
+                // shouldn't really happen, because we only do that just
+                // before a commit.
+                status = TeamStatusInfo.STATUS_NEEDSCOMMIT;
+            }
+            else {
+                status = TeamStatusInfo.STATUS_WEIRD;
+            }
+            
+            
+            if (files.remove(file)) {
+                TeamStatusInfo teamInfo = new TeamStatusInfo(file,
+                        workingRev,
+                        sinfo.getRepositoryRevision(),
+                        status);
+                returnInfo.add(teamInfo);
+            }
+        }
+        
+        // Now we may have some local files left which cvs hasn't given any
+        // status for...
+        for (Iterator<File> i = files.iterator(); i.hasNext(); ) {
+            File file = i.next();
+            TeamStatusInfo teamInfo = new TeamStatusInfo(file,
+                    "",
+                    null,
+                    TeamStatusInfo.STATUS_NEEDSADD);
+            returnInfo.add(teamInfo);
+        }
+
+        if (listener != null) {
+            while (! returnInfo.isEmpty()) {
+                TeamStatusInfo teamInfo = (TeamStatusInfo) returnInfo.removeFirst();
+                listener.gotStatus(teamInfo);
+            }
+            
+            listener.statusComplete(new CvsStatusHandle(repository));
+        }
+        
+        return statusServerResponse;
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.cvsnb.CvsCommand#getUpdateTo(bluej.groupwork.UpdateListener, java.util.Set, java.util.Set)
+     */
+    public TeamworkCommand getUpdateTo(UpdateListener listener, Set<File> files, Set<File> forceFiles)
+    {
+        return new CvsUpdateCommand(repository, listener, files, forceFiles);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsStatusHandle.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsStatusHandle.java
new file mode 100644
index 0000000000000000000000000000000000000000..6fd1c4e6ffac05d96e63c3a2e519c9945e25c26e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsStatusHandle.java
@@ -0,0 +1,72 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.util.Set;
+
+import bluej.groupwork.Repository;
+import bluej.groupwork.StatusHandle;
+import bluej.groupwork.TeamStatusInfo;
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.UpdateListener;
+
+/**
+ * Implementation of StatusHandle for CVS.
+ * 
+ * @author Davin McCall
+ */
+public class CvsStatusHandle implements StatusHandle
+{
+    private CvsRepository repository;
+    
+    public CvsStatusHandle(CvsRepository repository)
+    {
+        this.repository = repository;
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.StatusHandle#commitAll(java.util.Set, java.util.Set, java.util.Set, java.util.Set, java.util.Set, java.lang.String)
+     */
+    public TeamworkCommand commitAll(Set<File> newFiles,
+            Set<File> binaryNewFiles, Set<File> deletedFiles, Set<File> files,
+            Set<TeamStatusInfo> forceFiles, String commitComment)
+    {
+        return new CvsCommitCommand(repository, newFiles, binaryNewFiles, deletedFiles,
+                files, forceFiles, commitComment);
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.StatusHandle#updateTo(bluej.groupwork.UpdateListener, java.util.Set, java.util.Set)
+     */
+    public TeamworkCommand updateTo(UpdateListener listener, Set<File> files,
+            Set<File> forceFiles)
+    {
+        return repository.updateFiles(listener, files, forceFiles);
+    }
+    
+    @Override
+    public Repository getRepository()
+    {
+        return repository;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsUpdateCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsUpdateCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..9db26c8c807db6a046c5f7cf71404711dbe0ec87
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsUpdateCommand.java
@@ -0,0 +1,77 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.util.Set;
+
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.command.CommandException;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+
+import bluej.groupwork.UpdateListener;
+
+/**
+ * Command to perform an update of a specified set of files
+ * 
+ * @author Davin McCall
+ */
+public class CvsUpdateCommand extends CvsCommand
+{
+    private UpdateListener listener; // may be null
+    private Set<File> theFiles;
+    private Set<File> forceFiles;
+    
+    public CvsUpdateCommand(CvsRepository repository, UpdateListener listener,
+            Set<File> theFiles, Set<File> forceFiles)
+    {
+        super(repository);
+        this.listener = listener;
+        this.theFiles = theFiles;
+        this.forceFiles = forceFiles;
+    }
+
+    protected BasicServerResponse doCommand()
+        throws CommandAbortedException, CommandException, AuthenticationException
+    {
+        UpdateServerResponse response = null;
+        
+        if (! theFiles.isEmpty()) {
+            BlueJCvsClient client = getClient();
+            response = repository.doUpdateFiles(client, listener, theFiles, false);
+            if (listener != null) {
+                listener.handleConflicts(response);
+            }
+            
+            if (response.isError()) {
+                return response;
+            }
+        }
+        
+        if (! forceFiles.isEmpty()) {
+            BlueJCvsClient client = getClient();
+            response = repository.doUpdateFiles(client, listener, forceFiles, true);
+        }
+        
+        return response;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsUpdateResult.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsUpdateResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..78f8bdf986d2c91faf42d72edb225c86753147e0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/CvsUpdateResult.java
@@ -0,0 +1,110 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import bluej.groupwork.UnableToParseInputException;
+
+/**
+ * This class represents the result we get back from the server when doing an
+ * update. These results are lines of text that has the form <br/>
+ * statuscode filename<br/>
+ * the status code can be any in {A,C,M,P,R,U,?)
+ * 
+ * @author fisker
+ */
+public class CvsUpdateResult
+{
+    char statusCode = 'X';
+    String filename;
+    public static final char ADDED = 'A';
+    public static final char CONFLICT = 'C';
+    public static final char MODIFIED = 'M';
+    public static final char PATCHED = 'P';
+    public static final char REMOVED = 'R';
+    public static final char UPDATED = 'U';
+    public static final char UNKNOWN = '?';
+    
+    /**
+     * Create an UpdateResult with statusCode and filename
+     * @param statusCode
+     * @param filename
+     */
+    private CvsUpdateResult(char statusCode, String filename)
+    {
+        this.statusCode = statusCode;
+        this.filename = filename;
+    }
+    
+    /**
+     * Parse a string and create an UpdateResult. Used to parse the strings
+     * coming from an update command
+     * @param str the String to parse
+     * @return UpdateResult the resulting UpdateResult
+     * @throws UnableToParseInputException
+     */
+    public static CvsUpdateResult parse(String str) throws UnableToParseInputException
+    {
+        char statusCode = 'X';
+        String filename;
+                
+        boolean hasRightStructure = (str != null) && (str.length() > 3);
+        boolean hasRightStatusCode = false;
+        boolean messageOk;
+        if (hasRightStructure){
+            statusCode = str.charAt(0);
+            hasRightStatusCode = statusCode == ADDED ||
+            statusCode == CONFLICT || statusCode == MODIFIED ||
+            statusCode == PATCHED || statusCode == REMOVED || 
+            statusCode == UPDATED || statusCode == UNKNOWN;
+        }
+        messageOk = hasRightStructure && hasRightStatusCode;
+        
+        if (messageOk){
+            filename = str.substring(2);
+            return new CvsUpdateResult(statusCode, filename);
+            //System.out.println("statusCode=" + statusCode + " filename=" + filename);
+        }
+        else {
+            throw new UnableToParseInputException(str); 
+        }
+    }
+    
+    /**
+     * Get the file name and path, relative to the project.
+     */
+    public String getFilename()
+    {
+        return filename;
+    }
+    /**
+     * @return Returns the statusCode.
+     */
+    public char getStatusCode()
+    {
+        return statusCode;
+    }
+    
+    public String toString()
+    {
+        return "statusCode: " + statusCode + " filename: " + filename;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/EmptyAdminHandler.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/EmptyAdminHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..d54777af728df985cbbce914412469ff93825fdc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/EmptyAdminHandler.java
@@ -0,0 +1,98 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.netbeans.lib.cvsclient.admin.AdminHandler;
+import org.netbeans.lib.cvsclient.admin.Entry;
+import org.netbeans.lib.cvsclient.command.GlobalOptions;
+
+/**
+ * An admin handler which pretends that nothing exists.
+ * 
+ * @author Davin McCall
+ * @version $Id: EmptyAdminHandler.java 8116 2010-08-20 03:29:52Z davmac $
+ */
+public class EmptyAdminHandler
+    implements AdminHandler
+{
+    public EmptyAdminHandler()
+    {
+        // do nothing.
+    }
+    
+    public void updateAdminData(String localDirectory, String repositoryPath, Entry entry, GlobalOptions globalOptions)
+        throws IOException
+    {
+    }
+
+    public Entry getEntry(File file)
+        throws IOException
+    {
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Iterator getEntries(File directory)
+        throws IOException
+    {
+        return Collections.EMPTY_LIST.iterator();
+    }
+
+    public void setEntry(File file, Entry entry)
+        throws IOException
+    {
+    }
+
+    public String getRepositoryForDirectory(String directory, String repository)
+        throws IOException
+    {
+        return null;
+    }
+
+    public void removeEntry(File file)
+        throws IOException
+    {
+    }
+
+    public Set<File> getAllFiles(File directory)
+        throws IOException
+    {
+        return new HashSet<File>();
+    }
+
+    public String getStickyTagForDirectory(File directory)
+    {
+        return null;
+    }
+
+    public boolean exists(File file)
+    {
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/GSSHConnection.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/GSSHConnection.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a5f8e9d24a969d1e660fcf2d6720b23960326f5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/GSSHConnection.java
@@ -0,0 +1,160 @@
+package bluej.groupwork.cvsnb;
+
+import java.io.IOException;
+
+import javax.net.SocketFactory;
+
+import org.netbeans.lib.cvsclient.command.CommandAbortedException;
+import org.netbeans.lib.cvsclient.connection.AbstractConnection;
+import org.netbeans.lib.cvsclient.connection.AuthenticationException;
+import org.netbeans.lib.cvsclient.connection.ConnectionModifier;
+import org.netbeans.lib.cvsclient.util.LoggedDataInputStream;
+import org.netbeans.lib.cvsclient.util.LoggedDataOutputStream;
+
+import bluej.utility.Debug;
+
+import com.trilead.ssh2.Connection;
+import com.trilead.ssh2.InteractiveCallback;
+import com.trilead.ssh2.Session;
+
+/**
+ * Provides SSH tunnel for :ext: connection method, using the trilead library.
+ * 
+ * Based loosely on the SSHConnection class which used the jsch library, by Maros Sandor.
+ * 
+ * @author Davin McCall
+ */
+public class GSSHConnection extends AbstractConnection
+{
+    private static final String CVS_SERVER_COMMAND = System.getProperty("Env-CVS_SERVER", "cvs") + " server";  // NOI18N
+    
+    // private final SocketFactory socketFactory;
+    private final String host;
+    private final int port;
+    private final String username;
+    private final String password;
+    
+    private Session session;
+    private Connection connection;
+    // private ChannelExec channel;
+
+    /**
+     * Creates new SSH connection object.
+     * 
+     * @param socketFactory socket factory to use when connecting to SSH server
+     * @param host host names of the SSH server
+     * @param port port number of SSH server
+     * @param username SSH username
+     * @param password SSH password
+     */ 
+    public GSSHConnection(SocketFactory socketFactory, String host, int port, String username, String password)
+    {
+        //this.socketFactory = socketFactory;
+        this.host = host;
+        this.port = port;
+        this.username = username != null ? username : System.getProperty("user.name"); // NOI18N
+        this.password = password;
+    }
+
+    public void open() throws AuthenticationException, CommandAbortedException
+    {
+        try {
+            connection = new Connection(host, port);
+            connection.connect(null, 20000, 20000); // 20s timeout
+            
+            boolean isPwAvailable = connection.isAuthMethodAvailable(username, "password");
+            boolean isKIAvailable = connection.isAuthMethodAvailable(username, "keyboard-interactive");
+
+            boolean auth = false; 
+            if (isPwAvailable) {
+                auth = connection.authenticateWithPassword(username, password);
+            }
+            
+            if (! auth && isKIAvailable) {
+                // Try the "keyboard interactive" method instead.
+                auth = connection.authenticateWithKeyboardInteractive(username, new InteractiveCallback() {
+                    public String[] replyToChallenge(String name, String instruction,
+                            int numPrompts, String[] prompt, boolean[] echo)
+                    throws Exception {
+                        String [] result = new String[numPrompts];
+                        for (int i = 0; i < numPrompts; i++) {
+                            result[i] = password;
+                        }
+                        return result;
+                    }
+                });
+            }
+
+            if (! auth) { 
+                String msg = "SSH authentication failed: Wrong username/password?";
+                reset();
+                throw new AuthenticationException(msg, msg);
+            }
+            
+            session = connection.openSession();
+            session.execCommand(CVS_SERVER_COMMAND);
+            setInputStream(new LoggedDataInputStream(session.getStdout()));
+            setOutputStream(new LoggedDataOutputStream(session.getStdin()));
+        }
+        catch (IOException ioe) {
+            Debug.message("SSH connection: " + ioe.getMessage());
+            reset();
+            throw new AuthenticationException(ioe, "SSH connection failure");
+        }
+    }
+
+    /**
+     * Verifies that we can successfuly connect to the SSH server and run 'cvs server' command on it.
+     * 
+     * @throws AuthenticationException if connection to the SSH server cannot be established (network problem)
+     */ 
+    public void verify() throws AuthenticationException
+    {
+        try {
+            open();
+            close();
+        } catch (CommandAbortedException e) {
+            throw new AuthenticationException(CVS_SERVER_COMMAND, "CommandAbortedException");
+        } catch (IOException e) {
+            throw new AuthenticationException(CVS_SERVER_COMMAND, "IOException");
+        } finally {
+            reset();
+        }
+    }
+
+    private void reset()
+    {
+        if (session != null) {
+            session.close();
+            session = null;
+        }
+        if (connection != null) {
+            connection.close();
+            connection = null;
+        }
+        setInputStream(null);
+        setOutputStream(null);
+    }
+    
+    public void close() throws IOException
+    {
+        reset();
+    }
+
+    public boolean isOpen() {
+        return session != null;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void modifyInputStream(ConnectionModifier modifier) throws IOException {
+        modifier.modifyInputStream(getInputStream());
+    }
+
+    public void modifyOutputStream(ConnectionModifier modifier) throws IOException {
+        modifier.modifyOutputStream(getOutputStream());
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/LogServerResponse.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/LogServerResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..e601087d129c4aa15fe9a547ae17a174ddc766ef
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/LogServerResponse.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.netbeans.lib.cvsclient.command.FileInfoContainer;
+import org.netbeans.lib.cvsclient.command.log.LogInformation;
+import org.netbeans.lib.cvsclient.event.FileInfoEvent;
+
+
+/**
+ * A reponse handler for the "cvs log" command. Keeps a list of responses
+ * generated by the server.
+ * 
+ * @author Davin McCall
+ */
+public class LogServerResponse extends BasicServerResponse
+{
+    private List<LogInformation> infoList;
+    
+    public LogServerResponse()
+    {
+        infoList = new ArrayList<LogInformation>();
+    }
+    
+    public void fileInfoGenerated(FileInfoEvent arg0)
+    {
+        FileInfoContainer fic = arg0.getInfoContainer();
+        if (fic instanceof LogInformation) {
+            infoList.add((LogInformation) fic);
+        }
+    }
+    
+    public List<LogInformation> getInfoList()
+    {
+        return infoList;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/StatusServerResponse.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/StatusServerResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..28002c23af5f2d8884d296601a8737d77f4e8d82
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/StatusServerResponse.java
@@ -0,0 +1,66 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.netbeans.lib.cvsclient.command.FileInfoContainer;
+import org.netbeans.lib.cvsclient.command.status.StatusInformation;
+import org.netbeans.lib.cvsclient.event.FileInfoEvent;
+
+
+
+/**
+ * This class is used for registering and storing cvs status request information. 
+ *
+ * @author bquig
+ */
+public class StatusServerResponse extends BasicServerResponse
+{
+    private List<StatusInformation> infoEvents;
+
+    /**
+     * Creates a new instance of StatusServerResponse
+     */
+    public StatusServerResponse()
+    {
+        infoEvents = new ArrayList<StatusInformation>();
+    }
+
+    /**
+     * Keep each status info container so that it can be queried and used
+     */
+    public void fileInfoGenerated(FileInfoEvent infoEvent)
+    {
+        FileInfoContainer info = infoEvent.getInfoContainer();
+
+        if (info instanceof StatusInformation) {
+            infoEvents.add((StatusInformation) info);
+        }
+    }
+
+    public List<StatusInformation> getStatusInformation()
+    {
+        return infoEvents;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/UpdateServerResponse.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/UpdateServerResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..b2052300edbe0fc6d984db42dae39a81e5d34081
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/cvsnb/UpdateServerResponse.java
@@ -0,0 +1,316 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.cvsnb;
+
+import java.io.File;
+import java.util.*;
+
+import org.netbeans.lib.cvsclient.event.FileAddedEvent;
+import org.netbeans.lib.cvsclient.event.FileRemovedEvent;
+import org.netbeans.lib.cvsclient.event.FileUpdatedEvent;
+import org.netbeans.lib.cvsclient.event.MessageEvent;
+
+import bluej.groupwork.UnableToParseInputException;
+import bluej.groupwork.UpdateListener;
+import bluej.groupwork.UpdateResults;
+
+
+/**
+ * This class can be registred as a listener when doing an update. Registering
+ * could look like this:<p>
+ * 
+ * <code> 
+ * UpdateServerResponse updateServerResponse = new UpdateServerResponse();<br>
+ * client.getEventManager().addCVSListener(updateServerResponse);<br>
+ * </code>
+ * 
+ * <p>When the UpdateCommand has been executed, this listener will have build a 
+ * list of UpdateResults that can be accessed using getUpdateResults()
+ * 
+ * @author fisker
+ * 
+ */
+public class UpdateServerResponse extends BasicServerResponse implements UpdateResults
+{
+    /**
+     * Stores a tagged line
+     */
+    private final StringBuffer taggedLine = new StringBuffer();
+    
+    /**
+     * Stores the UpdateResults
+     */
+    private List<CvsUpdateResult> updateResults = new LinkedList<CvsUpdateResult>();
+    
+    /**
+     * Stores the names of new directories which were discovered during update
+     */
+    private List<String> newDirectoryNames = new LinkedList<String>();
+    
+    /** Listener to receive notifications of file changes */
+    private UpdateListener listener;
+    
+    /**
+     * Files which had conflicts, and for which a decision must be made:
+     * Keep the local version, or the repository version. Map File to File
+     * (original name, backup name)
+     */
+    private Map<File,File> conflictsMap;
+    
+    private BlueJCvsClient client;
+    
+    /**
+     * Constructor for UpdateServerResponse.
+     * 
+     * @param listener  The listener to receive notification of file changes.
+     *                  May be null.
+     */
+    public UpdateServerResponse(UpdateListener listener, BlueJCvsClient client)
+    {
+        this.listener = listener;
+        this.client = client;
+    }
+    
+    /*
+     * Example output from server:
+     * 
+     * cvs update: Updating .
+     * cvs update: New directory 'abcdef' -- ignored 
+     * cvs update: nonmergeable file needs merge
+     * cvs update: revision 1.7 from repository is now in bluej.pkg
+     * cvs update: file from working directory is now in .#bluej.pkg.1.6
+     * cvs update: Updating +libs
+     * cvs update: Updating Examples
+     * 
+     * If a file is deleted in repository as well as locally:
+     * cvs update: warning: Examples/bluej.pkg is not (any longer) pertinent
+     */
+    
+    /* CVS: RCS file: /home/cvsroot/simple/Alakazam.java,v
+       CVS: retrieving revision 1.6
+       CVS: retrieving revision 1.7
+       CVS: Merging differences between 1.6 and 1.7 into Alakazam.java
+       renameLocalFile, /home/davmac/bluej/examples/simple/Alakazam.java, .#Alakazam.java.1.6
+       CVS: cvs update: Updating .
+       CVS: rcsmerge: warning: conflicts during merge
+       CVS: CVS: cvs update: conflicts found in Alakazam.java
+       CVS: cvs update: Updating +libs
+       CVS tagged: text C 
+       CVS tagged: fname Alakazam.java
+       CVS tagged: newline
+       CVS: C Alakazam.java
+       CVS tagged: text M 
+       CVS tagged: fname bluej.pkg
+       CVS tagged: newline
+       CVS: M bluej.pkg
+       CVS: cvs update: Updating Examples */
+
+    
+    
+    /**
+     * Called when the server wants to send a message to be displayed to
+     * the user. The message is only for information purposes and clients
+     * can choose to ignore these messages if they wish.
+     * @param e the event
+     */
+    public void messageSent(MessageEvent e)
+    {
+        String line = e.getMessage();
+        //System.out.println("UpdateServerResponse parsed: " + e.getMessage() + 
+        //      " isTagged: " + e.isTagged()    );
+
+        if (e.isTagged())
+        {
+            // System.out.println("CVS tagged: " + e.getMessage());
+            line = MessageEvent.parseTaggedMessage(taggedLine, line);
+            // if we get back a non-null line, we have something
+            // to output. Otherwise, there is more to come and we
+            // should do nothing yet.
+            if (line == null) {
+                return;
+            }
+        }
+        
+        if (e.isError()) {
+            // System.out.println("CVS err: " + line);
+            int offset = 27;
+            if (line.startsWith("cvs update: New directory")
+                    || line.startsWith("cvs server: New directory")
+                    || (offset = 29) != 0 && line.startsWith("cvs checkout: New directory")) {
+                // Sheesh, CVS is really stoopid. When doing "cvs -n update",
+                // it won't recurse into new directories (i.e. directories
+                // which weren't previously known to the client) no matter
+                // what. At least it gives us this message, so we can record
+                // the directory name and re-stat it later.
+                int n = line.lastIndexOf("-- ignored");
+                if (n != -1) {
+                    String dirName = line.substring(offset, n - 2);
+                    newDirectoryNames.add(dirName);
+                }
+            }
+        }
+        else {
+            // System.out.println("CVS: " + line);
+            if (line.startsWith("Merging differences between ")) {
+                // We get this when a textual merge is performed.
+                if (client != null) {
+                    client.nextConflictNonBinary();
+                }
+            }
+        }
+
+        try {
+            CvsUpdateResult updateResult = CvsUpdateResult.parse(line);
+            updateResults.add(updateResult);
+        } catch (UnableToParseInputException e1) {
+            //e1.printStackTrace();
+        }
+    }
+    
+    public void fileUpdated(FileUpdatedEvent arg0)
+    {
+        if (listener != null) {
+            String filePath = arg0.getFilePath();
+            listener.fileUpdated(new File(filePath));
+        }
+    }
+    
+    public void fileAdded(FileAddedEvent arg0)
+    {
+        if (listener != null) {
+            String filePath = arg0.getFilePath();
+            listener.fileAdded(new File(filePath));
+        }
+    }
+    
+    public void fileRemoved(FileRemovedEvent arg0)
+    {
+        if (listener != null) {
+            String filePath = arg0.getFilePath();
+            listener.fileRemoved(new File(filePath));
+        }
+    }
+    
+    private List<CvsUpdateResult> getUpdateResultsOfType(char type)
+    {
+        List<CvsUpdateResult> results = new LinkedList<CvsUpdateResult>();
+        for (Iterator<CvsUpdateResult> i = updateResults.iterator(); i.hasNext();) {
+            CvsUpdateResult updateResult = i.next();
+            if (updateResult.getStatusCode() == type) {
+                results.add(updateResult);
+            }
+        }
+        return results;
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.UpdateResults#getConflicts()
+     */
+    public List<File> getConflicts()
+    {
+        waitForExecutionToFinish();
+        List<CvsUpdateResult> curList = getUpdateResultsOfType(CvsUpdateResult.CONFLICT);
+        List<File> fileList = new ArrayList<File>(curList.size());
+        for (Iterator<CvsUpdateResult> i = curList.iterator(); i.hasNext(); ) {
+            CvsUpdateResult result = i.next();
+            fileList.add(new File(client.getLocalPath(), result.getFilename()));
+        }
+        return fileList;
+    }
+    
+    /**
+     * Get a list of UpdateResults that represents updates. 
+     * This method will block until the UpdateCommand we are listening for has
+     * terminated.
+     * @return List of UpdateResults which represents updates
+     */
+    public List<CvsUpdateResult> getUpdated()
+    {
+        waitForExecutionToFinish();
+        return getUpdateResultsOfType(CvsUpdateResult.UPDATED);
+    }
+    
+    /**
+     * Get a list of directory names discovered during cvs -n update.
+     * 
+     * @return  the directory names (List of String)
+     */
+    public List<String> getNewDirectoryNames()
+    {
+        return newDirectoryNames;
+    }
+    
+    /**
+     * Set the conflict map, which maps the files which had binary conflicts
+     * to the backup name assigned by CVS.
+     * 
+     * @param m The map (File to File). The key is the original file name
+     *          (the repository version of the file) and the value is the
+     *          backup name (the local version of the file).
+     */
+    public void setConflictMap(Map<File,File> m)
+    {
+        conflictsMap = m;
+    }
+    
+    /**
+     * Get the set of files which had binary conflicts. These are files which
+     * have been modified both locally and in the repository. A decision needs to
+     * be made about which version (local or repository) is to be retained; use
+     * the overrideFiles() method to finalise this decision.
+     */
+    public Set<File> getBinaryConflicts()
+    {
+        return conflictsMap.keySet();
+    }
+    
+    /**
+     * Once the initial update has finished and the binary conflicts are known,
+     * this method must be called to select whether to keep the local or use the
+     * remove version of the conflicting files.
+     *  
+     * @param files  A set of files to fetch from the repository, overwriting the
+     *               local version. (For any file not in the set, the local version
+     *               is retained). 
+     */
+    public void overrideFiles(Set<File> files)
+    {
+        // First delete backups of files which are to be overridden
+        for (Iterator<File> i = files.iterator(); i.hasNext(); ) {
+            File f = (File) i.next();
+            File backupFile = (File) conflictsMap.remove(f);
+            if (backupFile != null) {
+                backupFile.delete();
+            }
+        }
+        
+        // Then, for the other files, rename the backup over the original
+        // file
+        for (Iterator<Map.Entry<File,File>> i = conflictsMap.entrySet().iterator(); i.hasNext(); ) {
+            Map.Entry<File,File> entry = i.next();
+            File f = entry.getKey();
+            File backupFile = entry.getValue();
+            f.delete();
+            backupFile.renameTo(f);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCheckoutCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCheckoutCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..bfe5b3297f06c207925c052e602d76342d724271
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCheckoutCommand.java
@@ -0,0 +1,73 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import java.io.File;
+
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.Depth;
+import org.tigris.subversion.javahl.Revision;
+import org.tigris.subversion.javahl.SVNClientInterface;
+
+import bluej.groupwork.TeamworkCommandAborted;
+import bluej.groupwork.TeamworkCommandError;
+import bluej.groupwork.TeamworkCommandResult;
+
+/**
+ * Subversion "checkout" command.
+ * 
+ * @author Davin McCall
+ */
+public class SvnCheckoutCommand extends SvnCommand
+{
+    private File checkoutPath;
+    private String moduleName;
+    
+    public SvnCheckoutCommand(SvnRepository repository, File projectPath)
+    {
+        super(repository);
+        this.checkoutPath = projectPath.getAbsoluteFile();
+        moduleName = projectPath.getName();
+    }
+    
+    protected TeamworkCommandResult doCommand()
+    {
+        SVNClientInterface client = getClient();
+        String reposUrl = getRepository().getReposUrl();
+        reposUrl += "/" + moduleName;
+        
+        try {
+            client.checkout(reposUrl, checkoutPath.getAbsolutePath(),
+                Revision.HEAD, Revision.HEAD, Depth.infinity, true, true);
+            if (! isCancelled()) {
+                return new TeamworkCommandResult();
+            }
+        }
+        catch (ClientException ce) {
+            if (! isCancelled()) {
+                return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
+            }
+        }
+
+        return new TeamworkCommandAborted();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..525f5c1e86bd3b19e47ff2ceb964ce8b17ad7b68
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCommand.java
@@ -0,0 +1,109 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.SVNClientInterface;
+
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.TeamworkCommandAborted;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.utility.Debug;
+
+/**
+ * Base class for subversion command implementations.
+ * 
+ * @author Davin McCall
+ */
+abstract public class SvnCommand
+    implements TeamworkCommand
+{
+    private SvnRepository repository;
+    private SVNClientInterface client;
+    private boolean cancelled = false;
+    
+    protected SvnCommand(SvnRepository repository)
+    {
+        this.repository = repository;
+    }
+    
+    public synchronized void cancel()
+    {
+        cancelled = true;
+        if (client != null) {
+            try {
+                client.cancelOperation();
+            }
+            catch (ClientException ce) {
+                // Why would we get an exception on a cancel?
+                Debug.message("Exception during subversion cancel:");
+                ce.printStackTrace(System.out);
+            }
+        }
+    }
+    
+    /**
+     * Check whether this command has been cancelled.
+     */
+    protected synchronized boolean isCancelled()
+    {
+        return cancelled;
+    }
+    
+    /**
+     * Get a handle to the SVN client interface.
+     */
+    protected SVNClientInterface getClient()
+    {
+        return client;
+    }
+    
+    /**
+     * Get a handle to the repository.
+     */
+    protected SvnRepository getRepository()
+    {
+        return repository;
+    }
+
+    public TeamworkCommandResult getResult()
+    {
+        return repository.execCommand(this);
+    }
+    
+    public TeamworkCommandResult doCommand(SVNClientInterface client)
+    {
+        synchronized (this) {
+            if (cancelled) {
+                return new TeamworkCommandAborted();
+            }
+            this.client = client;
+        }
+        
+        TeamworkCommandResult result = doCommand();
+        this.client = null; // so that cancellation after completion doesn't
+                       // cause the next command to be cancelled
+        return result;
+    }
+    
+    abstract protected TeamworkCommandResult doCommand();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCommitAllCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCommitAllCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6b0844e05ce03241cec1fb6e671575c4a8b08ff
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCommitAllCommand.java
@@ -0,0 +1,155 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.Depth;
+import org.tigris.subversion.javahl.PropertyData;
+import org.tigris.subversion.javahl.SVNClientInterface;
+import org.tigris.subversion.javahl.Status;
+import org.tigris.subversion.javahl.StatusCallback;
+
+import bluej.groupwork.TeamworkCommandAborted;
+import bluej.groupwork.TeamworkCommandError;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.utility.Debug;
+
+/**
+ * A subversion command to commit files.
+ * 
+ * @author Davin McCall
+ */
+public class SvnCommitAllCommand extends SvnCommand
+{
+    protected Set<File> newFiles;
+    protected Set<File> binaryNewFiles;
+    protected Set<File> deletedFiles;
+    protected Set<File> files;
+    protected String commitComment;
+    
+    public SvnCommitAllCommand(SvnRepository repository, Set<File> newFiles, Set<File> binaryNewFiles,
+            Set<File> deletedFiles, Set<File> files, String commitComment)
+    {
+        super(repository);
+        this.newFiles = newFiles;
+        this.binaryNewFiles = binaryNewFiles;
+        this.deletedFiles = deletedFiles;
+        this.files = files;
+        this.commitComment = commitComment;
+    }
+
+    protected TeamworkCommandResult doCommand()
+    {
+        SVNClientInterface client = getClient();
+        
+        // A class to allow callbacks to pass back status information.
+        class StatusRef {
+            Status status;
+        };
+
+        try {
+            // First "svn add" the new files
+            Iterator<File> i = newFiles.iterator();
+            while (i.hasNext()) {
+                File newFile = (File) i.next();
+                
+                final StatusRef statusRef = new StatusRef();
+                
+                client.status(newFile.getAbsolutePath(), Depth.empty, false, true, true, false, null,
+                        new StatusCallback() {
+                            @Override
+                            public void doStatus(Status status)
+                            {
+                                statusRef.status = status;
+                            }
+                        });
+                
+                
+                Status status = statusRef.status;
+                if (! status.isManaged()) {
+                    client.add(newFile.getAbsolutePath(), Depth.empty, false, false, true);
+                    if (! newFile.isDirectory()) {
+                        client.propertySet(newFile.getAbsolutePath(), PropertyData.EOL_STYLE,
+                                "native", Depth.empty, null, false, null);
+                    }
+                }
+            }
+            
+            // And binary files
+            i = binaryNewFiles.iterator();
+            while (i.hasNext()) {
+                File newFile = (File) i.next();
+                
+                final StatusRef statusRef = new StatusRef();
+                client.status(newFile.getAbsolutePath(), Depth.empty, false, true, true, false, null,
+                        new StatusCallback() {
+                            @Override
+                            public void doStatus(Status status)
+                            {
+                                statusRef.status = status;
+                            }
+                        });
+                Status status = statusRef.status;
+                if (! status.isManaged()) {
+                    client.add(newFile.getAbsolutePath(), Depth.empty, false, false, true);
+                    if (! newFile.isDirectory()) {
+                        client.propertySet(newFile.getAbsolutePath(), PropertyData.MIME_TYPE,
+                                "application/octet-stream", Depth.empty, null, false, null);
+                    }
+                }
+            }
+            
+            // "svn delete" removed files
+            i = deletedFiles.iterator();
+            while (i.hasNext()) {
+                File newFile = (File) i.next();
+                client.remove(new String[] {newFile.getAbsolutePath()}, "", true, false, Collections.emptyMap());
+            }
+            
+            // now do the commit
+            String [] commitFiles = new String[files.size()];
+            i = files.iterator();
+            for (int j = 0; j < commitFiles.length; j++) {
+                File file = (File) i.next();
+                commitFiles[j] = file.getAbsolutePath();
+            }
+            client.commit(commitFiles, commitComment, Depth.empty, false, false, null, Collections.emptyMap());
+            
+            if (! isCancelled()) {
+                return new TeamworkCommandResult();
+            }
+        }
+        catch (ClientException ce) {
+            if (! isCancelled()) {
+                Debug.reportError("Subversion commit all exception", ce);
+                return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
+            }
+        }
+
+        return new TeamworkCommandAborted();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCommitCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCommitCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..80e5ad3f18c128d25f23659276ad74f0de88ac25
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnCommitCommand.java
@@ -0,0 +1,126 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.Revision;
+import org.tigris.subversion.javahl.SVNClientInterface;
+
+import bluej.groupwork.TeamUtils;
+import bluej.groupwork.TeamworkCommandAborted;
+import bluej.groupwork.TeamworkCommandError;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.utility.Debug;
+
+/**
+ * Implementation of Subversion commit command, handling forced commits.
+ * 
+ * @author Davin McCall
+ */
+public class SvnCommitCommand extends SvnCommitAllCommand
+{
+    private Set<File> forceFiles;
+    private long revision;
+    
+    public SvnCommitCommand(SvnRepository repository, Set<File> newFiles,
+            Set<File> binaryNewFiles, Set<File> deletedFiles, Set<File> files,
+            Set<File> forceFiles, long revision, String commitComment)
+    {
+        super(repository, newFiles, binaryNewFiles, deletedFiles, files, commitComment);
+        this.forceFiles = forceFiles;
+        this.revision = revision;
+    }
+    
+    @Override
+    protected TeamworkCommandResult doCommand()
+    {
+        SVNClientInterface client = getClient();
+        
+        // Subversion doesn't allow any sort of forced commit. So, we have to
+        // make backups of the forced files (as long as they actually exist, i.e.
+        // not a forced delete), then update to the correct revision, then restore
+        // the backups.
+        
+        // Find the files to make backups of:
+        Set<File> backupSet = new HashSet<File>();
+        Set<File> deleteMeSet = new HashSet<File>();
+        Map<File,File> bmap = null;
+        for (Iterator<File> i = forceFiles.iterator(); i.hasNext(); ) {
+            File file = i.next();
+            if (file.exists() && ! deletedFiles.contains(file)) {
+                backupSet.add(file);
+            }
+            else {
+                deleteMeSet.add(file);
+            }
+        }
+        try {
+            bmap = TeamUtils.backupFiles(backupSet);
+            
+            // Perform update
+            String [] paths = new String[forceFiles.size()];
+            int j = 0;
+            for (Iterator<File> i = forceFiles.iterator(); i.hasNext(); ) {
+                File file = i.next();
+                paths[j++] = file.getAbsolutePath();
+                // Delete the file, so the update cannot conflict
+                file.delete();
+            }
+
+            client.update(paths, Revision.getInstance(revision), true, false);
+            
+            TeamworkCommandResult result = super.doCommand();
+            return result; // finally clause below restores backups
+        }
+        catch (IOException ioe) {
+            return new TeamworkCommandError(ioe.getMessage(), "File I/O error: " + ioe.getLocalizedMessage());
+        }
+        catch (ClientException ce) {
+            if (! isCancelled()) {
+                return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
+            }
+            else {
+                return new TeamworkCommandAborted();
+            }
+        }
+        finally {
+            if (bmap != null) {
+                try {
+                    TeamUtils.restoreBackups(bmap);
+                    for (Iterator<File> i = deleteMeSet.iterator(); i.hasNext(); ) {
+                        i.next().delete();
+                    }
+                }
+                catch (IOException ioe) {
+                    Debug.message("Failed to restore file after forced commit: " + ioe.getLocalizedMessage());
+                }
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnHistoryCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnHistoryCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c562f5732adefa1e180aadc4ec5b99f91513615
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnHistoryCommand.java
@@ -0,0 +1,147 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import java.io.File;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Map;
+
+import org.tigris.subversion.javahl.ChangePath;
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.LogDate;
+import org.tigris.subversion.javahl.LogMessageCallback;
+import org.tigris.subversion.javahl.Revision;
+import org.tigris.subversion.javahl.RevisionRange;
+import org.tigris.subversion.javahl.SVNClientInterface;
+
+import bluej.groupwork.HistoryInfo;
+import bluej.groupwork.LogHistoryListener;
+import bluej.groupwork.TeamworkCommandAborted;
+import bluej.groupwork.TeamworkCommandError;
+import bluej.groupwork.TeamworkCommandResult;
+
+/**
+ * A subversion history command.
+ * 
+ * @author Davin McCall
+ */
+public class SvnHistoryCommand extends SvnCommand
+{
+    private LogHistoryListener listener;
+    
+    public SvnHistoryCommand(SvnRepository repository, LogHistoryListener listener)
+    {
+        super(repository);
+        this.listener = listener;
+    }
+    
+    protected TeamworkCommandResult doCommand()
+    {
+        SVNClientInterface client = getClient();
+        File projectPath = getRepository().getProjectPath();
+
+        try {
+            RevisionRange rr = new RevisionRange(Revision.START, Revision.HEAD);
+            
+            client.logMessages(projectPath.getAbsolutePath(),
+                    Revision.HEAD,
+                    new RevisionRange[] {rr},
+                    false /* don't stopOnCopy */,
+                    true  /* do discoverPath */,
+                    false /* don't includeMergedRevisions */,
+                    new String[] {"svn:author", "svn:date", "svn:log"},
+                    0     /* give us all commits */,
+                    new LogMessageCallback() {
+                        @Override
+                        public void singleMessage(ChangePath[] paths,
+                                long revision, Map revProps,
+                                boolean hasChildren)
+                        {
+                            if (paths.length == 0) {
+                                return;
+                            }
+                            
+                            String revisionStr = Long.toString(revision);
+                            Object ldate = revProps.get("svn:date");
+                            
+                            try {
+                                Date theDate = new LogDate(ldate.toString()).getDate();
+                                String date = "";
+                                Calendar calendar = Calendar.getInstance();
+                                calendar.setTime(theDate);
+                                date += padInt(calendar.get(Calendar.YEAR), 4); 
+                                date += "/" + padInt(calendar.get(Calendar.MONTH) + 1, 2);
+                                date += "/" + padInt(calendar.get(Calendar.DAY_OF_MONTH), 2);
+                                date += " " + padInt(calendar.get(Calendar.HOUR_OF_DAY), 2);
+                                date += ":" + padInt(calendar.get(Calendar.MINUTE), 2);
+                                date += ":" + padInt(calendar.get(Calendar.SECOND), 2);
+
+                                String [] strPaths = new String[paths.length];
+                                for (int j = 0; j < paths.length; j++) {
+                                    strPaths[j] = paths[j].getPath();
+                                    int index = strPaths[j].indexOf(File.separator, 1);
+                                    if (index != -1) {
+                                        strPaths[j] = strPaths[j].substring(index + 1);
+                                    }
+                                    else {
+                                        // The project directory itself
+                                        strPaths[j] = strPaths[j].substring(1);
+                                    }
+                                }
+                                
+                                String author = revProps.get("svn:author").toString();
+                                String message = revProps.get("svn:log").toString();
+                                HistoryInfo info = new HistoryInfo(strPaths, revisionStr,
+                                        date, author, message);
+                                listener.logInfoAvailable(info);
+                            }
+                            catch (ParseException pe) {
+                                
+                            }
+                        }
+                    });
+            
+            return new TeamworkCommandResult();
+        }
+        catch (ClientException ce) {
+            if (! isCancelled()) {
+                return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
+            }
+        }
+
+        return new TeamworkCommandAborted();
+    }
+
+    /**
+     * Pad an integer to the given number of digits (using leading noughts).
+     */
+    private static String padInt(int number, int digits)
+    {
+        String result = Integer.toString(number);
+        while (result.length() < digits) {
+            result = "0" + result;
+        }
+        return result;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnModulesCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnModulesCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..490674a804c351332ae1cacb3b196b16723bd3c6
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnModulesCommand.java
@@ -0,0 +1,75 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import java.util.List;
+
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.DirEntry;
+import org.tigris.subversion.javahl.NodeKind;
+import org.tigris.subversion.javahl.Revision;
+import org.tigris.subversion.javahl.SVNClientInterface;
+
+import bluej.groupwork.TeamworkCommandAborted;
+import bluej.groupwork.TeamworkCommandError;
+import bluej.groupwork.TeamworkCommandResult;
+
+/**
+ * A command to retrieve a list of modules from a subversion repository.
+ * 
+ * @author Davin McCall
+ */
+public class SvnModulesCommand extends SvnCommand
+{
+    private List<String> modulesList;
+    
+    public SvnModulesCommand(SvnRepository repository, List<String> modulesList)
+    {
+        super(repository);
+        this.modulesList = modulesList;
+    }
+    
+    protected TeamworkCommandResult doCommand()
+    {
+        SVNClientInterface client = getClient();
+        
+        try {
+            DirEntry [] entries = client.list(getRepository().getReposUrl(), Revision.HEAD, false);
+            if (! isCancelled()) {
+                for (int i = 0; i < entries.length; i++) {
+                    if (entries[i].getNodeKind() == NodeKind.dir) {
+                        modulesList.add(entries[i].getPath());
+                    }
+                }
+                
+                return new TeamworkCommandResult();
+            }
+        }
+        catch (ClientException ce) {
+            if (! isCancelled()) {
+                return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
+            }
+        }
+        
+        return new TeamworkCommandAborted();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnRepository.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..eaa7ae602e9fce8d37e0f5741c4db18c22270810
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnRepository.java
@@ -0,0 +1,260 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.Depth;
+import org.tigris.subversion.javahl.SVNClientInterface;
+import org.tigris.subversion.javahl.Status;
+import org.tigris.subversion.javahl.StatusCallback;
+
+import bluej.groupwork.LogHistoryListener;
+import bluej.groupwork.Repository;
+import bluej.groupwork.StatusListener;
+import bluej.groupwork.TeamSettings;
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.utility.Debug;
+
+/**
+ * A subversion repository implementation.
+ * 
+ * @author Davin McCall
+ */
+public class SvnRepository
+    implements Repository
+{
+    private File projectPath;
+    private String protocol; // Only for data collection
+    private String reposUrl;
+    
+    private SVNClientInterface client;
+    private Object clientLock = new Object();
+    
+    public SvnRepository(File projectPath, String protocol, String reposUrl, SVNClientInterface client)
+    {
+        this.projectPath = projectPath;
+        this.protocol = protocol;
+        this.reposUrl = reposUrl;
+        this.client = client;
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#versionsDirectories()
+     */
+    public boolean versionsDirectories()
+    {
+        return true;
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#setPassword(bluej.groupwork.TeamSettings)
+     */
+    public void setPassword(TeamSettings newSettings)
+    {
+        client.password(newSettings.getPassword());
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#checkout(java.io.File)
+     */
+    public TeamworkCommand checkout(File projectPath)
+    {
+        return new SvnCheckoutCommand(this, projectPath);
+    }
+
+    /*
+     * @see bluej.groupwork.Repository#commitAll(java.util.Set, java.util.Set, java.util.Set, java.util.Set, java.lang.String)
+     */
+    public TeamworkCommand commitAll(Set<File> newFiles, Set<File> binaryNewFiles,
+            Set<File> deletedFiles, Set<File> files, String commitComment)
+    {
+        return new SvnCommitAllCommand(this, newFiles, binaryNewFiles, deletedFiles,
+                files, commitComment);
+    }
+
+    /*
+     * @see bluej.groupwork.Repository#getAllLocallyDeletedFiles(java.util.Set)
+     */
+    public void getAllLocallyDeletedFiles(final Set<File> files)
+    {
+        synchronized (clientLock) {
+            try {
+                client.status(projectPath.getAbsolutePath(), Depth.infinity,
+                        false, false, false, false, null,
+                        new StatusCallback() {
+                    public void doStatus(Status status)
+                    {
+                        File file = new File(status.getPath());
+                        if (! file.exists()) {
+                            files.add(file);
+                        }
+                    }
+                });
+            }
+            catch (ClientException ce) {
+                Debug.reportError("Subversion: ClientException when getting local status", ce);
+            }
+        }
+    }
+
+    public TeamworkCommand getLogHistory(LogHistoryListener listener)
+    {
+        return new SvnHistoryCommand(this, listener);
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.groupwork.Repository#getMetadataFilter()
+     */
+    public FileFilter getMetadataFilter()
+    {
+        return new FileFilter() {
+            public boolean accept(File pathname)
+            {
+                return ! pathname.getName().equals(".svn"); 
+            }
+        };
+    }
+
+    /*
+     * @see bluej.groupwork.Repository#getModules(java.util.List)
+     */
+    public TeamworkCommand getModules(List<String> modules)
+    {
+        return new SvnModulesCommand(this, modules);
+    }
+
+    /*
+     * @see bluej.groupwork.Repository#getStatus(bluej.groupwork.StatusListener, java.util.Set, boolean)
+     */
+    public TeamworkCommand getStatus(StatusListener listener, FileFilter filter, boolean includeRemote)
+    {
+        return new SvnStatusCommand(this, listener, filter, includeRemote);
+    }
+
+    /*
+     * @see bluej.groupwork.Repository#prepareCreateDir(java.io.File)
+     */
+    public void prepareCreateDir(final File dir)
+    {
+        try {
+            client.status(dir.getAbsolutePath(), Depth.empty, false, true, true, false, null,
+                    new StatusCallback() {
+                public void doStatus(Status stat)
+                {
+                    if (! stat.isManaged()) {
+                        try {
+                            client.add(dir.getAbsolutePath(), Depth.empty, true, false, true);
+                        }
+                        catch (ClientException ce) {
+                            Debug.message("Exception while doing svn add on directory: "
+                                    + ce.getLocalizedMessage());
+                        }
+                    }
+                }
+            });
+        }
+        catch (ClientException ce) {
+            Debug.message("Exception while doing svn status on new directory: "
+                    + ce.getLocalizedMessage());
+        }
+    }
+
+    /*
+     * @see bluej.groupwork.Repository#prepareDeleteDir(java.io.File)
+     */
+    public boolean prepareDeleteDir(File dir)
+    {
+        synchronized (clientLock) {
+            try {
+                client.remove(new String[] {dir.getAbsolutePath()}, "", true, true, Collections.emptyMap());
+            }
+            catch (ClientException ce) {
+                Debug.message("Exception while doing svn remove on directory: "
+                        + ce.getLocalizedMessage());
+            }
+        }
+        
+        return false;
+    }
+
+    /*
+     * @see bluej.groupwork.Repository#shareProject()
+     */
+    public TeamworkCommand shareProject()
+    {
+        return new SvnShareCommand(this);
+    }
+
+    /**
+     * Execute a subversion command with the client lock held. This is called by
+     * subversion commands internally, to acquire the client lock.
+     */
+    public TeamworkCommandResult execCommand(SvnCommand command)
+    {
+        synchronized (clientLock) {
+            return command.doCommand(client);
+        }
+    }
+    
+    /**
+     * Get the subversion URL for this project
+     */
+    public String getReposUrl()
+    {
+        return reposUrl;
+    }
+    
+    /**
+     * Get the path of the working copy
+     */
+    public File getProjectPath()
+    {
+        return projectPath;
+    }
+    
+    /**
+     * Get the client interface directly.
+     */
+    public SVNClientInterface getClient()
+    {
+        return client;
+    }
+
+    @Override
+    public String getVCSType()
+    {
+        return "SVN";
+    }
+
+    @Override
+    public String getVCSProtocol()
+    {
+        return protocol;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnShareCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnShareCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..85ff37a8484dbe64b29196d1da43b1776ba77023
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnShareCommand.java
@@ -0,0 +1,74 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import java.io.File;
+
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.Depth;
+import org.tigris.subversion.javahl.Revision;
+import org.tigris.subversion.javahl.SVNClientInterface;
+
+import bluej.Config;
+import bluej.groupwork.TeamworkCommandAborted;
+import bluej.groupwork.TeamworkCommandError;
+import bluej.groupwork.TeamworkCommandResult;
+
+/**
+ * Subversion command to share a project
+ * 
+ * @author Davin McCall
+ */
+public class SvnShareCommand extends SvnCommand
+{
+    public SvnShareCommand(SvnRepository repository)
+    {
+        super(repository);
+    }
+    
+    protected TeamworkCommandResult doCommand()
+    {
+        SVNClientInterface client = getClient();
+        File projectPath = getRepository().getProjectPath();
+        String projUrl = getRepository().getReposUrl() + "/" + projectPath.getName();
+        
+        try {
+            client.mkdir(new String[] {projUrl},
+                    Config.getString("team.import.initialMessage"));
+            
+            client.checkout(projUrl, projectPath.getAbsolutePath(), Revision.HEAD, Revision.HEAD,
+                    Depth.empty, false, true);
+            
+            if (! isCancelled()) {
+                return new TeamworkCommandResult();
+            }
+        }
+        catch (ClientException ce) {
+            if (! isCancelled()) {
+                return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
+            }
+        }
+
+        return new TeamworkCommandAborted();
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnStatusCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnStatusCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d0a12c04c80b86ce5c8c269de344f54b7e0ea75
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnStatusCommand.java
@@ -0,0 +1,296 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.*;
+
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.Depth;
+import org.tigris.subversion.javahl.SVNClientInterface;
+import org.tigris.subversion.javahl.Status;
+import org.tigris.subversion.javahl.StatusCallback;
+import org.tigris.subversion.javahl.StatusKind;
+
+import bluej.groupwork.*;
+import bluej.utility.Debug;
+
+/**
+ * Subversion "status" command.
+ * 
+ * @author Davin McCall
+ */
+public class SvnStatusCommand extends SvnCommand
+{
+    private StatusListener listener;
+    private FileFilter filter;
+    private long currentRevision = -1;
+    
+    public SvnStatusCommand(SvnRepository repository, StatusListener listener,
+            FileFilter filter, boolean includeRemote)
+    {
+        super(repository);
+        this.listener = listener;
+        this.filter = filter;
+    }
+    
+    protected TeamworkCommandResult doCommand()
+    {
+        SVNClientInterface client = getClient();
+        File projectPath = getRepository().getProjectPath().getAbsoluteFile();
+        
+        try {
+            final List<Status> statusList = new LinkedList<Status>();
+            client.status(projectPath.getAbsolutePath(), Depth.infinity, true,
+                    true, false, false, new String[0], new StatusCallback() {
+                        public void doStatus(Status arg0)
+                        {
+                            statusList.add(arg0);
+                        }
+                    });
+            
+            Status [] status = statusList.toArray(new Status[statusList.size()]);
+            
+            /*
+             * Subversion is a bit stupid. If a directory has been removed from
+             * the repository, status of files within still shows as "up to date".
+             * We'll fix that. We need to cache status entries until we get the
+             * status for the parent directory.
+             */
+            
+            // The set of directories for which we have status
+            Set<File> completed = new HashSet<File>();
+            // A map (File->Set<TeamStatusInfo>) from directories for which
+            // we don't yet have status, to the status of files within
+            Map<File,Set<TeamStatusInfo>> unreported = new HashMap<File,Set<TeamStatusInfo>>();
+            
+            for (int i = 0; i < status.length; i++) {
+                File file = new File(status[i].getPath());
+                
+                int textStat = status[i].getTextStatus();
+                
+                // All I've seen so far is "added", "deleted", "non-svn" (none).
+                int reposStat = status[i].getRepositoryTextStatus();
+                
+                // the repository revision doesn't seem to be valid for
+                // status "normal", or "repository: deleted".
+                // it is valid for "repository: added".
+                long reposRev = status[i].getReposLastCmtRevisionNumber();
+                if (reposRev > currentRevision) {
+                    currentRevision = reposRev;
+                }
+                
+                TeamStatusInfo rinfo = null;
+                
+                if (textStat == StatusKind.missing
+                        || textStat == StatusKind.deleted) {
+                    String rev = "" + status[i].getLastChangedRevisionNumber();
+                    if (reposStat == StatusKind.modified) {
+                        rinfo = new TeamStatusInfo(file, rev, "" + reposRev, TeamStatusInfo.STATUS_CONFLICT_LDRM);
+                    }
+                    else {
+                        rinfo = new TeamStatusInfo(file, rev, "", TeamStatusInfo.STATUS_DELETED);
+                    }
+                }
+                else if (textStat == StatusKind.unversioned) {
+                    if (filter.accept(file)) {
+                        if (reposStat != StatusKind.added) {
+                            rinfo = new TeamStatusInfo(file, "", "", TeamStatusInfo.STATUS_NEEDSADD);
+                        }
+                        else {
+                            // conflict: added locally and in repository
+                            rinfo = new TeamStatusInfo(file, "", "" + status[i].getReposLastCmtRevisionNumber(), TeamStatusInfo.STATUS_CONFLICT_ADD);
+                        }
+                        if (file.isDirectory()) {
+                            statLocalDir(file);
+                        }
+                    }
+                }
+                else if (textStat == StatusKind.normal) {
+                    if (filter.accept(file)) {
+                        String rev = "" + status[i].getLastChangedRevisionNumber();
+                        if (reposStat == StatusKind.deleted) {
+                            rinfo = new TeamStatusInfo(file, rev, "", TeamStatusInfo.STATUS_REMOVED);
+                        }
+                        else if (reposStat == StatusKind.modified) {
+                            rinfo = new TeamStatusInfo(file, rev,
+                                    "" + status[i].getReposLastCmtRevisionNumber(),
+                                    TeamStatusInfo.STATUS_NEEDSUPDATE);
+                        }
+                        else {
+                            rinfo = new TeamStatusInfo(file, rev, rev, TeamStatusInfo.STATUS_UPTODATE);
+                        }
+                    }
+                }
+                else if (textStat == StatusKind.modified) {
+                    if (filter.accept(file)) {
+                        String rev = "" + status[i].getLastChangedRevisionNumber();
+                        if (reposStat == StatusKind.deleted) {
+                            rinfo = new TeamStatusInfo(file, rev, "", TeamStatusInfo.STATUS_CONFLICT_LMRD);
+                        }
+                        else if (reposStat == StatusKind.modified) {
+                            rinfo = new TeamStatusInfo(file, rev, "", TeamStatusInfo.STATUS_NEEDSMERGE);
+                        }
+                        else {
+                            rinfo = new TeamStatusInfo(file, rev, rev, TeamStatusInfo.STATUS_NEEDSCOMMIT);
+                        }
+                    }
+                }
+                else if (textStat == StatusKind.none) {
+                    if (reposStat == StatusKind.added) {
+                        rinfo = new TeamStatusInfo(file, "", "" + reposRev, TeamStatusInfo.STATUS_NEEDSCHECKOUT);
+                    }
+                }
+                else if (textStat == StatusKind.added) {
+                    // shouldn't normally happen unless something went wrong
+                    // or someone has done "svn add" from command line etc.
+                    rinfo = new TeamStatusInfo(file, "", "", TeamStatusInfo.STATUS_NEEDSCOMMIT);
+                }
+                
+//                if (filter.accept(file) || ! file.exists()) {
+//                    System.out.println("Status for: " + status[i].getPath());
+//                    System.out.println("   Revision: " + status[i].getRevisionNumber());
+//                    System.out.println("   lcRev: " + status[i].getLastChangedRevisionNumber());
+//                    System.out.println("   statusDesc: " + status[i].getTextStatusDescription());
+//                    
+//                    System.out.println("   repostStat: " + Status.Kind.getDescription(reposStat));
+//                    System.out.println("   reposRev: " + status[i].getReposLastCmtRevisionNumber());
+//                    System.out.println("   hasRemote: " + status[i].hasRemote());
+//                    
+//                    System.out.println("   conflictNew: " + status[i].getConflictNew());
+//                    System.out.println("   conflictOld: " + status[i].getConflictOld());
+//                    System.out.println("   conflictWorking: " + status[i].getConflictWorking());
+//                }
+                
+                if (rinfo != null) {
+                    if (! file.exists()) {
+                        listener.gotStatus(rinfo);
+                    }
+                    else if (completed.contains(file.getParentFile())
+                            || file.equals(projectPath)) {
+                        complete(completed, unreported, rinfo);
+                    }
+                    else {
+                        // The status of the parent directory hasn't been reported
+                        // yet. If the parent has been removed, the status we have
+                        // now is incorrect; we need to cache the result into the
+                        // parent status is reported.
+                        Set<TeamStatusInfo> s = unreported.get(file.getParentFile());
+                        if (s == null) {
+                            s = new HashSet<TeamStatusInfo>();
+                        }
+                        s.add(rinfo);
+                        unreported.put(file.getParentFile(), s);
+                    }
+                }
+            }
+            
+            listener.statusComplete(new SvnStatusHandle(getRepository(), currentRevision));
+            return new TeamworkCommandResult();
+        }
+        catch (ClientException ce) {
+            if (! isCancelled()) {
+                Debug.reportError("Subversion status command exception", ce);
+                return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
+            }
+        }
+
+        return new TeamworkCommandAborted();
+    }
+    
+    /**
+     * Provide status information for files in a directory which is
+     * unversioned (and therefore ignored) according to subversion
+     */
+    private void statLocalDir(File dir)
+    {
+        File [] subFiles = dir.listFiles(filter);
+        for (int i = 0; i < subFiles.length; i++) {
+            listener.gotStatus(new TeamStatusInfo(subFiles[i], "", "",
+                    TeamStatusInfo.STATUS_NEEDSADD));
+            if (subFiles[i].isDirectory()) {
+                statLocalDir(subFiles[i]);
+            }
+        }
+    }
+    
+    private void complete(Set<File> completed, Map<File,Set<TeamStatusInfo>> unreported,
+            TeamStatusInfo rinfo)
+    {
+        listener.gotStatus(rinfo);
+
+        int rinfoStat = rinfo.getStatus();
+
+        File file = rinfo.getFile();
+        if (file.isDirectory()) {
+            completed.add(file);
+
+            Set<TeamStatusInfo> entries = unreported.remove(file);
+            if (entries == null) {
+                entries = Collections.emptySet();
+            }
+            for (Iterator<TeamStatusInfo> i = entries.iterator(); i.hasNext(); ) {
+                TeamStatusInfo status = i.next();
+                int einfoStat = status.getStatus();
+                if (rinfoStat == TeamStatusInfo.STATUS_CONFLICT_LMRD
+                        || rinfoStat == TeamStatusInfo.STATUS_REMOVED) {
+
+                    // Parent was removed. We must change the child status to
+                    // be removed also. One case we don't have to worry about
+                    // is if the child has been locally deleted.
+                    if (einfoStat != TeamStatusInfo.STATUS_DELETED
+                            && einfoStat != TeamStatusInfo.STATUS_NEEDSCHECKOUT) {
+                        // can these happen?
+                        //if (einfoStat == TeamStatusInfo.STATUS_CONFLICT_LDRM)
+                        //if (einfoStat == TeamStatusInfo.STATUS_CONFLICT_LMRD)
+                        if (einfoStat == TeamStatusInfo.STATUS_NEEDSADD) {
+                            // what status to give here?
+                            einfoStat = TeamStatusInfo.STATUS_CONFLICT_LMRD;
+                        }
+                        else if (einfoStat == TeamStatusInfo.STATUS_NEEDSCOMMIT) {
+                            einfoStat = TeamStatusInfo.STATUS_CONFLICT_LMRD;
+                        }
+                        else if (einfoStat == TeamStatusInfo.STATUS_NEEDSMERGE) {
+                            einfoStat = TeamStatusInfo.STATUS_CONFLICT_LMRD;
+                        }
+                        else if (einfoStat == TeamStatusInfo.STATUS_NEEDSUPDATE) {
+                            einfoStat = TeamStatusInfo.STATUS_REMOVED;
+                        }
+                        else if (einfoStat == TeamStatusInfo.STATUS_UPTODATE) {
+                            einfoStat = TeamStatusInfo.STATUS_REMOVED;
+                        }
+
+                        complete(completed, unreported, new TeamStatusInfo(
+                                status.getFile(), status.getLocalVersion(),
+                                status.getRepositoryVersion(), einfoStat));
+                    }
+                }
+                else {
+                    // parent not deleted: report normally
+                    complete(completed, unreported, status);
+                }
+            }
+
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnStatusHandle.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnStatusHandle.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae2107660943d78ef98e797d410ed0947a43186a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnStatusHandle.java
@@ -0,0 +1,89 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import bluej.groupwork.Repository;
+import bluej.groupwork.StatusHandle;
+import bluej.groupwork.TeamStatusInfo;
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.UpdateListener;
+
+/**
+ * Implementation of StatusHandle for Subversion.
+ * 
+ * @author davmac
+ */
+public class SvnStatusHandle implements StatusHandle
+{
+    private SvnRepository repository;
+    private long version;
+    
+    public SvnStatusHandle(SvnRepository repository, long version)
+    {
+        this.repository = repository;
+        this.version = version;
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.groupwork.StatusHandle#commitAll(java.util.Set, java.util.Set, java.util.Set, java.util.Set, java.util.Set, java.lang.String)
+     */
+    public TeamworkCommand commitAll(Set<File> newFiles,
+            Set<File> binaryNewFiles, Set<File> deletedFiles, Set<File> files,
+            Set<TeamStatusInfo> forceFiles, String commitComment)
+    {
+        Set<File> forceFileSet = new HashSet<File>();
+        for (Iterator<TeamStatusInfo> i = forceFiles.iterator(); i.hasNext(); ) {
+            forceFileSet.add(i.next().getFile());
+        }
+        
+        if (version != -1) {
+            return new SvnCommitCommand(repository, newFiles, binaryNewFiles, deletedFiles,
+                    files, forceFileSet, version, commitComment);
+        }
+        else {
+            // The working copy is up-to-date
+            return new SvnCommitAllCommand(repository, newFiles, binaryNewFiles,
+                    deletedFiles, files, commitComment);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.groupwork.StatusHandle#updateTo(bluej.groupwork.UpdateListener, java.util.Set, java.util.Set)
+     */
+    public TeamworkCommand updateTo(UpdateListener listener, Set<File> files,
+            Set<File> forceFiles)
+    {
+        return new SvnUpdateToCommand(repository, listener,
+                version, files, forceFiles);
+    }
+
+    @Override
+    public Repository getRepository()
+    {
+        return repository;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnUpdateToCommand.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnUpdateToCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..df1d7d48ee45f970359a1d54a6797fe96921f43c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/svn/SvnUpdateToCommand.java
@@ -0,0 +1,307 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.svn;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.tigris.subversion.javahl.ClientException;
+import org.tigris.subversion.javahl.ConflictDescriptor;
+import org.tigris.subversion.javahl.ConflictResult;
+import org.tigris.subversion.javahl.Depth;
+import org.tigris.subversion.javahl.NodeKind;
+import org.tigris.subversion.javahl.Notify2;
+import org.tigris.subversion.javahl.NotifyAction;
+import org.tigris.subversion.javahl.NotifyInformation;
+import org.tigris.subversion.javahl.NotifyStatus;
+import org.tigris.subversion.javahl.PropertyData;
+import org.tigris.subversion.javahl.Revision;
+import org.tigris.subversion.javahl.SVNClientInterface;
+import org.tigris.subversion.javahl.Status;
+import org.tigris.subversion.javahl.StatusCallback;
+import org.tigris.subversion.javahl.SubversionException;
+
+import bluej.groupwork.TeamworkCommandAborted;
+import bluej.groupwork.TeamworkCommandError;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.groupwork.UpdateListener;
+import bluej.groupwork.UpdateResults;
+import bluej.utility.Debug;
+
+/**
+ * Subversion command to update to a particular revision.
+ * 
+ * @author Davin McCall
+ */
+public class SvnUpdateToCommand extends SvnCommand implements UpdateResults
+{
+    private long version;
+    private Set<File> files;
+    private Set<File> forceFiles;
+    private UpdateListener listener;
+    private List<File> conflicts = new ArrayList<File>();
+    private Set<File> binaryConflicts = new HashSet<File>();
+    
+    public SvnUpdateToCommand(SvnRepository repository, UpdateListener listener,
+            long version, Set<File> files, Set<File> forceFiles)
+    {
+        super(repository);
+        this.version = version;
+        this.files = files;
+        this.forceFiles = forceFiles;
+        this.listener = listener;
+    }
+    
+    protected TeamworkCommandResult doCommand()
+    {
+        SVNClientInterface client = getClient();
+
+        // The subversion client library gives us update notifications before
+        // the notifications have actually been performed. So, we save the
+        // list of updated files and notify the listener only once the update
+        // is complete.
+        final List<File> addedList = new ArrayList<File>();
+        final List<File> updatedList = new ArrayList<File>();
+        final List<File> removedList = new ArrayList<File>();
+        final List<File> removedDirs = new ArrayList<File>();
+        
+        try {
+            String [] paths = new String[forceFiles.size() + files.size()];
+            int j = 0;
+            for (Iterator<File> i = forceFiles.iterator(); i.hasNext(); ) {
+                File file = i.next();
+                paths[j++] = file.getAbsolutePath();
+                // Delete the file, so the update cannot conflict
+                file.delete();
+            }
+            for (Iterator<File> i = files.iterator(); i.hasNext(); ) {
+                File file = i.next();
+                paths[j++] = file.getAbsolutePath();
+            }
+
+            client.notification2(new Notify2() {
+                public void onNotify(NotifyInformation ninfo)
+                {
+                    // System.out.println("NotifyInfo:");
+                    // System.out.println("  path: " + ninfo.getPath());
+                    // System.out.println("  revision: " + ninfo.getRevision());
+                    // System.out.println("  action: " + NotifyAction.actionNames[ninfo.getAction()]);
+                    // System.out.println("  errmsg: " + ninfo.getErrMsg());
+                    // System.out.println("  contentstate: " + NotifyStatus.statusNames[ninfo.getContentState()]);
+                    // System.out.println("  node kind = " + NodeKind.getNodeKindName(ninfo.getKind()));
+                    // System.out.println("  mimetype = " + ninfo.getMimeType());
+                    
+                    if (ninfo.getKind() == NodeKind.file
+                            || ninfo.getKind() == NodeKind.none) {
+                        int action = ninfo.getAction();
+                        if (ninfo.getPath() != null) {
+                            File file = new File(ninfo.getPath());
+                            if (action == NotifyAction.update_add
+                                    || action == NotifyAction.restore) {
+                                addedList.add(file);
+                            }
+                            else if (action == NotifyAction.update_update) {
+                                updatedList.add(file);
+                                if (ninfo.getContentState() == NotifyStatus.conflicted) {
+                                    conflicts.add(file);
+                                }
+                            }
+                            else if (action == NotifyAction.update_delete) {
+                                removedList.add(file);
+                            }
+                            /* Goik: Quick fix, not present in any usable Maven version found so far. Newer svn-javahl depends
+                             * on Apache API not available from Maven for licensing issues
+                             */
+//                            else if (action == NotifyAction.tree_conflict) {
+//                                // We get this if the file has been removed in
+//                                // repository, but modified here.
+//                                binaryConflicts.add(file);
+//                            }
+                        }
+                    }
+                    else if (ninfo.getKind() == NodeKind.dir) {
+                        int action = ninfo.getAction();
+                        if (action == NotifyAction.update_delete) {
+                            removedDirs.add(new File(ninfo.getPath()));
+                        }
+                    }
+                    
+                }
+            });
+            
+            client.update(paths, Revision.getInstance(version),
+                    Depth.immediates, false, false, false);
+        }
+        catch (ClientException ce) {
+            if (isCancelled()) {
+                return new TeamworkCommandAborted();
+            } else {
+                return new TeamworkCommandError(ce.getMessage(), ce.getLocalizedMessage());
+            }
+        }
+        finally {
+            client.notification2(null);
+            
+            Iterator<File> i;
+            for (i = addedList.iterator(); i.hasNext(); ) {
+                listener.fileAdded(i.next());
+            }
+            for (i = updatedList.iterator(); i.hasNext(); ) {
+                listener.fileUpdated(i.next());
+            }
+            for (i = removedList.iterator(); i.hasNext(); ) {
+                listener.fileRemoved(i.next());
+            }
+            for (i = removedDirs.iterator(); i.hasNext(); ) {
+                listener.dirRemoved(i.next());
+            }
+            
+            if (! conflicts.isEmpty()) {
+                for (i = conflicts.iterator(); i.hasNext(); ) {
+                    File file = (File) i.next();
+                    try {
+                        PropertyData pdata = client.propertyGet(
+                                file.getAbsolutePath(), "svn:mime-type", Revision.getInstance(version));
+                        if (pdata != null && "application/octet-stream".equals(pdata.getValue())) {
+                            // This is a binary file
+                            i.remove();
+                            binaryConflicts.add(file);
+                        }
+                        else {
+                            // remove all the extraneous files that subversion generates
+                            client.resolve(file.getAbsolutePath(), 0, ConflictResult.chooseMerged);
+                        }
+                    }
+                    catch (SubversionException se) {
+                        Debug.message("Subversion client exception when resolving conflicts: " + se.getLocalizedMessage());
+                        Debug.message("   (on file: " + file + ")");
+                    } catch (ClientException ce) {
+                    	Debug.message("Goik quick fix: Subversion client exception when resolving conflicts: " + ce.getLocalizedMessage());
+                        Debug.message("   (on file: " + file + ")");
+					}
+                }
+            }
+            if (! conflicts.isEmpty() || ! binaryConflicts.isEmpty()) {
+                listener.handleConflicts(this);
+            }
+        }
+        
+        return new TeamworkCommandResult();
+    }
+
+    public Set<File> getBinaryConflicts()
+    {
+        return binaryConflicts;
+    }
+    
+    public List<File> getConflicts()
+    {
+        return conflicts;
+    }
+    
+    public void overrideFiles(final Set<File> files)
+    {
+        final SVNClientInterface client = getRepository().getClient();
+
+        StatusCallback scb = new StatusCallback() {
+            public void doStatus(Status status)
+            {
+            	
+            	/* Goik quick fix: Method getConflictDescriptor() not available in current version */
+            	
+//                File file = new File(status.getPath());
+//                try {
+//                    ConflictDescriptor cd = status.getConflictDescriptor();
+//                    if (cd != null) {
+//                        int action = cd.getAction();
+//                        int kind = cd.getKind();
+//                        int reason = cd.getReason();
+//
+//                        if (kind != ConflictDescriptor.Kind.text) {
+//                            return; // Can't handle property conflicts
+//                        }
+//
+//                        if (action == ConflictDescriptor.Action.delete
+//                                && reason == ConflictDescriptor.Reason.edited) {
+//                            // The file was deleted in the repository, but locally edited.
+//                            // For some reason "chooseMerged" is the only option which works:
+//                            client.resolve(file.getAbsolutePath(), 0, ConflictResult.chooseMerged);
+//
+//                            // That leaves the file in the "added" status.
+//                            boolean keepLocal = ! files.contains(file); 
+//
+//                            // Doing a remove will either remove the "added" status
+//                            // (keepLocal == true) or completely remove the file.
+//                            String [] paths = new String[] { file.getPath() };
+//                            client.remove(paths, "", true, keepLocal, Collections.emptyMap());
+//
+//                            return;
+//                        }
+//                        else if (action == ConflictDescriptor.Action.edit
+//                                && reason == ConflictDescriptor.Reason.deleted) {
+//                            // Locally deleted, but modifications in the repository.
+//                            // Shouldn't see this normally, seeing as BlueJ does a
+//                            // "forced update" of such files.
+//                            client.resolve(file.getAbsolutePath(), 0, ConflictResult.chooseTheirsFull);
+//                        }
+//                    }
+//
+//                    String conflictOld = status.getConflictOld();
+//                    if (conflictOld != null) {
+//                        File oldRev = new File(file.getParent(), status.getConflictOld());
+//                        oldRev.delete();
+//                    }
+//
+//                    if (files.contains(file)) {
+//                        // override with repository version
+//                        client.resolve(file.getAbsolutePath(), 0, ConflictResult.chooseTheirsFull);
+//                    }
+//                    else {
+//                        // keep working copy version
+//                        client.resolve(file.getAbsolutePath(), 0, ConflictResult.chooseMineFull);
+//                    }
+//                }
+//                catch (SubversionException sve) {
+//                    Debug.message("Subversion library exception trying to resolve binary conflict: " + sve.getLocalizedMessage());
+//                    Debug.message("   (on file: " + file + ")");
+//                }
+            } 
+        };
+        
+        for (Iterator<File> i = binaryConflicts.iterator(); i.hasNext(); ) {
+            File file = i.next();
+            try {
+                client.status(file.getAbsolutePath(), Depth.empty, false,
+                        true, true, true, new String[0], scb);
+            }
+            catch (ClientException ce) {
+                Debug.message("Subversion library exception trying to resolve binary conflict: " + ce.getLocalizedMessage());
+                Debug.message("   (on file: " + file + ")");
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ActivityIndicator.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ActivityIndicator.java
new file mode 100644
index 0000000000000000000000000000000000000000..257a647aeb8763b7946f068ff212562b3b6adcfe
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ActivityIndicator.java
@@ -0,0 +1,91 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.Dimension;
+import java.awt.EventQueue;
+
+import javax.swing.JComponent;
+import javax.swing.JProgressBar;
+import javax.swing.OverlayLayout;
+
+public class ActivityIndicator extends JComponent implements Runnable
+{
+    private JProgressBar progressBar;
+    private boolean running;
+    
+    public ActivityIndicator()
+    {
+        setBorder(null);
+        setLayout(new OverlayLayout(this));
+        progressBar = new JProgressBar(0, 100);
+        progressBar.setIndeterminate(true);
+        progressBar.setVisible(false);
+        add(progressBar);
+    }
+    
+    /**
+     * Set the activity indicator's running state. This is safe to call
+     * from any thread.
+     * 
+     * @param running  The new running state
+     */
+    public void setRunning(boolean running)
+    {
+        this.running = running;
+        if (EventQueue.isDispatchThread()) {
+            progressBar.setVisible(running);
+        }
+        else {
+            EventQueue.invokeLater(this);
+        }
+    }
+    
+    /*
+     * The run() method will only be called on the event dispatch thread, and
+     * is used to update the current running state.
+     */
+    public void run()
+    {
+        progressBar.setVisible(running);
+    }
+    
+    public Dimension getPreferredSize()
+    {
+        return progressBar.getPreferredSize();
+    }
+    
+    public Dimension getMinimumSize()
+    {
+        return progressBar.getMinimumSize();
+    }
+    
+    public Dimension getMaximumSize()
+    {
+        return progressBar.getMaximumSize();
+    }
+    
+    public boolean isValidateRoot()
+    {
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/CheckConnectionDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/CheckConnectionDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7a1bff144d6100f00dbb87ba2ba6102990351f0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/CheckConnectionDialog.java
@@ -0,0 +1,130 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.Dialog;
+import java.awt.EventQueue;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.groupwork.TeamSettings;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.groupwork.TeamworkProvider;
+import bluej.utility.DBox;
+import bluej.utility.EscapeDialog;
+import bluej.utility.MultiWrapLabel;
+
+/**
+ * A dialog which displays an activity indicator while connection settings are
+ * being verified
+ * 
+ * @author Davin McCall
+ */
+public class CheckConnectionDialog extends EscapeDialog
+{
+    private ActivityIndicator activityIndicator;
+    private MultiWrapLabel connLabel;
+    private JButton closeButton;
+    
+    private TeamSettings settings;
+    private TeamworkProvider provider;
+    
+    public CheckConnectionDialog(Dialog owner, TeamworkProvider provider,
+            TeamSettings settings)
+    {
+        super(owner, true);
+        setTitle(Config.getString("team.settings.checkConnection"));
+        
+        this.provider = provider;
+        this.settings = settings;
+        
+        buildUI();
+        setLocationRelativeTo(owner);
+    }
+    
+    private void buildUI()
+    {
+        DBox contentPane = new DBox(DBox.Y_AXIS, 0, BlueJTheme.componentSpacingLarge, 0.0f);
+        contentPane.setBorder(BlueJTheme.dialogBorder);
+        setContentPane(contentPane);
+        
+        connLabel = new MultiWrapLabel(Config.getString("team.checkconn.checking"));
+        
+        contentPane.add(connLabel);
+        
+        activityIndicator = new ActivityIndicator();
+        activityIndicator.setRunning(true);
+        contentPane.add(activityIndicator);
+        
+        closeButton = BlueJTheme.getCancelButton();
+        closeButton.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e)
+                {
+                    setVisible(false);
+                }
+            });
+        contentPane.add(closeButton);
+        
+        pack();
+    }
+    
+    public void setVisible(boolean vis)
+    {
+        // Must start the thread before calling super.setVisible(), because
+        // we are modal - super.setVisible() will block.
+        if (vis) {
+            new Thread() {
+                public void run()
+                {
+                    final TeamworkCommandResult res = validateConnection();
+                    EventQueue.invokeLater(new Runnable() {
+                        public void run()
+                        {
+                            if (!res.isError()) {
+                                connLabel.setText(Config.getString("team.checkconn.ok"));
+                            }
+                            else {
+                                connLabel.setText(Config.getString("team.checkconn.bad")
+                                        + System.getProperty("line.separator") + System.getProperty("line.separator")
+                                        + res.getErrorMessage());
+                            }
+                            
+                            activityIndicator.setRunning(false);
+                            closeButton.setText(BlueJTheme.getCloseLabel());
+                            pack();
+                        }
+                    });
+                }
+            }.start();
+        }
+        super.setVisible(vis);
+    }
+    
+    private TeamworkCommandResult validateConnection()
+    {
+        return provider.checkConnection(settings);
+    }   
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/CommitCommentsFrame.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/CommitCommentsFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..52e8ee7c64caf23d9096cfcd39d5cc8f9631dfe3
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/CommitCommentsFrame.java
@@ -0,0 +1,636 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.BorderFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextArea;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.groupwork.CommitFilter;
+import bluej.groupwork.Repository;
+import bluej.groupwork.StatusHandle;
+import bluej.groupwork.StatusListener;
+import bluej.groupwork.TeamStatusInfo;
+import bluej.groupwork.TeamUtils;
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.groupwork.actions.CommitAction;
+import bluej.pkgmgr.BlueJPackageFile;
+import bluej.pkgmgr.Project;
+import bluej.utility.DBox;
+import bluej.utility.DBoxLayout;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+import bluej.utility.SwingWorker;
+import bluej.utility.Utility;
+
+
+/**
+ * A Swing based user interface to add commit comments.
+ * @author Bruce Quig
+ * @version $Id$
+ */
+public class CommitCommentsFrame extends EscapeDialog
+{
+    private JList commitFiles;
+    private JPanel topPanel;
+    private JPanel bottomPanel;
+    private JTextArea commitText;
+    private JButton commitButton;
+    private JCheckBox includeLayout;
+    private ActivityIndicator progressBar;
+    private CommitAction commitAction;
+    private CommitWorker commitWorker;
+
+    private Project project;
+    
+    private Repository repository;
+    private DefaultListModel commitListModel;
+    
+    private Set<TeamStatusInfo> changedLayoutFiles;
+    
+    /** The packages whose layout should be committed compulsorily */
+    private Set<File> packagesToCommmit = new HashSet<File>();
+    
+    private static String noFilesToCommit = Config.getString("team.nocommitfiles"); 
+
+    public CommitCommentsFrame(Project proj)
+    {
+        project = proj;
+        changedLayoutFiles = new HashSet<TeamStatusInfo>();
+        createUI();
+        DialogManager.centreDialog(this);
+    }
+    
+    public void setVisible(boolean show)
+    {
+        super.setVisible(show);
+        if (show) {
+            // we want to set comments and commit action to disabled
+            // until we know there is something to commit
+            commitAction.setEnabled(false);
+            commitText.setEnabled(false);
+            includeLayout.setSelected(false);
+            includeLayout.setEnabled(false);
+            changedLayoutFiles.clear();
+            commitListModel.removeAllElements();
+            
+            repository = project.getRepository();
+            
+            if (repository != null) {
+                try {
+                    project.saveAllEditors();
+                    project.saveAll();
+                }
+                catch (IOException ioe) {
+                    String msg = DialogManager.getMessage("team-error-saving-project");
+                    if (msg != null) {
+                        msg = Utility.mergeStrings(msg, ioe.getLocalizedMessage());
+                        DialogManager.showErrorText(this, msg);
+                    }
+                }
+                startProgress();
+                commitWorker = new CommitWorker();
+                commitWorker.start();
+            }
+            else {
+                super.setVisible(false);
+            }
+        }
+    }
+    
+    /**
+     * Create the user-interface for the error display dialog.
+     */
+    protected void createUI()
+    {
+        setTitle(Config.getString("team.commit.title"));
+        commitListModel = new DefaultListModel();
+        
+        //setIconImage(BlueJTheme.getIconImage());
+        setLocation(Config.getLocation("bluej.commitdisplay"));
+
+        // save position when window is moved
+        addComponentListener(new ComponentAdapter() {
+                public void componentMoved(ComponentEvent event)
+                {
+                    Config.putLocation("bluej.commitdisplay", getLocation());
+                }
+            });
+
+        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+        splitPane.setBorder(BlueJTheme.generalBorderWithStatusBar);
+        splitPane.setResizeWeight(0.5);
+
+        topPanel = new JPanel();
+
+        JScrollPane commitFileScrollPane = new JScrollPane();
+
+        {
+            topPanel.setLayout(new BorderLayout());
+
+            JLabel commitFilesLabel = new JLabel(Config.getString(
+                        "team.commit.files"));
+            commitFilesLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
+            topPanel.add(commitFilesLabel, BorderLayout.NORTH);
+
+            commitFiles = new JList(commitListModel);
+            commitFiles.setCellRenderer(new FileRenderer(project));
+            commitFiles.setEnabled(false);
+            commitFileScrollPane.setViewportView(commitFiles);
+            
+            topPanel.add(commitFileScrollPane, BorderLayout.CENTER);
+        }
+
+        splitPane.setTopComponent(topPanel);
+
+        bottomPanel = new JPanel();
+
+        {
+            bottomPanel.setLayout(new BorderLayout());
+
+            JLabel commentLabel = new JLabel(Config.getString(
+                        "team.commit.comment"));
+            commentLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
+            bottomPanel.add(commentLabel, BorderLayout.NORTH);
+
+            commitText = new JTextArea("");
+            commitText.setRows(6);
+            commitText.setColumns(42);
+
+            Dimension size = commitText.getPreferredSize();
+            size.width = commitText.getMinimumSize().width;
+            commitText.setMinimumSize(size);
+
+            JScrollPane commitTextScrollPane = new JScrollPane(commitText);
+            commitTextScrollPane.setMinimumSize(size);
+            bottomPanel.add(commitTextScrollPane, BorderLayout.CENTER);
+
+            commitAction = new CommitAction(this);
+            commitButton = BlueJTheme.getOkButton();
+            commitButton.setAction(commitAction);
+            getRootPane().setDefaultButton(commitButton);
+
+            JButton closeButton = BlueJTheme.getCancelButton();
+            closeButton.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent e)
+                    {
+                        commitWorker.abort();
+                        commitAction.cancel();
+                        setVisible(false);
+                    }
+                });
+           
+            DBox buttonPanel = new DBox(DBoxLayout.X_AXIS, 0, BlueJTheme.commandButtonSpacing, 0.5f);
+            buttonPanel.setBorder(BlueJTheme.generalBorder);
+            
+            progressBar = new ActivityIndicator();
+            progressBar.setRunning(false);
+            
+            DBox checkBoxPanel = new DBox(DBoxLayout.Y_AXIS, 0, BlueJTheme.commandButtonSpacing, 0.5f);
+            includeLayout = new JCheckBox(Config.getString("team.commit.includelayout"));
+            includeLayout.setEnabled(false);
+            includeLayout.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e)
+                {
+                    JCheckBox layoutCheck = (JCheckBox)e.getSource();
+                    if(layoutCheck.isSelected()) {
+                        addModifiedLayouts();
+                        if(!commitButton.isEnabled())
+                            commitAction.setEnabled(true);
+                    }
+                    // unselected
+                    else {
+                        removeModifiedLayouts();
+                        if(isCommitListEmpty())
+                            commitAction.setEnabled(false);
+                    }
+                }
+            });
+
+            checkBoxPanel.add(includeLayout);
+            checkBoxPanel.add(buttonPanel);
+            
+            buttonPanel.add(progressBar);
+            buttonPanel.add(commitButton);
+            buttonPanel.add(closeButton);
+            bottomPanel.add(checkBoxPanel, BorderLayout.SOUTH);
+        }
+
+        splitPane.setBottomComponent(bottomPanel);
+
+        getContentPane().add(splitPane);
+        pack();
+    }
+
+    public String getComment()
+    {
+        return commitText.getText();
+    }
+
+    public void setComment(String newComment)
+    {
+        commitText.setText(newComment);
+    }
+
+    public void reset()
+    {
+        commitListModel.clear();
+        setComment("");
+    }
+    
+    private void removeModifiedLayouts()
+    {
+        // remove modified layouts from list of files shown for commit
+        for(Iterator<TeamStatusInfo> it = changedLayoutFiles.iterator(); it.hasNext(); ) {
+            TeamStatusInfo info = it.next();
+            if (! packagesToCommmit.contains(info.getFile().getParentFile())) {
+                commitListModel.removeElement(info);
+            }
+        }
+        if (commitListModel.isEmpty()) {
+            commitListModel.addElement(noFilesToCommit);
+            commitText.setEnabled(false);
+        }
+    }
+    
+    private boolean isCommitListEmpty()
+    {
+        return commitListModel.isEmpty() || commitListModel.contains(noFilesToCommit);
+    }
+    
+    private void addModifiedLayouts()
+    {
+        if(commitListModel.contains(noFilesToCommit)) {
+            commitListModel.removeElement(noFilesToCommit);
+            commitText.setEnabled(true);
+        }
+        // add diagram layout files to list of files to be committed
+        Set<File> displayedLayouts = new HashSet<File>();
+        for(Iterator<TeamStatusInfo> it = changedLayoutFiles.iterator(); it.hasNext(); ) {
+            TeamStatusInfo info = it.next();
+            File parentFile = info.getFile().getParentFile();
+            if (! displayedLayouts.contains(parentFile)
+                    && ! packagesToCommmit.contains(parentFile)) {
+                commitListModel.addElement(info);
+                displayedLayouts.add(info.getFile().getParentFile());
+            }
+        }
+    }
+    
+    /**
+     * Get a list of the layout files to be committed
+     */
+    public Set<File> getChangedLayoutFiles()
+    {
+        Set<File> files = new HashSet<File>();
+        for(Iterator<TeamStatusInfo> it = changedLayoutFiles.iterator(); it.hasNext(); ) {
+            TeamStatusInfo info = it.next();
+            files.add(info.getFile());
+        }
+        return files;
+    }
+    
+    /**
+     * Remove a file from the list of changes layout files.
+     */
+    private void removeChangedLayoutFile(File file)
+    {
+        for(Iterator<TeamStatusInfo> it = changedLayoutFiles.iterator(); it.hasNext(); ) {
+            TeamStatusInfo info = it.next();
+            if (info.getFile().equals(file)) {
+                it.remove();
+                return;
+            }
+        }        
+    }
+    
+    /**
+     * Get a set of the layout files which have changed (with status info).
+     */
+    public Set<TeamStatusInfo> getChangedLayoutInfo()
+    {
+        return changedLayoutFiles;
+    }
+    
+    public boolean includeLayout()
+    {
+        return includeLayout != null && includeLayout.isSelected();
+    }
+    
+    /**
+     * Start the activity indicator.
+     */
+    public void startProgress()
+    {
+        progressBar.setRunning(true);
+    }
+
+    /**
+     * Stop the activity indicator. Call from any thread.
+     */
+    public void stopProgress()
+    {
+        progressBar.setRunning(false);
+    }
+    
+    public Project getProject()
+    {
+        return project;
+    }
+    
+    private void setLayoutChanged(boolean hasChanged)
+    {
+        includeLayout.setEnabled(hasChanged);
+    }
+
+    /**
+    * Inner class to do the actual cvs status check to populate commit dialog
+    * to ensure that the UI is not blocked during remote call
+    */
+    class CommitWorker extends SwingWorker implements StatusListener
+    {
+        List<TeamStatusInfo> response;
+        TeamworkCommand command;
+        TeamworkCommandResult result;
+        private boolean aborted;
+
+        public CommitWorker()
+        {
+            super();
+            response = new ArrayList<TeamStatusInfo>();
+            FileFilter filter = project.getTeamSettingsController().getFileFilter(true);
+            command = repository.getStatus(this, filter, false);
+        }
+        
+        /*
+         * @see bluej.groupwork.StatusListener#gotStatus(bluej.groupwork.TeamStatusInfo)
+         */
+        public void gotStatus(TeamStatusInfo info)
+        {
+            response.add(info);
+        }
+        
+        /*
+         * @see bluej.groupwork.StatusListener#statusComplete(bluej.groupwork.CommitHandle)
+         */
+        public void statusComplete(StatusHandle statusHandle)
+        {
+            commitAction.setStatusHandle(statusHandle);
+        }
+        
+        public Object construct()
+        {
+            result = command.getResult();
+            return response;
+        }
+        
+        public void abort()
+        {
+            command.cancel();
+            aborted = true;
+        }
+
+        public void finished()
+        {
+            stopProgress();
+            if (! aborted) {
+                if (result.isError()) {
+                    TeamUtils.handleServerResponse(result, CommitCommentsFrame.this);
+                    setVisible(false);
+                }
+                else if (response != null) {
+                    Set<File> filesToCommit = new HashSet<File>();
+                    Set<File> filesToAdd = new LinkedHashSet<File>();
+                    Set<File> filesToDelete = new HashSet<File>();
+                    Set<File> mergeConflicts = new HashSet<File>();
+                    Set<File> deleteConflicts = new HashSet<File>();
+                    Set<File> otherConflicts = new HashSet<File>();
+                    Set<File> needsMerge = new HashSet<File>();
+                    Set<File> modifiedLayoutFiles = new HashSet<File>();
+
+                    List<TeamStatusInfo> info = response;
+                    getCommitFileSets(info, filesToCommit, filesToAdd, filesToDelete,
+                            mergeConflicts, deleteConflicts, otherConflicts,
+                            needsMerge, modifiedLayoutFiles);
+
+                    if (!mergeConflicts.isEmpty() || !deleteConflicts.isEmpty()
+                            || !otherConflicts.isEmpty() || !needsMerge.isEmpty()) {
+
+                        handleConflicts(mergeConflicts, deleteConflicts,
+                                otherConflicts, needsMerge);
+                        return;
+                    }
+
+                    commitAction.setFiles(filesToCommit);
+                    commitAction.setNewFiles(filesToAdd);
+                    commitAction.setDeletedFiles(filesToDelete);
+                }
+
+                if(commitListModel.isEmpty()) {
+                    commitListModel.addElement(noFilesToCommit);
+                }
+                else {
+                    commitText.setEnabled(true);
+                    commitText.requestFocusInWindow();
+                    commitAction.setEnabled(true);
+                }
+            }
+        }
+        
+        private void handleConflicts(Set<File> mergeConflicts, Set<File> deleteConflicts,
+                Set<File> otherConflicts, Set<File> needsMerge)
+        {
+            String dlgLabel;
+            String filesList;
+            
+            // If there are merge conflicts, handle those first
+            if (! mergeConflicts.isEmpty()) {
+                dlgLabel = "team-resolve-merge-conflicts";
+                filesList = buildConflictsList(mergeConflicts);
+            }
+            else if (! deleteConflicts.isEmpty()) {
+                dlgLabel = "team-resolve-conflicts-delete";
+                filesList = buildConflictsList(deleteConflicts);
+            }
+            else if (! otherConflicts.isEmpty()) {
+                dlgLabel = "team-update-first";
+                filesList = buildConflictsList(otherConflicts);
+            }
+            else {
+                stopProgress();
+                DialogManager.showMessage(CommitCommentsFrame.this, "team-uptodate-failed");
+                CommitCommentsFrame.this.setVisible(false);
+                return;
+            }
+
+            stopProgress();
+            DialogManager.showMessageWithText(CommitCommentsFrame.this, dlgLabel, filesList);
+            CommitCommentsFrame.this.setVisible(false);
+        }
+        
+        /**
+         * Buid a list of files, max out at 10 files.
+         * @param conflicts
+         * @return
+         */
+        private String buildConflictsList(Set<File> conflicts)
+        {
+            String filesList = "";
+            Iterator<File> i = conflicts.iterator();
+            for (int j = 0; j < 10 && i.hasNext(); j++) {
+                File conflictFile = (File) i.next();
+                filesList += "    " + conflictFile.getName() + "\n";
+            }
+
+            if (i.hasNext()) {
+                filesList += "    " + Config.getString("team.commit.moreFiles");
+            }
+            
+            return filesList;
+        }
+        
+        /**
+         * Go through the status list, and figure out which files to commit, and
+         * of those which are to be added (i.e. which aren't in the repository) and
+         * which are to be removed.
+         * 
+         * @param info  The list of files with status (List of TeamStatusInfo)
+         * @param filesToCommit  The set to store the files to commit in
+         * @param filesToAdd     The set to store the files to be added in
+         * @param filesToRemove  The set to store the files to be removed in
+         * @param mergeConflicts The set to store files with merge conflicts in.
+         * @param deleteConflicts The set to store files with conflicts in, which
+         *                        need to be resolved by first deleting the local file
+         * @param otherConflicts  The set to store files with "locally deleted" conflicts
+         *                        (locally deleted, remotely modified).
+         * @param needsMerge     The set of files which are updated locally as
+         *                       well as in the repository (required merging).
+         * @param conflicts      The set to store unresolved conflicts in
+         */
+        private void getCommitFileSets(List<TeamStatusInfo> info, Set<File> filesToCommit, Set<File> filesToAdd,
+                Set<File> filesToRemove, Set<File> mergeConflicts, Set<File> deleteConflicts,
+                Set<File> otherConflicts, Set<File> needsMerge, Set<File> modifiedLayoutFiles)
+        {
+            //boolean includeLayout = project.getTeamSettingsController().includeLayout();
+            
+            CommitFilter filter = new CommitFilter();
+            Map<File,File> modifiedLayoutDirs = new HashMap<File,File>();
+
+            for (Iterator<TeamStatusInfo> it = info.iterator(); it.hasNext();) {
+                TeamStatusInfo statusInfo = it.next();
+                File file = statusInfo.getFile();
+                boolean isPkgFile = BlueJPackageFile.isPackageFileName(file.getName());
+                int status = statusInfo.getStatus();
+                if(filter.accept(statusInfo)) {
+                    if (! isPkgFile) {
+                        commitListModel.addElement(statusInfo);
+                        filesToCommit.add(file);
+                    }
+                    else if (status == TeamStatusInfo.STATUS_NEEDSADD
+                                || status == TeamStatusInfo.STATUS_DELETED
+                                || status == TeamStatusInfo.STATUS_CONFLICT_LDRM) {
+                        // Package file which must be committed.
+                        if (packagesToCommmit.add(statusInfo.getFile().getParentFile())) {
+                            commitListModel.addElement(statusInfo);
+                            File otherPkgFile = modifiedLayoutDirs.remove(file.getParentFile());
+                            if (otherPkgFile != null) {
+                                removeChangedLayoutFile(otherPkgFile);
+                                filesToCommit.add(otherPkgFile);
+                            }
+                        }
+                        filesToCommit.add(statusInfo.getFile());
+                    }
+                    else {
+                        // add file to list of files that may be added to commit
+                        File parentFile = file.getParentFile();
+                        if (! packagesToCommmit.contains(parentFile)) {
+                            modifiedLayoutFiles.add(file);
+                            modifiedLayoutDirs.put(parentFile, file);
+                            // keep track of StatusInfo objects representing changed diagrams
+                            changedLayoutFiles.add(statusInfo);
+                        }
+                        else {
+                            // We must commit the file unconditionally
+                            filesToCommit.add(file);
+                        }
+                    }
+                    
+                    if (status == TeamStatusInfo.STATUS_NEEDSADD) {
+                        filesToAdd.add(statusInfo.getFile());
+                    }
+                    else if (status == TeamStatusInfo.STATUS_DELETED
+                            || status == TeamStatusInfo.STATUS_CONFLICT_LDRM) {
+                        filesToRemove.add(statusInfo.getFile());
+                    }
+                }
+                else {
+                    if(! isPkgFile) {
+                        if (status == TeamStatusInfo.STATUS_HASCONFLICTS) {
+                            mergeConflicts.add(statusInfo.getFile());
+                        }
+                        if (status == TeamStatusInfo.STATUS_UNRESOLVED
+                                || status == TeamStatusInfo.STATUS_CONFLICT_ADD
+                                || status == TeamStatusInfo.STATUS_CONFLICT_LMRD) {
+                            deleteConflicts.add(statusInfo.getFile());
+                        }
+                        if (status == TeamStatusInfo.STATUS_CONFLICT_LDRM) {
+                            otherConflicts.add(statusInfo.getFile());
+                        }
+                        if (status == TeamStatusInfo.STATUS_NEEDSMERGE) {
+                            needsMerge.add(statusInfo.getFile());
+                        }
+                    }
+                }
+            }
+            
+            setLayoutChanged (! changedLayoutFiles.isEmpty());
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ConflictsDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ConflictsDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..875a653b9828deb627825f10d1fcd0fd28878cb8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ConflictsDialog.java
@@ -0,0 +1,188 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+
+import bluej.pkgmgr.Project;
+
+import java.awt.FlowLayout;
+import java.awt.Font;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+
+/**
+ * A dialog which presents conflicts after an update.
+ * 
+ * @author fisker
+ */
+public class ConflictsDialog extends JDialog
+{
+    private JLabel heading;
+    private List<String> bluejConflicts;
+    private List<String> nonBluejConflicts;
+    private Project project;
+
+    /**
+     * @param project2
+     * @param blueJconflicts
+     * @param nonBlueJConflicts
+     */
+    public ConflictsDialog(Project project, List<String> bluejConflicts,
+        List<String> nonBlueJConflicts)
+    {
+        super();
+        this.project = project;
+        this.bluejConflicts = bluejConflicts;
+        this.nonBluejConflicts = nonBlueJConflicts;
+        setTitle(Config.getString("team.conflicts.title"));
+        makeWindow();
+    }
+
+    private void makeWindow()
+    {
+        JPanel mainPanel = new JPanel();
+        JPanel bluejConflictsPanel = makeConflictsPanel(Config.getString("team.conflicts.classes"),
+                bluejConflicts);
+        JPanel nonBluejConflictsPanel = makeConflictsPanel(Config.getString("team.conflicts.classes"),
+                nonBluejConflicts);
+        JPanel buttonPanel = makeButtonPanel();
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+        mainPanel.setBorder(BlueJTheme.generalBorder);
+        mainPanel.add(bluejConflictsPanel);
+
+        if (nonBluejConflicts.size() > 0) {
+            mainPanel.add(nonBluejConflictsPanel);
+        }
+
+        mainPanel.add(buttonPanel);
+        getContentPane().add(mainPanel);
+
+        // save position when window is moved
+        addComponentListener(new ComponentAdapter() {
+                public void componentMoved(ComponentEvent event)
+                {
+                    Config.putLocation("bluej.teamwork.conflicts", getLocation());
+                }
+            });
+
+        setLocation(Config.getLocation("bluej.teamwork.conflicts"));
+        pack();
+    }
+
+    private JPanel makeConflictsPanel(String headline, List<String> conflicts)
+    {
+        JPanel labelPanel = new JPanel();
+
+        {
+            labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.Y_AXIS));
+            labelPanel.setBorder(BlueJTheme.dialogBorder);
+
+            /*labelPanel.setBorder(BorderFactory.createCompoundBorder(
+                    BorderFactory.createTitledBorder("Conflict"),
+                    BlueJTheme.generalBorder));*/
+            labelPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+            //heading
+            heading = new JLabel(headline);
+
+            Font smallFont = heading.getFont().deriveFont(Font.BOLD, 12.0f);
+            heading.setFont(smallFont);
+            labelPanel.add(heading);
+            labelPanel.add(Box.createVerticalStrut(5));
+
+            JPanel conflictsPanel = new JPanel();
+            conflictsPanel.setLayout(new BoxLayout(conflictsPanel,
+                    BoxLayout.Y_AXIS));
+            conflictsPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+            //the conflicting files labels
+            for (Iterator<String> i = conflicts.iterator(); i.hasNext();) {
+                String conflict = i.next();
+                conflictsPanel.add(new JLabel(conflict));
+            }
+
+            JScrollPane scrollPane = new JScrollPane(conflictsPanel);
+            labelPanel.add(scrollPane);
+        }
+
+        return labelPanel;
+    }
+
+    /**
+     * Create the button panel with a Resolve button and a close button
+     * @return JPanel the buttonPanel
+     */
+    private JPanel makeButtonPanel()
+    {
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+
+        {
+            buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+            //close button
+            JButton closeButton = new JButton(Config.getString("close"));
+            closeButton.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent evt)
+                    {
+                        setVisible(false);
+                    }
+                });
+
+            //resolve button
+            JButton resolveButton = new JButton(Config.getString("team.conflicts.show"));
+            resolveButton.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent evt)
+                    {
+                        project.openEditorsForSelectedTargets();
+
+                        // move to resolve button
+                        dispose();
+                    }
+                });
+
+            getRootPane().setDefaultButton(resolveButton);
+
+            buttonPanel.add(resolveButton);
+            buttonPanel.add(closeButton);
+            resolveButton.setEnabled(bluejConflicts.size() > 0);
+        }
+
+        return buttonPanel;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/FileRenderer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/FileRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..b74303e22ac78eeb1428987aebd3efadafa7efe0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/FileRenderer.java
@@ -0,0 +1,54 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import bluej.pkgmgr.Project;
+import java.awt.Component;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JLabel;
+import javax.swing.JList;
+
+/**
+ * Class to display files to be committed in a list for the CommitCommentsFrame
+ * or UpdateFilesFrame
+ * 
+ * @author Bruce Quig
+ * @author Davin McCall
+ * @version $Id: FileRenderer.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class FileRenderer extends DefaultListCellRenderer
+{
+    private Project project;
+    
+    public FileRenderer(Project proj)
+    {
+        project = proj;
+    }
+        
+    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
+    {
+        String status = ResourceDescriptor.getResource(project, value, true);       
+        JLabel label = new JLabel(status);
+        return label;
+    }
+   
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/HistoryFrame.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/HistoryFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..48a838905c933915c2729a55d57d4dd9276920e0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/HistoryFrame.java
@@ -0,0 +1,416 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.*;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import javax.swing.*;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.groupwork.*;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.utility.DBox;
+import bluej.utility.DBoxLayout;
+import bluej.utility.EscapeDialog;
+import bluej.utility.SwingWorker;
+
+/**
+ * A frame to display the commit history, including dates, users, revisions
+ * and commit comments.
+ * 
+ * @author Davin McCall
+ */
+public class HistoryFrame extends EscapeDialog
+{
+    Project project;
+    ActivityIndicator activityBar;
+    HistoryWorker worker;
+    
+    HistoryListModel listModel = new HistoryListModel();
+    HistoryListRenderer renderer = new HistoryListRenderer(listModel);
+    JList historyList;
+    JScrollPane historyPane;
+    List<HistoryInfo> historyInfoList;
+    
+    JComboBox fileFilterCombo;
+    JComboBox userFilterCombo;
+    ActionListener filterActionListener;
+    JLabel filterSpacer;
+    
+    /**
+     * Create a new HistoryFrame.
+     */
+    public HistoryFrame(PkgMgrFrame pmf)
+    {
+        super((Frame) null, Config.getString("team.history.title"));
+        project = pmf.getProject();
+        buildUI();
+        pack();
+    }
+    
+    /**
+     * Construct the UI components.
+     */
+    private void buildUI()
+    {
+        // Content pane
+        JPanel contentPane = new JPanel();
+        DBoxLayout layout = new DBoxLayout(DBoxLayout.Y_AXIS, 0,
+                BlueJTheme.generalSpacingWidth);
+        contentPane.setLayout(layout); 
+        contentPane.setBorder(BlueJTheme.dialogBorder);
+        setContentPane(contentPane);
+
+        // History list
+        historyList = new JList(listModel) {
+            public Dimension getPreferredScrollableViewportSize()
+            {
+                return getPreferredSize();
+            }
+        };
+        historyList.setCellRenderer(renderer);
+        historyPane = new JScrollPane(historyList);
+        historyPane.setAlignmentX(0f);
+        historyPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+        contentPane.add(historyPane);
+        
+        // Find a suitable size for the history list
+        List<HistoryInfo> tempList = new ArrayList<HistoryInfo>(5);
+        HistoryInfo tempInfo = new HistoryInfo(new String[] {"somepath/abcdefg.java"}, "1.1", "2006/11/34 12:34:56", "abraham", "this is the expected comment length of comments");
+        for (int i = 0; i < 8; i++) {
+            tempList.add(tempInfo);
+        }
+        listModel.setListData(tempList);
+        Dimension size = historyList.getPreferredSize();
+        listModel.setListData(Collections.<HistoryInfo>emptyList());
+        historyList.setPreferredSize(size);
+        
+        contentPane.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        
+        // File and user filter boxes
+        DBox filterBox = new DBox(DBox.X_AXIS, 0, BlueJTheme.componentSpacingLarge, 0.5f);
+        filterBox.setAxisBounded(DBox.Y_AXIS, true);
+        filterBox.add(new JLabel(Config.getString("team.history.filefilter") + " "));
+        fileFilterCombo = new JComboBox();
+        fileFilterCombo.setEnabled(false);
+        filterBox.add(fileFilterCombo);
+        // filterBox.add(Box.createHorizontalStrut(BlueJTheme.componentSpacingLarge));
+        filterBox.add(new JLabel(Config.getString("team.history.userfilter") + " "));
+        userFilterCombo = new JComboBox();
+        userFilterCombo.setEnabled(false);
+        filterBox.add(userFilterCombo);
+        // Add in a spacer, which helps ensure the initial size of the frame is ok.
+        // When the filter combo boxes are filled, the spacer is removed.
+        filterSpacer = new JLabel("                              ");
+        userFilterCombo.addItem("         ");
+        fileFilterCombo.addItem("               ");
+        filterBox.add(filterSpacer);
+        filterBox.setAlignmentX(0f);
+        contentPane.add(filterBox);
+        filterActionListener = new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                refilter();
+            };
+        };
+        
+        contentPane.add(Box.createVerticalStrut(BlueJTheme.dialogCommandButtonsVertical - BlueJTheme.generalSpacingWidth));
+        
+        // Activity indicator and close button
+        Box buttonBox = new Box(BoxLayout.X_AXIS);
+        activityBar = new ActivityIndicator();
+        buttonBox.add(activityBar);
+        buttonBox.add(Box.createHorizontalGlue());
+        JButton closeButton = new JButton(Config.getString("close"));
+        closeButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                if (worker != null) {
+                    worker.cancel();
+                }
+                dispose();
+            }
+        });
+        buttonBox.add(closeButton);
+        buttonBox.setAlignmentX(0f);
+        contentPane.add(buttonBox);
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.Component#setVisible(boolean)
+     */
+    public void setVisible(boolean vis)
+    {
+        super.setVisible(vis);
+        
+        if (vis) {
+            Repository repository = project.getRepository();
+            
+            if (repository != null) {
+                worker = new HistoryWorker(repository);
+                worker.start();
+                activityBar.setRunning(true);
+            }
+        }
+        else {
+            if (worker != null) {
+                worker.cancel();
+            }
+        }
+    }
+    
+    /**
+     * Filter the history info list according to the selected file and user
+     * filters. The filtered list is then displayed.
+     */
+    private void refilter()
+    {
+        String user = null;
+        int userIndex = userFilterCombo.getSelectedIndex();
+        if (userIndex != 0) {
+            user = (String) userFilterCombo.getItemAt(userIndex);
+        }
+        
+        String file = null;
+        int fileIndex = fileFilterCombo.getSelectedIndex();
+        if (fileIndex != 0) {
+            file = (String) fileFilterCombo.getItemAt(fileIndex);
+        }
+        
+        List<HistoryInfo> displayList;
+        if (user == null && file == null) {
+            displayList = historyInfoList;
+        }
+        else {
+            displayList = new ArrayList<HistoryInfo>();
+            for (Iterator<HistoryInfo> i = historyInfoList.iterator(); i.hasNext(); ) {
+                HistoryInfo info = (HistoryInfo) i.next();
+                if (user != null && ! info.getUser().equals(user)) {
+                    continue;
+                }
+                if (file != null && ! hinfoHasFile(info, file)) {
+                    continue;
+                }
+                
+                displayList.add(info);
+            }
+        }
+        
+        listModel.setListData(displayList);
+    }
+    
+    /**
+     * Check whether a history item pertains at all to a particular file
+     */
+    private boolean hinfoHasFile(HistoryInfo info, String file)
+    {
+        String [] files = info.getFiles();
+        for (int i = 0; i < files.length; i++) {
+            if (files[i].equals(file)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Reset the filter boxes (user filter and file filter), adding a complete list
+     * of all users and files.
+     */
+    private void resetFilterBoxes()
+    {
+        Set<String> users = new HashSet<String>();
+        Set<String> files = new HashSet<String>();
+        
+        for (Iterator<HistoryInfo> i = historyInfoList.iterator(); i.hasNext(); ) {
+            HistoryInfo info = i.next();
+            String [] infoFiles = info.getFiles();
+            for (int j = 0; j < infoFiles.length; j++) {
+                files.add(infoFiles[j]);
+            }
+            users.add(info.getUser());
+        }
+        
+        List<String> usersList = new ArrayList<String>(users);
+        Collections.sort(usersList);
+        List<String> filesList = new ArrayList<String>(files);
+        Collections.sort(filesList);
+        
+        userFilterCombo.removeAllItems();
+        userFilterCombo.addItem(Config.getString("team.history.allUsers"));
+        Iterator<String> i = usersList.iterator();
+        while (i.hasNext()) {
+            userFilterCombo.addItem(i.next());
+        }
+        userFilterCombo.addActionListener(filterActionListener);
+        userFilterCombo.setEnabled(true);
+        
+        fileFilterCombo.removeAllItems();
+        fileFilterCombo.addItem(Config.getString("team.history.allFiles"));
+        i = filesList.iterator();
+        while (i.hasNext()) {
+            fileFilterCombo.addItem(i.next());
+        }
+        fileFilterCombo.addActionListener(filterActionListener);
+        fileFilterCombo.setEnabled(true);
+        
+        filterSpacer.setVisible(false);
+    }
+    
+    /**
+     * A worker class to fetch the required information from the repository
+     * in the background.
+     */
+    private class HistoryWorker extends SwingWorker implements LogHistoryListener
+    {
+        private List<HistoryInfo> responseList;
+        private Repository repository;
+        private TeamworkCommand command;
+        private TeamworkCommandResult response;
+        
+        public HistoryWorker(Repository repository)
+        {
+            this.responseList = new ArrayList<HistoryInfo>();
+            
+            command = repository.getLogHistory(this);
+            this.repository = repository;
+        }
+        
+        public Object construct()
+        {
+            response = command.getResult();
+            return response;
+        }
+        
+        public void logInfoAvailable(HistoryInfo hInfo)
+        {
+            responseList.add(hInfo);
+        }
+        
+        public void finished()
+        {
+            if (command != null) {
+                activityBar.setRunning(false);
+                command = null; // marks the command as finished
+                if (response.isError()) {
+                    TeamUtils.handleServerResponse(response, HistoryFrame.this);
+                    setVisible(false);
+                }
+                else {
+                    
+                    Collections.sort(responseList, new DateCompare());
+                    
+                    // Make the history list forget the preferred size that was forced
+                    // upon it when we built the frame.
+                    historyList.setPreferredSize(null);
+                    
+                    renderer.setWrapMode(historyPane);
+                    listModel.setListData(responseList);
+                    historyInfoList = responseList;
+                    
+                    resetFilterBoxes();
+                }
+            }
+        }
+        
+        public void cancel()
+        {
+            if (command != null) {
+                activityBar.setRunning(false);
+                command.cancel();
+                command = null;
+            }
+        }
+    }
+}
+
+/**
+ * A comparator to sort HistoryInfo objects by date.
+ * 
+ * @author Davin McCall
+ */
+class DateCompare implements Comparator<HistoryInfo>
+{
+    @Override
+  public Comparator<HistoryInfo> reversed() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Comparator<HistoryInfo> thenComparing(
+      Comparator<? super HistoryInfo> other) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public <U> Comparator<HistoryInfo> thenComparing(
+      Function<? super HistoryInfo, ? extends U> keyExtractor,
+      Comparator<? super U> keyComparator) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public <U extends Comparable<? super U>> Comparator<HistoryInfo> thenComparing(
+      Function<? super HistoryInfo, ? extends U> keyExtractor) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Comparator<HistoryInfo> thenComparingInt(
+      ToIntFunction<? super HistoryInfo> keyExtractor) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Comparator<HistoryInfo> thenComparingLong(
+      ToLongFunction<? super HistoryInfo> keyExtractor) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Comparator<HistoryInfo> thenComparingDouble(
+      ToDoubleFunction<? super HistoryInfo> keyExtractor) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+    public int compare(HistoryInfo hi0, HistoryInfo hi1)
+    {
+        return hi1.getDate().compareTo(hi0.getDate());
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/HistoryListModel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/HistoryListModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6dd7747ab92534fef4704e49a88e1591961ceda
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/HistoryListModel.java
@@ -0,0 +1,110 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.AbstractListModel;
+
+import bluej.groupwork.HistoryInfo;
+
+/**
+ * A list model for the history list.
+ * 
+ * Because the cells change height depending on their width, we track
+ * the heights here and fire a cell changed event if the height changes.
+ * It's the responsibility of the cell renderer to let us know when
+ * the height changes.
+ * 
+ * @author Davin McCall
+ */
+public class HistoryListModel extends AbstractListModel
+{
+    private List<HistoryInfo> listData;
+    private int [] cellHeights;
+    
+    public HistoryListModel()
+    {
+        super();
+        listData = Collections.emptyList();
+    }
+    
+    /**
+     * Set the data to be displayed in the list. 
+     * 
+     * @param newData A list of HistoryInfo objects.
+     */
+    public void setListData(List<HistoryInfo> newData)
+    {
+        int endIndex = listData.size() - 1;
+        if (endIndex >= 0) {
+            fireIntervalRemoved(this, 0, endIndex);
+        }
+        
+        cellHeights = new int[newData.size()];
+        for (int i = 0; i < cellHeights.length; i++) {
+            cellHeights[i] = -1;
+        }
+        
+        listData = newData;
+        endIndex = listData.size() - 1;
+        if (endIndex >= 0) {
+            fireIntervalAdded(this, 0, endIndex);
+        }
+    }
+    
+    /**
+     * Specify the cell height at a certain index. If the cell height
+     * has changed, the list will be notified.
+     * 
+     * @param index   The index of the cell
+     * @param height  The height of the specified cell
+     */
+    public void setCellHeight(final int index, int height)
+    {
+        int oldHeight = cellHeights[index];
+        cellHeights[index] = height;
+        if (oldHeight != -1 && oldHeight != height) {
+            fireContentsChanged(this, index, index);
+        }
+    }
+    
+    /**
+     * All the renderer to flag that a cell needs to change size.
+     * @param index  The cell index
+     */
+    public void changeChell(int index)
+    {
+        fireContentsChanged(this, index, index);
+    }
+    
+    public Object getElementAt(int index)
+    {
+        return listData.get(index);
+    }
+    
+    public int getSize()
+    {
+        return listData.size();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/HistoryListRenderer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/HistoryListRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..b8b8d21aff74295645baacd196f8b81d1d16287b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/HistoryListRenderer.java
@@ -0,0 +1,208 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.Insets;
+import java.awt.Rectangle;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.LineBorder;
+
+import bluej.groupwork.HistoryInfo;
+import bluej.utility.DBox;
+import bluej.utility.MultiWrapLabel;
+
+/**
+ * Renderer for cells in the log/history list.
+ * 
+ * <p>This is a little complicated because the renderer wraps text at the width
+ * of the list. This means that the preferred height of a cell is dependent on the
+ * width.
+ * 
+ * @author Davin McCall
+ */
+public class HistoryListRenderer extends DBox implements ListCellRenderer
+{
+    private HistoryListModel model;
+    
+    private JLabel topLabel;
+    private MultiWrapLabel commentArea;
+    private JLabel spacerLabel;
+    private JTextArea filesArea;
+    
+    private JScrollPane container;
+    
+    private int index;
+    
+    private Box filesBox;
+    private Box commentBox;
+    
+    /**
+     * Create a new list renderer.
+     */
+    public HistoryListRenderer(HistoryListModel model)
+    {
+        //super(BoxLayout.Y_AXIS);
+        super(DBox.Y_AXIS, 0f);
+        
+        this.model = model;
+        
+        topLabel = new JLabel();
+        Font font = topLabel.getFont();
+        topLabel.setAlignmentX(0f);
+        topLabel.setFont(font.deriveFont(Font.BOLD));
+        add(topLabel);
+        
+        filesBox = new Box(BoxLayout.X_AXIS);
+        JLabel spaceLabel = new JLabel("    ");
+        filesBox.add(spaceLabel);
+        filesArea = new JTextArea();
+        filesArea.setAlignmentX(0f);
+        filesArea.setFont(font.deriveFont(0));
+        filesBox.add(filesArea);
+        filesBox.setAlignmentX(0f);
+        add(filesBox);
+        
+        commentBox = new Box(BoxLayout.X_AXIS);
+        spacerLabel = new JLabel("        ");
+        commentBox.add(spacerLabel);
+        commentArea = new MultiWrapLabel();
+        commentArea.setAlignmentX(0f);
+        //commentArea.setFont(font.deriveFont(font.getSize2D() * 0.9f).deriveFont(0));
+        commentArea.setFont(font.deriveFont(0));
+        commentBox.add(commentArea);
+        commentBox.setAlignmentX(0f);
+        add(commentBox);
+    }
+    
+    /**
+     * Set the containing scroll pane. This is needed to be able to wrap
+     * comment text correctly according to the width of the scroll pane.
+     */
+    public void setWrapMode(JScrollPane container)
+    {
+        this.container = container;
+    }
+    
+    /* (non-Javadoc)
+     * @see javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean)
+     */
+    public Component getListCellRendererComponent(
+      JList list,
+      Object value,            // value to display
+      int index,               // cell index
+      boolean isSelected,      // is the cell selected
+      boolean cellHasFocus)    // the list and the cell have the focus
+    {
+        HistoryInfo info = (HistoryInfo) value;
+        String topText = info.getDate() + "  "  + info.getRevision() + "  " + info.getUser();
+        String [] files = info.getFiles();
+        String filesText = files[0];
+        for (int i = 1; i < files.length; i++) {
+            filesText += "\n" + files[i];
+        }
+        filesArea.setText(filesText);
+        filesArea.invalidate();
+        filesBox.invalidate();
+        topLabel.setText(topText);
+        
+        String commentText = info.getComment();
+        // commentArea.setText("");
+        //commentArea.setLineWrap(false);
+        //commentArea.setLineWrap(true);
+        commentArea.setText(commentText);
+        commentBox.invalidate();
+
+        if (isSelected) {
+            setBackground(list.getSelectionBackground());
+            setForeground(list.getSelectionForeground());
+            filesArea.setForeground(list.getSelectionForeground());
+            filesArea.setBackground(list.getSelectionBackground());
+            setOpaque(true);
+        }
+        else {
+            setBackground(list.getBackground());
+            setForeground(list.getForeground());
+            filesArea.setForeground(list.getForeground());
+            filesArea.setBackground(list.getBackground());
+            setOpaque(false);
+        }
+        
+        if (cellHasFocus) {
+            setBorder(new LineBorder(list.getSelectionForeground(), 1));
+        }
+        else {
+            setBorder(new EmptyBorder(1,1,1,1));
+        }
+        
+        setEnabled(list.isEnabled());
+        setFont(list.getFont());
+        
+        if (container != null) {
+            Rectangle bbounds = container.getViewportBorderBounds();
+            int listWidth = bbounds.width;
+            Insets containerInsets = container.getViewport().getInsets();
+            listWidth -= containerInsets.left + containerInsets.right;
+            listWidth -= spacerLabel.getPreferredSize().width;
+            listWidth -= getInsets().left + getInsets().right;
+            
+            commentArea.setWrapWidth(listWidth);
+            commentArea.invalidate();
+        }
+
+        // We need to validate to ensure that we have the correct preferred
+        // size.
+        invalidate();
+        validate();
+        
+        // Inform the model of our desired height. If this has changed, the model
+        // fires a "cell changed" event so that the list will detect the change.
+        model.setCellHeight(index, this.getPreferredSize().height);
+        this.index = index;
+        
+        // Once we return, the list should ask what our preferred size is; it
+        // will then call setBounds to set a size.
+        return this;
+    }
+    
+    public void setBounds(int x, int y, int width, int height)
+    {
+        super.setBounds(x, y, width, height);
+        
+        // Ok, the list has assigned us a size. However, the horizontal size
+        // we told the list we needed may now be incorrect, which can cause
+        // a horizontal scrollbar to needlessly appear.
+                
+        validate();
+        if (getPreferredSize().getWidth() < width) {
+            model.changeChell(index);
+        }
+    }
+    
+    public boolean isValidateRoot()
+    {
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ModuleSelectDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ModuleSelectDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..76d159c202f6f2eb5cc765e93b22e8ece1743a32
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ModuleSelectDialog.java
@@ -0,0 +1,292 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.Container;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.groupwork.Repository;
+import bluej.groupwork.TeamUtils;
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.utility.EscapeDialog;
+import bluej.utility.SwingWorker;
+
+/**
+ * A dialog for selecting a module to checkout.
+ * 
+ * @author Davin McCall
+ */
+public class ModuleSelectDialog extends EscapeDialog implements ListSelectionListener
+{
+    private Repository repository;
+    
+    private ActivityIndicator progressBar;
+    private JTextField moduleField;
+    private JButton okButton;
+    private JList moduleList;
+    private ModuleListerThread worker;
+    
+    private boolean wasOk;
+    
+    public ModuleSelectDialog(Frame owner, Repository repository)
+    {
+        super(owner, Config.getString("team.moduleselect.title"), true);
+        this.repository = repository;
+        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+        buildUI();
+        pack();
+    }
+    
+    /**
+     * Get the selected module name, or null if no module was selected
+     * (dialog was cancelled).
+     */
+    public String getModuleName()
+    {
+        if (wasOk) {
+            return moduleField.getText();
+        }
+        else {
+            return null;
+        }
+    }
+    
+    /**
+     * Start the progress bar. Safe to call from any thread.
+     */
+    private void startProgressBar()
+    {
+        progressBar.setRunning(true);
+    }
+    
+    /**
+     * Stop the progress bar. Safe to call from any thread.
+     */
+    private void stopProgressBar()
+    {
+        progressBar.setRunning(false);
+    }
+    
+    private void setModuleList(List<String> modules)
+    {
+        Object [] listData = modules.toArray();
+        moduleList.setListData(listData);
+    }
+    
+    private void buildUI()
+    {
+        // Content pane
+        JPanel contentPane = new JPanel();
+        BoxLayout layout = new BoxLayout(contentPane, BoxLayout.Y_AXIS);
+        contentPane.setLayout(layout);    
+        contentPane.setBorder(BlueJTheme.dialogBorder);
+        setContentPane(contentPane);
+        
+        // Module text field
+        Box moduleBox = new Box(BoxLayout.X_AXIS);
+        moduleBox.add(new JLabel(Config.getString("team.moduleselect.label")));
+        moduleBox.add(Box.createHorizontalStrut(BlueJTheme.generalSpacingWidth));
+        moduleField = new JTextField(20);
+        moduleField.getDocument().addDocumentListener(new DocumentListener() {
+            public void changedUpdate(DocumentEvent e)
+            {
+                resetOk();
+            }
+            
+            public void insertUpdate(DocumentEvent e)
+            {
+                resetOk();
+            }
+            
+            public void removeUpdate(DocumentEvent e)
+            {
+                resetOk();
+            }
+            
+            public void resetOk()
+            {
+                okButton.setEnabled(moduleField.getText().length() != 0);
+            }
+        });
+        moduleBox.add(moduleField);
+        addXAligned(contentPane, moduleBox, 0.0f);
+        contentPane.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        
+        addXAligned(contentPane, new JSeparator(), 0.0f);
+        contentPane.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+
+        // Modules list
+        addXAligned(contentPane, new JLabel(Config.getString("team.moduleselect.available")), 0f);
+        
+        Box moduleListBox = new Box(BoxLayout.X_AXIS);
+        moduleList = new JList();
+        moduleList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        moduleList.getSelectionModel().addListSelectionListener(this);
+        moduleList.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent e)
+            {
+                if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
+                    int index = moduleList.locationToIndex(e.getPoint());
+                    if (index != -1) {
+                        wasOk = true;
+                        dispose();
+                    }
+                }
+            }
+        });
+        moduleList.setAlignmentY(0f);
+        JScrollPane moduleListSP = new JScrollPane(moduleList);
+        moduleListSP.setAlignmentY(0f);
+        moduleListBox.add(moduleListSP);
+        moduleListBox.add(Box.createHorizontalStrut(BlueJTheme.generalSpacingWidth));
+        final JButton listButton = new JButton(Config.getString("team.moduleselect.show"));
+        listButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                listButton.setEnabled(false);
+                startProgressBar();
+                worker = new ModuleListerThread();
+                worker.start();
+            }
+        });
+        listButton.setAlignmentY(0f);
+        moduleListBox.add(listButton);
+        
+        addXAligned(contentPane, moduleListBox, 0f);
+
+        contentPane.add(Box.createVerticalStrut(BlueJTheme.dialogCommandButtonsVertical));
+        
+        // Button box
+        Box buttonBox = new Box(BoxLayout.X_AXIS);
+        progressBar = new ActivityIndicator();
+        buttonBox.add(progressBar);
+        buttonBox.add(Box.createHorizontalGlue());
+        addXAligned(contentPane, buttonBox, 0.0f);
+        
+        // Ok button
+        buttonBox.add(Box.createHorizontalStrut(BlueJTheme.generalSpacingWidth));
+        okButton = BlueJTheme.getOkButton();
+        getRootPane().setDefaultButton(okButton);
+        okButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                wasOk = true;
+                dispose();
+            }
+        });
+        okButton.setEnabled(false);
+        buttonBox.add(okButton);
+        
+        // Cancel button
+        buttonBox.add(Box.createHorizontalStrut(BlueJTheme.generalSpacingWidth));
+        JButton cancelButton = BlueJTheme.getCancelButton();
+        cancelButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                if (worker != null) {
+                    worker.cancel();
+                }
+                dispose();
+            }
+        });
+        buttonBox.add(cancelButton);
+    }
+    
+    private void addXAligned(Container parent, JComponent child, float alignment)
+    {
+        child.setAlignmentX(alignment);
+        parent.add(child);
+    }
+    
+    // ---- ListSelectionListener interface ----
+    
+    public void valueChanged(ListSelectionEvent e)
+    {
+        if (! e.getValueIsAdjusting()) {
+            int selected = moduleList.getSelectedIndex();
+            if (selected != -1) {
+                String module = moduleList.getModel().getElementAt(selected).toString();
+                moduleField.setText(module);
+            }
+        }
+    }
+    
+    /**
+     * A thread to find the available modules in the background.
+     * 
+     * @author Davin McCall
+     */
+    private class ModuleListerThread extends SwingWorker
+    {
+        private TeamworkCommand command;
+        private TeamworkCommandResult result;
+        private List<String> modules;
+        
+        public ModuleListerThread()
+        {
+            modules = new ArrayList<String>();
+            command = repository.getModules(modules);
+        }
+        
+        public Object construct()
+        {
+            result = command.getResult();
+            return result;
+        }
+        
+        public void finished()
+        {
+            stopProgressBar();
+            if (command != null) {
+                if (result != null && ! result.isError()) {
+                    setModuleList(modules);
+                }
+                else {
+                    TeamUtils.handleServerResponse(result, ModuleSelectDialog.this);
+                }
+            }
+        }
+        
+        public void cancel()
+        {
+            if (command != null) {
+                command.cancel();
+                command = null;
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ResourceDescriptor.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ResourceDescriptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..d77269019bed777daf0acd4c85cc7f9e4108a950
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/ResourceDescriptor.java
@@ -0,0 +1,74 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import bluej.Config;
+import bluej.groupwork.TeamStatusInfo;
+import bluej.pkgmgr.BlueJPackageFile;
+import bluej.pkgmgr.Project;
+
+/**
+ * Class to determine team resource descriptions for use in dialogs
+ * 
+ * @author Bruce Quig
+ * @version $Id: ResourceDescriptor.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class ResourceDescriptor
+{
+           
+    public static String getResource(Project project, Object value, boolean annotate)
+    {
+        String status = value.toString();
+        if(value instanceof TeamStatusInfo) {
+            TeamStatusInfo info = (TeamStatusInfo)value;
+            boolean isPkgFile = BlueJPackageFile.isPackageFileName(info.getFile().getName());
+
+            if (isPkgFile) {
+                  status = Config.getString("team.commit.layout") + " " + project.getPackageForFile(info.getFile());
+            }
+            if(annotate) {
+                // file has been deleted
+                if(info.getStatus() == TeamStatusInfo.STATUS_DELETED) {
+                    status += " (" + Config.getString("team.status.delete") + ")";
+                }
+                else if (info.getStatus() == TeamStatusInfo.STATUS_NEEDSADD) {
+                    status += " (" + Config.getString("team.status.add") + ")";
+                }
+                else if (info.getStatus() == TeamStatusInfo.STATUS_NEEDSCHECKOUT) {
+                    status += " (" + Config.getString("team.status.new") + ")";
+                }
+                else if (info.getStatus() == TeamStatusInfo.STATUS_REMOVED
+                        || info.getStatus() == TeamStatusInfo.STATUS_CONFLICT_LMRD) {
+                    status += " (" + Config.getString("team.status.removed") + ")";
+                }
+                else if (info.getStatus() == TeamStatusInfo.STATUS_NEEDSMERGE) {
+                    if (! isPkgFile) {
+                        status += " (" + Config.getString("team.status.needsmerge") + ")";
+                    }
+                }
+            }
+        }
+        
+        return status;
+    }
+   
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/StatusFrame.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/StatusFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..20bbc0d76c40b9c290148276ab047560f0e961e0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/StatusFrame.java
@@ -0,0 +1,338 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.groupwork.Repository;
+import bluej.groupwork.StatusHandle;
+import bluej.groupwork.StatusListener;
+import bluej.groupwork.TeamStatusInfo;
+import bluej.groupwork.TeamUtils;
+import bluej.groupwork.TeamViewFilter;
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.pkgmgr.Project;
+import bluej.utility.EscapeDialog;
+import bluej.utility.SwingWorker;
+
+/**
+ * Main frame for CVS Status Dialog
+ *
+ * @author bquig
+ */
+public class StatusFrame extends EscapeDialog
+{
+    private Project project;
+    private JTable statusTable;
+    private StatusTableModel statusModel;
+    private JScrollPane statusScroller;
+    private JButton refreshButton;
+    private ActivityIndicator progressBar;
+    private StatusMessageCellRenderer statusRenderer;
+    
+    private StatusWorker worker;
+    
+    private Repository repository;
+    
+    private static final int MAX_ENTRIES = 20; 
+    
+    /** 
+     * Creates a new instance of StatusFrame. Called via factory method
+     * getStatusWindow. 
+     */
+    public StatusFrame(Project proj)
+    {
+        project = proj;
+        makeWindow();
+        //DialogManager.tileWindow(this, proj);
+    }
+
+    private void makeWindow()
+    {              
+        setTitle(Config.getString("team.status.status"));
+        // try and set up a reasonable default amount of entries that avoids resizing
+        // and scrolling once we get info back from repository
+        statusModel = new StatusTableModel(project, estimateInitialEntries());
+        statusTable = new JTable(statusModel);
+        statusTable.getTableHeader().setReorderingAllowed(false);
+        
+        // set relative column widths
+        statusTable.getColumnModel().getColumn(0).setPreferredWidth(80);
+        statusTable.getColumnModel().getColumn(1).setPreferredWidth(30);
+        statusTable.getColumnModel().getColumn(2).setPreferredWidth(120);
+        
+        //set up custom renderer to colour code status message field
+        statusRenderer = new StatusMessageCellRenderer(project);
+        statusTable.setDefaultRenderer(java.lang.Object.class, statusRenderer);
+        
+        statusScroller = new JScrollPane(statusTable);               
+        statusScroller.setBorder(BlueJTheme.generalBorderWithStatusBar);
+        Dimension prefSize = statusTable.getMaximumSize();
+        Dimension scrollPrefSize =  statusTable.getPreferredScrollableViewportSize();
+        
+        Dimension best = new Dimension(scrollPrefSize.width + 50, prefSize.height + 30);
+        statusScroller.setPreferredSize(best);
+        getContentPane().add(statusScroller, BorderLayout.CENTER);
+        getContentPane().add(makeButtonPanel(), BorderLayout.SOUTH);
+        pack();
+    }
+    
+    /**
+     * Create the button panel with a Resolve button and a close button
+     * @return JPanel the buttonPanel
+     */
+    private JPanel makeButtonPanel()
+    {
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+
+        {
+            buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+            buttonPanel.setBorder(BlueJTheme.generalBorder);
+            
+            // progress bar
+            progressBar = new ActivityIndicator();
+            progressBar.setRunning(false);
+            buttonPanel.add(progressBar);
+            
+            //close button
+            JButton closeButton = BlueJTheme.getCloseButton();
+            closeButton.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent evt)
+                    {
+                        if (worker != null) {
+                            worker.abort();
+                        }
+                        setVisible(false);
+                    }
+                });
+
+            //refresh button
+            refreshButton = new JButton(Config.getString("team.status.refresh"));
+            refreshButton.setEnabled(false);
+            refreshButton.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent evt)
+                    {
+                        update();
+                    }
+                });
+
+            getRootPane().setDefaultButton(refreshButton);
+
+            buttonPanel.add(refreshButton);
+            buttonPanel.add(closeButton);
+        }
+
+        return buttonPanel;
+    }
+    
+    /**
+     * try and estimate the number of entries in status table to avoid resizing
+     * once repository has responded.
+     */
+    private int estimateInitialEntries()
+    {
+        // Use number of targets + README.TXT
+        int initialEntries = project.getFilesInProject(true, false).size() + 1;
+        // may need to include diagram layout
+        //if(project.includeLayout())
+        //    initialEntries++;
+        // Limit to a reasonable maximum
+        if(initialEntries > MAX_ENTRIES) {
+            initialEntries = MAX_ENTRIES;
+        }
+        return initialEntries;
+    }
+
+    /**
+     * Refresh the status window.
+     */
+    public void update()
+    {
+        repository = project.getRepository();
+        if (repository != null) {
+            progressBar.setRunning(true);
+            refreshButton.setEnabled(false);
+            worker = new StatusWorker();
+            worker.start();
+        }
+        else {
+            setVisible(false);
+        }
+    }
+    
+    /**
+     * Inner class to do the actual cvs status call to ensure that the UI is not 
+     * blocked during remote call
+     */
+    class StatusWorker extends SwingWorker implements StatusListener
+    {
+        List<TeamStatusInfo> resources;
+        TeamworkCommand command;
+        TeamworkCommandResult result;
+        boolean aborted;
+        FileFilter filter = project.getTeamSettingsController().getFileFilter(true);
+
+        public StatusWorker()
+        {
+            super();
+            resources = new ArrayList<TeamStatusInfo>();
+            //Set files = project.getTeamSettingsController().getProjectFiles(true);
+            command = repository.getStatus(this, filter, true);
+        }
+
+        public void abort()
+        {
+            command.cancel();
+            aborted = true;
+        }
+
+        public Object construct() 
+        {
+            result = command.getResult();
+            return resources;
+        }
+
+        public void gotStatus(TeamStatusInfo info)
+        {
+            resources.add(info);
+        }
+
+        public void statusComplete(StatusHandle commitHandle)
+        {
+            // Nothing to be done here.
+        }
+        
+        public void finished() 
+        {
+            progressBar.setRunning(false);
+            if (! aborted) {
+                if (result.isError()) {
+                    TeamUtils.handleServerResponse(result, StatusFrame.this);
+                    setVisible(false);
+                }
+                else {
+                    Collections.sort(resources, new Comparator<TeamStatusInfo>() {
+                        @Override
+                      public Comparator<TeamStatusInfo> reversed() {
+                        // TODO Auto-generated method stub
+                        return null;
+                      }
+
+                      @Override
+                      public Comparator<TeamStatusInfo> thenComparing(
+                          Comparator<? super TeamStatusInfo> other) {
+                        // TODO Auto-generated method stub
+                        return null;
+                      }
+
+                      @Override
+                      public <U> Comparator<TeamStatusInfo> thenComparing(
+                          Function<? super TeamStatusInfo, ? extends U> keyExtractor,
+                          Comparator<? super U> keyComparator) {
+                        // TODO Auto-generated method stub
+                        return null;
+                      }
+
+                      @Override
+                      public <U extends Comparable<? super U>> Comparator<TeamStatusInfo> thenComparing(
+                          Function<? super TeamStatusInfo, ? extends U> keyExtractor) {
+                        // TODO Auto-generated method stub
+                        return null;
+                      }
+
+                      @Override
+                      public Comparator<TeamStatusInfo> thenComparingInt(
+                          ToIntFunction<? super TeamStatusInfo> keyExtractor) {
+                        // TODO Auto-generated method stub
+                        return null;
+                      }
+
+                      @Override
+                      public Comparator<TeamStatusInfo> thenComparingLong(
+                          ToLongFunction<? super TeamStatusInfo> keyExtractor) {
+                        // TODO Auto-generated method stub
+                        return null;
+                      }
+
+                      @Override
+                      public Comparator<TeamStatusInfo> thenComparingDouble(
+                          ToDoubleFunction<? super TeamStatusInfo> keyExtractor) {
+                        // TODO Auto-generated method stub
+                        return null;
+                      }
+
+                        public int compare(TeamStatusInfo arg0, TeamStatusInfo arg1)
+                        {
+                            TeamStatusInfo tsi0 = (TeamStatusInfo) arg0;
+                            TeamStatusInfo tsi1 = (TeamStatusInfo) arg1;
+
+                            return tsi1.getStatus() - tsi0.getStatus();
+                        }
+                    });
+
+                    TeamViewFilter filter = new TeamViewFilter();
+                    // Remove old package files from display
+                    for (Iterator<TeamStatusInfo> iterator = resources.iterator(); iterator.hasNext();) {
+                        TeamStatusInfo info = iterator.next();
+                        if(! filter.accept(info)) {
+                            iterator.remove();
+                        }                        
+                    }
+                    statusModel.setStatusData(resources);
+                    
+                    Map<File, String> statusMap = new HashMap<File, String>();
+                    
+                    for (TeamStatusInfo s : resources)
+                    {
+                        statusMap.put(s.getFile(), TeamStatusInfo.getStatusString(s.getStatus()));
+                    }
+                }
+                refreshButton.setEnabled(true);
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/StatusMessageCellRenderer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/StatusMessageCellRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..9605b6b4d820aea1737939c62f3d9f6c30709124
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/StatusMessageCellRenderer.java
@@ -0,0 +1,136 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+
+package bluej.groupwork.ui;
+
+import bluej.groupwork.TeamStatusInfo;
+import bluej.pkgmgr.Project;
+import java.awt.Color;
+import java.awt.Component;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableCellRenderer;
+
+/*
+ * StatusCellRenderer.java
+ * Renderer to add colour to the status message of resources inside a StatusFrame
+ * @author Bruce Quig
+ * @cvs $Id: StatusMessageCellRenderer.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class StatusMessageCellRenderer extends DefaultTableCellRenderer 
+{
+    private final static Color UPTODATE = Color.BLACK;
+    private final static Color NEEDSUPDATE = new Color(11,57,120);  // blue
+    private final static Color NEEDSCHECKOUT = NEEDSUPDATE;
+    private final static Color REMOVED = new Color(135,150,170);     // grey-blue
+    private final static Color NEEDSMERGE = new Color(137,13,19);   // red
+    private final static Color NEEDSCOMMIT = new Color(10,85,15);   // green
+    private final static Color NEEDSADD = NEEDSCOMMIT;
+    private final static Color DELETED = new Color(122,143,123);      // grey-green
+    private final static Color CONFLICT = NEEDSMERGE;   // darker red
+
+    Project project;
+    
+    public StatusMessageCellRenderer(Project project)
+    {
+        super();
+        this.project = project;
+    }
+    
+   
+    /**
+     * Over-ridden from super class. Get the status message string and appropriate colour
+     * for the status. Render using these values.
+     */
+    public Component getTableCellRendererComponent(JTable jTable, Object object,
+        boolean isSelected, boolean hasFocus , int row, int column) 
+    {
+        super.getTableCellRendererComponent(jTable, object, isSelected, hasFocus, row, column);
+        
+        int status = getStatus(jTable, row);
+        setForeground(getStatusColour(status));
+        String statusLabel = getStatusString(object, status, row, column);
+        setText(statusLabel);
+        setForeground(getStatusColour(status));
+        
+        return this;
+    }
+    
+    private int getStatus(JTable table, int row) 
+    {
+        int status = 0;
+        Object val = table.getModel().getValueAt(row, 2);
+        if(val instanceof Integer) {
+            status = ((Integer)val).intValue();
+        }
+        return status;
+    }
+    
+    /**
+     * get the String value of the statis ID
+     */
+    private String getStatusString(Object value, int statusValue, int row, int col) 
+    {
+        // TODO, change to use column names for ID
+        if(col == 0 || col == 1) {
+            return value.toString();
+        }        
+        return TeamStatusInfo.getStatusString(statusValue);
+    }
+    
+    /**
+     * get the colour for the given status ID value
+     */
+    private Color getStatusColour(int statusValue) 
+    {
+        Color color = Color.BLACK;
+        
+        if (statusValue == TeamStatusInfo.STATUS_UPTODATE) {
+            color = UPTODATE;
+        }
+        else if (statusValue == TeamStatusInfo.STATUS_NEEDSCHECKOUT) {
+            color = NEEDSCHECKOUT;
+        }
+        else if (statusValue == TeamStatusInfo.STATUS_DELETED) {
+            color = DELETED;
+        }
+        else if (statusValue == TeamStatusInfo.STATUS_NEEDSUPDATE) {
+            color = NEEDSUPDATE;
+        }
+        else if (statusValue == TeamStatusInfo.STATUS_NEEDSCOMMIT) {
+            color = NEEDSCOMMIT;
+        }
+        else if (statusValue == TeamStatusInfo.STATUS_NEEDSMERGE) {
+            color = NEEDSMERGE;
+        }
+        else if (statusValue == TeamStatusInfo.STATUS_NEEDSADD) {
+            color = NEEDSADD;
+        }
+        else if (statusValue == TeamStatusInfo.STATUS_REMOVED) {
+            color = REMOVED;
+        }
+        else {
+            color = CONFLICT;
+        }
+        
+        return color;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/StatusTableModel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/StatusTableModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1a94ee2c51e95faee1df2b13c1c687a6eade0b1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/StatusTableModel.java
@@ -0,0 +1,155 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.table.AbstractTableModel;
+
+import bluej.Config;
+import bluej.groupwork.TeamStatusInfo;
+import bluej.pkgmgr.Project;
+
+/**
+ * Given a list of StatusEntry(s) returns a table model which allows them to
+ * be edited in a JTable.
+ * 
+ * 
+ * @author Bruce Quig
+ * @cvs $Id: StatusTableModel.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class StatusTableModel extends AbstractTableModel
+{
+    static final String resourceLabel = Config.getString("team.status.resource");
+    static final String statusLabel = Config.getString("team.status.status");
+    static final String versionLabel = Config.getString("team.status.version");
+ 
+    private Project project;
+    private List<TeamStatusInfo> resources;
+    
+    /**
+     *
+     */
+    public StatusTableModel(Project project, int initialRows)
+    {
+        this.project = project;
+        resources = new ArrayList<TeamStatusInfo>();
+        for(int i = 0; i < initialRows; i++) {
+            resources.add(new TeamStatusInfo());
+        }
+    }
+    
+    /**
+     * Return the name of a particular column
+     *
+     * @param col   the column we are naming
+     * @return      a string of the columns name
+     */
+    public String getColumnName(int col)
+    {
+        if (col == 0)
+            return resourceLabel;
+         else if (col == 1)
+            return versionLabel;
+        else if (col == 2)
+            return statusLabel;
+
+        throw new IllegalArgumentException("bad column number in StatusTableModel::getColumnName()");
+    }
+
+    /**
+     * Return the number of rows in the table
+     *
+     * @return      the number of rows in the table
+     */
+    public int getRowCount()
+    {
+        return resources.size();
+    }
+    
+    /**
+     * Return the number of columns in the table
+     *
+     * @return      the number of columns in the table
+     */
+    public int getColumnCount()
+    {
+        return 3;
+    }
+    
+    /**
+     * Find the table entry at a particular row and column
+     *
+     * @param   row     the table row
+     * @param   col     the table column
+     * @return          the Object at that location in the table
+     */
+    public Object getValueAt(int row, int col)
+    {
+        TeamStatusInfo info = (TeamStatusInfo) resources.get(row);
+        
+        if (col == 0)
+            return ResourceDescriptor.getResource(project, info, false);
+        else if (col == 1)
+            return info.getLocalVersion(); 
+        else if (col == 2)
+            return new Integer(info.getStatus());
+
+        return null;
+    }
+
+    /**
+     * Indicate that nothing is editable
+     */
+    public boolean isCellEditable(int row, int col)
+    {
+        return false;
+    }
+
+    /**
+     * Set the table entry at a particular row and column (only
+     * valid for the location column)
+     *
+     * @param   value   the Object at that location in the table
+     * @param   row     the table row
+     * @param   col     the table column
+     */
+    public void setValueAt(Object value, int row, int col)
+    {
+       // do nothing here
+    }
+    
+    public void clear()
+    {
+        resources.clear();
+        fireTableDataChanged();
+    }
+    
+    public void setStatusData(List<TeamStatusInfo> statusResources)
+    {
+        resources = statusResources;
+        fireTableDataChanged();
+    }
+    
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamControlsPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamControlsPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b8069b823a139f27a3928b8cb83bbe2aadbd145
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamControlsPanel.java
@@ -0,0 +1,205 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.UIManager;
+
+import bluej.BlueJTheme;
+import bluej.groupwork.actions.UpdateDialogAction;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.Config;
+import bluej.groupwork.actions.CommitCommentAction;
+
+/**
+ * This panel shows to buttons labeled "Update from Repository" and
+ * "Commit to Repository" and a checkBox.
+ *
+ * @author fisker
+ *
+ */
+public class TeamControlsPanel extends JPanel
+{
+    
+    private JButton commitButton;
+    private JButton updateButton;
+    private PkgMgrFrame pmf;
+    private JCheckBox includeGraphLayoutCheckBox;
+    private JPanel helpPanel = null;
+    
+    private CommitCommentAction commitCommentAction;
+    private UpdateDialogAction updateAction;
+    
+    /**
+     * Create a TeamControlsPanel with a reference to the PkgMgrFrame holding the
+     * project it is to work on. If the reference to Project is null, all graphical
+     * elements are greyed out.
+     * @param project
+     */
+    public TeamControlsPanel(PkgMgrFrame pmf)
+    {
+        this.pmf = pmf;
+        updateAction = new UpdateDialogAction();
+       
+        commitCommentAction = new CommitCommentAction();
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+        JPanel codeSynchPanel = new JPanel();
+        {
+            codeSynchPanel.setLayout(new BoxLayout(codeSynchPanel, BoxLayout.Y_AXIS));
+            
+            codeSynchPanel.setBorder(BorderFactory.createCompoundBorder(
+                BorderFactory.createTitledBorder("Code Synchronization"),
+                BlueJTheme.generalBorder));
+            
+            //teamControlsPanel.setBorder(BlueJTheme.dialogBorder);
+            codeSynchPanel.setAlignmentX(CENTER_ALIGNMENT);
+            // Commit button
+            commitButton = new JButton(commitCommentAction);
+            
+            // Update button
+            updateButton = new JButton(updateAction);
+            
+            
+            // IncludeGraphLayoutCheckbox
+            includeGraphLayoutCheckBox = new JCheckBox("Include graph layout");
+            
+            //allow the Add and Delete buttons to be resized to equal width
+            commitButton.setMaximumSize(new Dimension(Integer.MAX_VALUE,
+                commitButton.getPreferredSize().height));
+            updateButton.setMaximumSize(new Dimension(Integer.MAX_VALUE,
+                updateButton.getPreferredSize().height));
+            
+            codeSynchPanel.add(commitButton);
+            codeSynchPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+            codeSynchPanel.add(updateButton);
+            codeSynchPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+            codeSynchPanel.add(includeGraphLayoutCheckBox);
+            
+            add(codeSynchPanel);
+            
+        }
+        doGreyOut(pmf.getProject() == null);
+        configureHelp();
+    }
+    
+    
+    public void doGreyOut(boolean greyout)
+    {
+        updateAction.setEnabled(!greyout);
+        commitCommentAction.setEnabled(!greyout);
+        includeGraphLayoutCheckBox.setEnabled(!greyout);
+    }
+    
+    public boolean includeGraphLayout()
+    {
+        return includeGraphLayoutCheckBox.isSelected();
+    }
+    
+    /**
+     *
+     */
+    public void configureHelp()
+    {
+        if (pmf.getProject() == null)
+        {
+            setHelp("To get a project from the repository, open the Team menu" +
+                "and select Checkout Project...");
+            doGreyOut(true);
+            return;
+        }
+        
+        //The project is not a team project. Show help and greyout
+        if (!pmf.getProject().isTeamProject())
+        {
+            setHelp("This project is not a team project." + Config.nl +
+                "To share this project, open the Team menu and select " +
+                "Share Project..." + Config.nl +
+                "To get a project from the repository, open the Team menu " +
+                "and select Checkout Project...");
+            doGreyOut(true);
+        }
+        
+        //everything is good. Show no help and show all buttons
+        if (pmf.getProject().isTeamProject())
+        {
+            if (helpPanel != null)
+            {
+                remove(helpPanel);
+            }
+            doGreyOut(false);
+        }
+        
+    }
+    
+    private void setHelp(String helpStr)
+    {
+        JPanel p = makeHelpPanel(helpStr);
+        setHelpPanel(p);
+    }
+    
+    
+    private JPanel makeHelpPanel(String input)
+    {
+        JPanel panel = new JPanel();
+        {
+            panel.setBorder(BlueJTheme.generalBorder);
+            panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+            panel.setAlignmentX(CENTER_ALIGNMENT);
+            Font helpFont = ((Font)UIManager.get("Label.font")).deriveFont(Font.ITALIC, 12.0f);
+            JTextArea text = new JTextArea(input);
+            {
+                text.setEditable(false);
+                text.setLineWrap(true);
+                text.setWrapStyleWord(true);
+                text.setBackground((Color)UIManager.get("Label.background"));
+                text.setForeground((Color)UIManager.get("Label.foreground"));
+                text.setFont(helpFont);
+            }
+            panel.add(text);
+        }
+        return panel;
+    }
+    
+    /**
+     * Set the helpPanel of the TeamControlsPanel
+     * @param helpPanel
+     */
+    private void setHelpPanel(JPanel helpPanel)
+    {
+        if (this.helpPanel != null)
+        {
+            remove(this.helpPanel);
+        }
+        this.helpPanel = helpPanel;
+        add(helpPanel, 0);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamPanelFocusPolicy.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamPanelFocusPolicy.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e2858a0b7e72b7b6ede98ec0e6ca5a135584c3c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamPanelFocusPolicy.java
@@ -0,0 +1,89 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.FocusTraversalPolicy;
+import java.awt.Window;
+
+/**
+ * A focus policy to override the initially focused component.
+ * All other operations are delegated to the original policy.
+ * 
+ * @author Davin McCall
+ * @version $Id: TeamPanelFocusPolicy.java 7421 2010-04-28 04:20:46Z davmac $
+ */
+public class TeamPanelFocusPolicy extends FocusTraversalPolicy
+{
+    private Component defaultComponent;
+    private FocusTraversalPolicy delegate;
+    
+    public TeamPanelFocusPolicy(Component defaultComponent, FocusTraversalPolicy delegate)
+    {
+        super();
+        this.defaultComponent = defaultComponent;
+        this.delegate = delegate;
+    }
+    
+    public Component getDefaultComponent(Container aContainer)
+    {
+        return delegate.getDefaultComponent(aContainer);
+    }
+    
+    public Component getComponentAfter(Container aContainer, Component aComponent)
+    {
+        aContainer.setFocusTraversalPolicy(delegate);
+        Component r = delegate.getComponentAfter(aContainer, aComponent);
+        aContainer.setFocusTraversalPolicy(this);
+        return r;
+    }
+    
+    public Component getComponentBefore(Container aContainer, Component aComponent)
+    {
+        aContainer.setFocusTraversalPolicy(delegate);
+        Component r = delegate.getComponentBefore(aContainer, aComponent);
+        aContainer.setFocusTraversalPolicy(this);
+        return r;
+    }
+        
+    public Component getFirstComponent(Container aContainer)
+    {
+        aContainer.setFocusTraversalPolicy(delegate);
+        Component r = delegate.getFirstComponent(aContainer);
+        aContainer.setFocusTraversalPolicy(this);
+        return r;
+    }
+    
+    public Component getLastComponent(Container aContainer)
+    {
+        aContainer.setFocusTraversalPolicy(delegate);
+        Component r = delegate.getLastComponent(aContainer);
+        aContainer.setFocusTraversalPolicy(this);
+        return r;
+    }
+    
+    public Component getInitialComponent(Window window)
+    {
+        return defaultComponent;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamSettingsDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamSettingsDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..716325b15130f3dfa6448d4dd408eaeea6185080
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamSettingsDialog.java
@@ -0,0 +1,174 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.groupwork.TeamSettings;
+import bluej.groupwork.TeamSettingsController;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+
+/**
+ * A dialog for teamwork settings.
+ *
+ * @author fisker
+ * @author bquig
+ * @version $Id: TeamSettingsDialog.java 7055 2010-01-27 13:58:55Z plcs $
+ */
+public class TeamSettingsDialog extends EscapeDialog
+{
+    private String title = Config.getString(
+            "team.settings.title");
+    public static final int OK = 0;
+    public static final int CANCEL = 1;
+    private TeamSettingsController teamSettingsController;
+    private TeamSettingsPanel teamSettingsPanel;
+    private int event;
+    
+    private JButton okButton;
+
+    /**
+     * Create a team settings dialog with a reference to the team settings
+     * controller that it manipulates.
+     */
+    public TeamSettingsDialog(TeamSettingsController controller)
+    {
+        teamSettingsController = controller;
+        event = CANCEL;
+        if(teamSettingsController.hasProject()) {
+            title += " - " + teamSettingsController.getProject().getProjectName();
+        }
+        setTitle(title);
+       
+        setModal(true);
+
+        JPanel mainPanel = new JPanel();
+        mainPanel.setBorder(BlueJTheme.dialogBorder);
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+
+        JPanel buttonPanel = makeButtonPanel();
+        teamSettingsPanel = new TeamSettingsPanel(teamSettingsController, this);
+        setFocusTraversalPolicy(teamSettingsPanel.getTraversalPolicy(
+                getFocusTraversalPolicy()));
+        mainPanel.add(teamSettingsPanel);
+        mainPanel.add(buttonPanel);
+        setContentPane(mainPanel);
+        pack();
+    }
+
+    /**
+     * Set up the panel containing the ok and cancel buttons, with associated
+     * actions.
+     */
+    private JPanel makeButtonPanel()
+    {
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+
+        {
+            buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+            okButton = BlueJTheme.getOkButton();
+            okButton.addActionListener(new ActionListener() {
+                    /**
+                     * Write the data from the teamSettingsPanel to the project's team.defs file
+                     * If checkbox in teamSettingsPanel is checked, the data is also stored in
+                     * bluej.properties
+                     */
+                    public void actionPerformed(ActionEvent e)
+                    {
+                        TeamSettings settings = teamSettingsPanel.getSettings();
+                        
+                        teamSettingsController.updateSettings(settings,
+                                teamSettingsPanel.getUseAsDefault());
+                        
+                        if (teamSettingsController.hasProject()) {
+                            teamSettingsController.writeToProject();
+                        }
+
+                        event = OK;
+                        setVisible(false);
+                    }
+                });
+
+            getRootPane().setDefaultButton(okButton);
+
+            JButton cancelButton = BlueJTheme.getCancelButton();
+            cancelButton.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent e)
+                    {
+                        event = CANCEL;
+                        setVisible(false);
+                    }
+                });
+
+            DialogManager.addOKCancelButtons(buttonPanel, okButton, cancelButton);
+        }
+
+        return buttonPanel;
+    }
+
+    /**
+     * Disable the fields used to specify the repository:
+     * group, prefix, server and protocol. Called when the team settings
+     * dialog is connected to a project already.
+     */
+    public void disableRepositorySettings()
+    {
+        teamSettingsPanel.disableRepositorySettings();
+    }
+
+    /**
+     * Display the dialog and wait for a response. Returns the user
+     * response as OK or CANCEL.
+     */
+    public int doTeamSettings()
+    {
+        setVisible(true);
+
+        return event;
+    }
+    
+    /**
+     * Enabled or disable to "Ok" button of the dialog.
+     */
+    public void setOkButtonEnabled(boolean enabled)
+    {
+        okButton.setEnabled(enabled);
+    }
+    
+    /**
+     * Get the settings specified by the user
+     */
+    public TeamSettings getSettings()
+    {
+        return teamSettingsPanel.getSettings();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamSettingsPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamSettingsPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..aaa3b840d42c0dd346320b6d36151af60e69e902
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/TeamSettingsPanel.java
@@ -0,0 +1,428 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.FocusTraversalPolicy;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.groupwork.TeamSettings;
+import bluej.groupwork.TeamSettingsController;
+import bluej.groupwork.TeamworkProvider;
+import bluej.groupwork.actions.ValidateConnectionAction;
+import bluej.utility.MiksGridLayout;
+
+/**
+ * A panel for team settings.
+ * 
+ * @author fisker
+ */
+public class TeamSettingsPanel extends JPanel 
+{
+    private static final int fieldsize = 20;
+    private TeamSettingsController teamSettingsController;
+    private TeamSettingsDialog teamSettingsDialog;
+    
+    private JTextField userField;
+    private JPasswordField passwordField;
+    private JTextField groupField;
+    private JTextField prefixField;
+    private JComboBox serverTypeComboBox;
+    private JTextField serverField;
+    private JComboBox protocolComboBox;
+    private JButton validateButton;
+    private JCheckBox useAsDefault;
+    
+    private JLabel serverTypeLabel;
+    private JLabel groupLabel;
+    private JLabel prefixLabel;
+    private JLabel serverLabel;
+    private JLabel protocolLabel;
+    
+    private int selectedServerType = -1;
+    private boolean okEnabled = true;
+    
+    public TeamSettingsPanel(TeamSettingsController teamSettingsController, TeamSettingsDialog dialog)
+    {
+        this.teamSettingsController = teamSettingsController;
+        this.teamSettingsDialog = dialog;
+        
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+        setBorder(BlueJTheme.generalBorder);
+        add(Box.createVerticalGlue());
+        
+        add(makePersonalPanel());
+        add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        add(makeLocationPanel());
+        add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        useAsDefault = new JCheckBox(Config.getString("team.settings.rememberSettings"));
+        add(useAsDefault);
+        add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        validateButton = new JButton(new ValidateConnectionAction(
+                Config.getString("team.settings.checkConnection"), this, dialog));
+        add(validateButton);
+        
+        DocumentListener changeListener = new DocumentListener() {
+            public void changedUpdate(DocumentEvent e)
+            {
+                checkOkEnabled();
+            }
+            
+            public void insertUpdate(DocumentEvent e)
+            {
+                checkOkEnabled();
+            }
+            
+            public void removeUpdate(DocumentEvent e)
+            {
+                checkOkEnabled();
+            }
+        };
+        
+        userField.getDocument().addDocumentListener(changeListener);
+        serverField.getDocument().addDocumentListener(changeListener);
+        
+        //add(new JSeparator());
+        add(Box.createVerticalGlue());
+        setupContent();
+        checkOkEnabled();
+        if (!teamSettingsController.hasProject()){
+            useAsDefault.setSelected(true);
+            // useAsDefault.setEnabled(false);
+        }
+    }
+    
+    /**
+     * Get the focus traversal policy for the parent window. The new policy
+     * overrides some functionality and delegates everything else back to
+     * the original policy (the delegate).
+     * 
+     * @param delegate  The original traversal policy
+     */
+    public FocusTraversalPolicy getTraversalPolicy(FocusTraversalPolicy delegate)
+    {
+        if (getUser().length() != 0) {
+            return new TeamPanelFocusPolicy(passwordField, delegate);
+        }
+        else {
+            return delegate;
+        }
+    }
+    
+    /**
+     * Disable the fields used to specify the repository:
+     * group, prefix, server and protocol
+     */
+    public void disableRepositorySettings()
+    {
+        serverTypeComboBox.setEnabled(false);
+        groupField.setEnabled(false);
+        prefixField.setEnabled(false);
+        serverField.setEnabled(false);
+        protocolComboBox.setEnabled(false);
+        
+        // useAsDefault.setEnabled(false);
+        
+        serverTypeLabel.setEnabled(false);
+        groupLabel.setEnabled(false);
+        prefixLabel.setEnabled(false);
+        serverLabel.setEnabled(false);
+        protocolLabel.setEnabled(false);
+    }
+    
+    private JPanel makePersonalPanel()
+    {
+        JPanel authentificationPanel = new JPanel();
+        {
+            authentificationPanel.setLayout(new MiksGridLayout(3,2,10,5));
+            String docTitle = Config.getString("team.settings.personal");
+            authentificationPanel.setBorder(BorderFactory.createCompoundBorder(
+                    BorderFactory.createTitledBorder(docTitle),
+                    BlueJTheme.generalBorder));
+            authentificationPanel.setAlignmentX(LEFT_ALIGNMENT);
+            
+            JLabel userLabel = new JLabel(Config.getString("team.settings.user"));
+            userField = new JTextField(fieldsize);
+            JLabel passwordLabel = new JLabel(Config.getString("team.settings.password"));
+            passwordField = new JPasswordField(fieldsize);
+            groupLabel = new JLabel(Config.getString("team.settings.group"));
+            groupField = new JTextField(fieldsize);
+            
+            userLabel.setMaximumSize(userLabel.getMinimumSize());
+            userField.setMaximumSize(userField.getMinimumSize());
+            passwordLabel.setMaximumSize(passwordLabel.getMinimumSize());
+            passwordField.setMaximumSize(passwordField.getMinimumSize());
+            groupLabel.setMaximumSize(groupLabel.getMinimumSize());
+            groupField.setMaximumSize(groupField.getMinimumSize());
+                        
+            authentificationPanel.add(userLabel);
+            authentificationPanel.add(userField);
+            authentificationPanel.add(passwordLabel);
+            authentificationPanel.add(passwordField);
+            authentificationPanel.add(groupLabel);
+            authentificationPanel.add(groupField);
+            
+        }
+        return authentificationPanel;
+    }
+    
+    private JPanel makeLocationPanel()
+    {
+        JPanel locationPanel = new JPanel(new MiksGridLayout(4,2,10,5));
+        {
+            String docTitle2 = Config.getString("team.settings.location");
+            locationPanel.setBorder(BorderFactory.createCompoundBorder(
+                    BorderFactory.createTitledBorder(docTitle2),
+                    BlueJTheme.generalBorder));
+            locationPanel.setAlignmentX(LEFT_ALIGNMENT);
+            
+            serverTypeLabel = new JLabel(Config.getString("team.settings.serverType"));
+            serverTypeComboBox = new JComboBox();
+            List<TeamworkProvider> teamProviders = teamSettingsController.getTeamworkProviders();
+            for (TeamworkProvider provider : teamProviders) {
+                serverTypeComboBox.addItem(provider.getProviderName());
+            }
+            
+            serverTypeComboBox.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e)
+                {
+                    setProviderSettings();
+                }
+            });
+            
+            serverLabel = new JLabel(Config.getString("team.settings.server"));
+            serverField = new JTextField(fieldsize);
+            
+            prefixLabel = new JLabel(Config.getString("team.settings.prefix"));
+            prefixField = new JTextField(fieldsize);
+            
+            protocolLabel = new JLabel(Config.getString("team.settings.protocol"));
+            protocolComboBox = new JComboBox();
+            protocolComboBox.setEditable(false);
+            
+            prefixLabel.setMaximumSize(prefixLabel.getMinimumSize());
+            prefixField.setMaximumSize(prefixField.getMinimumSize());
+            serverLabel.setMaximumSize(serverLabel.getMinimumSize());
+            serverField.setMaximumSize(serverField.getMinimumSize());
+            serverTypeLabel.setMaximumSize(serverTypeLabel.getMinimumSize());
+            serverTypeComboBox.setMaximumSize(serverTypeComboBox.getMinimumSize());
+            
+            locationPanel.add(serverTypeLabel);
+            locationPanel.add(serverTypeComboBox);
+            locationPanel.add(serverLabel);
+            locationPanel.add(serverField);
+            locationPanel.add(prefixLabel);
+            locationPanel.add(prefixField);
+            locationPanel.add(protocolLabel);
+            locationPanel.add(protocolComboBox);
+        }
+        return locationPanel;
+    }
+    
+    /**
+     * Empty the protocol selection box, then fill it with the available protocols
+     * from the currently selected teamwork provider.
+     */
+    private void fillProtocolSelections()
+    {
+        int selected = serverTypeComboBox.getSelectedIndex();
+        if (selected != selectedServerType) {
+            selectedServerType = selected;
+            protocolComboBox.removeAllItems();
+            List<TeamworkProvider> teamProviders = teamSettingsController.getTeamworkProviders();
+            TeamworkProvider provider = teamProviders.get(selected);
+            String [] protocols = provider.getProtocols();
+            for (int i = 0; i < protocols.length; i++) {
+                protocolComboBox.addItem(protocols[i]);
+            }
+        }
+    }
+        
+    private void setupContent()
+    {
+        String user = teamSettingsController.getPropString("bluej.teamsettings.user");
+        if (user != null) {
+            setUser(user);
+        }
+        String password = teamSettingsController.getPasswordString();
+        if (password != null) {
+            setPassword(password);
+        }
+        String group = teamSettingsController.getPropString("bluej.teamsettings.groupname");
+        if(group != null) {
+            setGroup(group);
+        }
+        String useAsDefault = teamSettingsController.getPropString("bluej.teamsettings.useAsDefault");
+        if (useAsDefault != null) {
+            setUseAsDefault(Boolean.getBoolean(useAsDefault));
+        }
+        
+        String providerName = teamSettingsController.getPropString("bluej.teamsettings.vcs");
+        if (providerName != null) {
+            List<TeamworkProvider> teamProviders = teamSettingsController.getTeamworkProviders();
+            for (int index = 0; index < teamProviders.size(); index++) {
+                TeamworkProvider provider = teamProviders.get(index);
+                if (provider.getProviderName().equalsIgnoreCase(providerName)) {
+                    serverTypeComboBox.setSelectedIndex(index);
+                    break;
+                }
+            }
+        }
+        
+        setProviderSettings();
+    }
+    
+    /**
+     * Set settings to provider-specific values (repository prefix, server, protocol).
+     * The values are remembered on a per-provider basis; this sets the fields to show
+     * the remembered values for the selected provider. 
+     */
+    private void setProviderSettings()
+    {
+        String keyBase = "bluej.teamsettings."
+            + getSelectedProvider().getProviderName().toLowerCase() + "."; 
+        
+        String prefix = teamSettingsController.getPropString(keyBase + "repositoryPrefix");
+        if (prefix != null) {
+            setPrefix(prefix);
+        }
+        String server = teamSettingsController.getPropString(keyBase + "server");
+        if (server != null) {
+            setServer(server);
+        }
+        
+        fillProtocolSelections();
+        
+        String protocol = teamSettingsController.getPropString(keyBase + "protocol");
+        if (protocol != null){
+            setProtocol(protocol);
+        }
+    }
+    
+    /**
+     * Check whether the "ok" button should be enabled or disabled according
+     * to whether required fields have been provided.
+     */
+    private void checkOkEnabled()
+    {
+        boolean newOkEnabled = userField.getText().length() != 0;
+        newOkEnabled &= serverField.getText().length() != 0;
+        if (newOkEnabled != okEnabled) {
+            okEnabled = newOkEnabled;
+            teamSettingsDialog.setOkButtonEnabled(okEnabled);
+        }
+    }
+    
+    private void setUser(String user)
+    {
+        userField.setText(user);
+    }
+    
+    private void setPassword(String password)
+    {
+        passwordField.setText(password);
+    }
+    
+    private void setGroup(String group)
+    {
+        groupField.setText(group);
+    }
+    
+    private void setPrefix(String prefix)
+    {
+        prefixField.setText(prefix);
+    }
+    
+    private void setServer(String server)
+    {
+        serverField.setText(server);
+    }
+    
+    /**
+     * Set the protocol to that identified by the given protocol key.
+     */
+    private void setProtocol(String protocolKey)
+    {
+        String protocolLabel = getSelectedProvider().getProtocolLabel(protocolKey);
+        protocolComboBox.setSelectedItem(protocolLabel);
+    }
+    
+    private void setUseAsDefault(boolean use)
+    {
+        useAsDefault.setSelected(use);
+    }
+    
+    public TeamworkProvider getSelectedProvider()
+    {
+        int selected = serverTypeComboBox.getSelectedIndex();
+        return teamSettingsController.getTeamworkProviders().get(selected);
+    }
+    
+    private String getUser()
+    {
+        return userField.getText();
+    }
+    
+    private String getPassword()
+    {
+        return new String(passwordField.getPassword());
+    }
+    
+    private String getGroup()
+    {
+        return groupField.getText();
+    }
+    
+    private String getPrefix()
+    {
+        return prefixField.getText();
+    }
+    
+    private String getServer()
+    {
+        return serverField.getText();
+    }
+    
+    private String getProtocolKey()
+    {
+        int protocol = protocolComboBox.getSelectedIndex();
+        return getSelectedProvider().getProtocolKey(protocol);
+    }
+    
+    public boolean getUseAsDefault()
+    {
+        return useAsDefault.isSelected();
+    }
+    
+    public TeamSettings getSettings()
+    {
+        return new TeamSettings(getSelectedProvider(), getProtocolKey(),
+                getServer(), getPrefix(), getGroup(), getUser(), getPassword());
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/UpdateFilesFrame.java b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/UpdateFilesFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..67b50b259030bb41312dee5ade5018760396518c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/groupwork/ui/UpdateFilesFrame.java
@@ -0,0 +1,531 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.groupwork.ui;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.BorderFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.groupwork.Repository;
+import bluej.groupwork.StatusHandle;
+import bluej.groupwork.StatusListener;
+import bluej.groupwork.TeamStatusInfo;
+import bluej.groupwork.TeamUtils;
+import bluej.groupwork.TeamViewFilter;
+import bluej.groupwork.TeamworkCommand;
+import bluej.groupwork.TeamworkCommandResult;
+import bluej.groupwork.UpdateFilter;
+import bluej.groupwork.actions.UpdateAction;
+import bluej.pkgmgr.BlueJPackageFile;
+import bluej.pkgmgr.Project;
+import bluej.utility.DBox;
+import bluej.utility.DBoxLayout;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+import bluej.utility.SwingWorker;
+import bluej.utility.Utility;
+
+
+/**
+ * A Swing based user interface for showing files to be updated
+ * @author Bruce Quig
+ * @author Davin McCall
+ */
+public class UpdateFilesFrame extends EscapeDialog
+{
+    private JList updateFiles;
+    private JPanel topPanel;
+    private JPanel bottomPanel;
+    private JButton updateButton;
+    private JCheckBox includeLayoutCheckbox;
+    private ActivityIndicator progressBar;
+    private UpdateAction updateAction;
+    private UpdateWorker updateWorker;
+
+    private Project project;
+    
+    private Repository repository;
+    private DefaultListModel updateListModel;
+    
+    private Set<TeamStatusInfo> changedLayoutFiles; // set of TeamStatusInfo
+    private Set<File> forcedLayoutFiles; // set of File
+    private boolean includeLayout = true;
+    
+    private static String noFilesToUpdate = Config.getString("team.noupdatefiles"); 
+
+    public UpdateFilesFrame(Project proj)
+    {
+        project = proj;
+        changedLayoutFiles = new HashSet<TeamStatusInfo>();
+        forcedLayoutFiles = new HashSet<File>();
+        createUI();
+        DialogManager.centreDialog(this);
+    }
+    
+    public void setVisible(boolean show)
+    {
+        super.setVisible(show);
+        if (show) {
+            // we want to set update action disabled until we know that
+            // there's something to update
+            updateAction.setEnabled(false);
+            includeLayoutCheckbox.setSelected(false);
+            includeLayoutCheckbox.setEnabled(false);
+            changedLayoutFiles.clear();
+            forcedLayoutFiles.clear();
+            updateListModel.removeAllElements();
+            
+            repository = project.getRepository();
+            
+            if (repository != null) {
+                try {
+                    project.saveAllEditors();
+                    project.saveAll();
+                }
+                catch (IOException ioe) {
+                    String msg = DialogManager.getMessage("team-error-saving-project");
+                    if (msg != null) {
+                        msg = Utility.mergeStrings(msg, ioe.getLocalizedMessage());
+                        DialogManager.showErrorText(this, msg);
+                    }
+                }
+                startProgress();
+                updateWorker = new UpdateWorker();
+                updateWorker.start();
+            }
+            else {
+                super.setVisible(false);
+            }
+        }
+    }
+    
+    /**
+     * Create the user-interface for the error display dialog.
+     */
+    protected void createUI()
+    {
+        setTitle(Config.getString("team.update.title"));
+        updateListModel = new DefaultListModel();
+        
+        //setIconImage(BlueJTheme.getIconImage());
+        setLocation(Config.getLocation("bluej.updatedisplay"));
+
+        // save position when window is moved
+        addComponentListener(new ComponentAdapter() {
+                public void componentMoved(ComponentEvent event)
+                {
+                    Config.putLocation("bluej.updatedisplay", getLocation());
+                }
+            });
+
+        topPanel = new JPanel();
+
+        JScrollPane updateFileScrollPane = new JScrollPane();
+
+        {
+            topPanel.setLayout(new BorderLayout());
+
+            JLabel updateFilesLabel = new JLabel(Config.getString(
+                        "team.update.files"));
+            updateFilesLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
+            topPanel.add(updateFilesLabel, BorderLayout.NORTH);
+
+            updateFiles = new JList(updateListModel);
+            updateFiles.setCellRenderer(new FileRenderer(project));
+            updateFiles.setEnabled(false);
+            updateFileScrollPane.setViewportView(updateFiles);
+            
+            topPanel.add(updateFileScrollPane, BorderLayout.CENTER);
+        }
+
+        bottomPanel = new JPanel();
+
+        {
+            bottomPanel.setLayout(new BorderLayout());
+
+            updateAction = new UpdateAction(this);
+            updateButton = BlueJTheme.getOkButton();
+            updateButton.setAction(updateAction);
+            updateButton.addActionListener(new ActionListener() {
+               public void actionPerformed(ActionEvent e)
+                {
+                   includeLayoutCheckbox.setEnabled(false);
+                } 
+            });
+            getRootPane().setDefaultButton(updateButton);
+
+            JButton closeButton = BlueJTheme.getCancelButton();
+            closeButton.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent e)
+                    {
+                        updateAction.cancel();
+                        updateWorker.abort();
+                        setVisible(false);
+                    }
+                });
+           
+            DBox buttonPanel = new DBox(DBoxLayout.X_AXIS, 0, BlueJTheme.commandButtonSpacing, 0.5f);
+            buttonPanel.setBorder(BlueJTheme.generalBorder);
+            
+            progressBar = new ActivityIndicator();
+            progressBar.setRunning(false);
+            
+            DBox checkBoxPanel = new DBox(DBoxLayout.Y_AXIS, 0, BlueJTheme.commandButtonSpacing, 0.5f);
+            includeLayoutCheckbox = new JCheckBox(Config.getString("team.update.includelayout"));
+            includeLayoutCheckbox.setEnabled(false);
+            includeLayoutCheckbox.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e)
+                {
+                    JCheckBox layoutCheck = (JCheckBox)e.getSource();
+                    includeLayout = layoutCheck.isSelected();
+                    resetForcedFiles();
+                    if (includeLayout) {
+                        addModifiedLayouts();
+                        if(!updateButton.isEnabled()) {
+                            updateAction.setEnabled(true);
+                        }
+                    }
+                    // unselected
+                    else {
+                        removeModifiedLayouts();
+                        if(isUpdateListEmpty()) {
+                            updateAction.setEnabled(false);
+                        }
+                    }
+                }
+            });
+
+            checkBoxPanel.add(includeLayoutCheckbox);
+            checkBoxPanel.add(buttonPanel);
+            
+            buttonPanel.add(progressBar);
+            buttonPanel.add(updateButton);
+            buttonPanel.add(closeButton);
+            bottomPanel.add(checkBoxPanel, BorderLayout.SOUTH);
+        }
+
+        DBox mainPanel = new DBox(DBox.Y_AXIS, 0.5f);
+        mainPanel.setBorder(BlueJTheme.dialogBorder);
+        mainPanel.add(topPanel);
+        mainPanel.add(bottomPanel);
+        getContentPane().add(mainPanel);
+        
+        pack();
+    }
+
+    public void reset()
+    {
+        updateListModel.clear();
+    }
+    
+    private void removeModifiedLayouts()
+    {
+        // remove modified layouts from list of files shown for commit
+        for(Iterator<TeamStatusInfo> it = changedLayoutFiles.iterator(); it.hasNext();) {
+            updateListModel.removeElement(it.next());
+        }
+        if(updateListModel.isEmpty()) {
+            updateListModel.addElement(noFilesToUpdate);
+        }
+    }
+    
+    private boolean isUpdateListEmpty()
+    {
+        return updateListModel.isEmpty() || updateListModel.contains(noFilesToUpdate);
+    }
+    
+    /**
+     * Add the modified layouts to the displayed list of files to be updated.
+     */
+    private void addModifiedLayouts()
+    {
+        if(updateListModel.contains(noFilesToUpdate)) {
+            updateListModel.removeElement(noFilesToUpdate);
+        }
+    }
+    
+    /**
+     * Get a set (of File) containing the layout files which need to be updated.
+     */
+    public Set<File> getChangedLayoutFiles()
+    {
+        Set<File> files = new HashSet<File>();
+        for(Iterator<TeamStatusInfo> it = changedLayoutFiles.iterator(); it.hasNext(); ) {
+            TeamStatusInfo info = it.next();
+            files.add(info.getFile());
+        }
+        return files;
+    }
+    
+    public boolean includeLayout()
+    {
+        return includeLayoutCheckbox != null && includeLayoutCheckbox.isSelected();
+    }
+    
+    /**
+     * Start the activity indicator.
+     */
+    public void startProgress()
+    {
+        progressBar.setRunning(true);
+    }
+
+    /**
+     * Stop the activity indicator. Call from any thread.
+     */
+    public void stopProgress()
+    {
+        progressBar.setRunning(false);
+    }
+    
+    public Project getProject()
+    {
+        return project;
+    }
+    
+    /**
+     * The layout has changed. Enable the "include layout" checkbox, etc.
+     */
+    private void setLayoutChanged()
+    {
+        includeLayoutCheckbox.setEnabled(true);
+        includeLayoutCheckbox.setSelected(includeLayout);
+    }
+    
+    /**
+     * Re-set the forced files in the update action. This needs to be
+     * done when the "include layout" option is toggled.
+     */
+    private void resetForcedFiles()
+    {
+        Set<File> forcedFiles = new HashSet<File>(forcedLayoutFiles);
+        if (includeLayout) {
+            for (Iterator<TeamStatusInfo> i = changedLayoutFiles.iterator(); i.hasNext(); ) {
+                TeamStatusInfo info = i.next();
+                forcedFiles.add(info.getFile());
+            }
+        }
+        updateAction.setFilesToForceUpdate(forcedFiles);
+    }
+
+    /**
+    * Inner class to do the actual cvs status check to populate commit dialog
+    * to ensure that the UI is not blocked during remote call
+    */
+    class UpdateWorker extends SwingWorker implements StatusListener
+    {
+        List<TeamStatusInfo> response;
+        TeamworkCommand command;
+        TeamworkCommandResult result;
+        private boolean aborted;
+        private StatusHandle statusHandle;
+
+        public UpdateWorker()
+        {
+            super();
+            response = new ArrayList<TeamStatusInfo>();
+            FileFilter filter = project.getTeamSettingsController().getFileFilter(true);
+            command = repository.getStatus(this, filter, true);
+        }
+        
+        /* (non-Javadoc)
+         * @see bluej.groupwork.StatusListener#gotStatus(bluej.groupwork.TeamStatusInfo)
+         */
+        public void gotStatus(TeamStatusInfo info)
+        {
+            response.add(info);
+        }
+        
+        /* (non-Javadoc)
+         * @see bluej.groupwork.StatusListener#statusComplete(bluej.groupwork.CommitHandle)
+         */
+        public void statusComplete(StatusHandle statusHandle)
+        {
+            this.statusHandle = statusHandle;
+        }
+        
+        public Object construct()
+        {
+            result = command.getResult();
+            return response;
+        }
+        
+        public void abort()
+        {
+            command.cancel();
+            aborted = true;
+        }
+
+        public void finished()
+        {
+            stopProgress();
+            if (! aborted) {
+                if (result.isError()) {
+                    TeamUtils.handleServerResponse(result, UpdateFilesFrame.this);
+                    setVisible(false);
+                }
+                else {
+                    Set<File> filesToUpdate = new HashSet<File>();
+                    Set<File> conflicts = new HashSet<File>();
+                    Set<File> modifiedLayoutFiles = new HashSet<File>();
+
+                    List<TeamStatusInfo> info = response;
+                    getUpdateFileSet(info, filesToUpdate, conflicts, modifiedLayoutFiles);
+
+                    if (conflicts.size() != 0) {
+                        String filesList = "";
+                        Iterator<File> i = conflicts.iterator();
+                        for (int j = 0; j < 10 && i.hasNext(); j++) {
+                            File conflictFile = i.next();
+                            filesList += "    " + conflictFile.getName() + "\n";
+                        }
+
+                        // If there are more than 10 conflicts, we won't list them
+                        // all in the dialog
+                        if (i.hasNext()) {
+                            filesList += "    (and more - check status)";
+                        }
+
+                        DialogManager.showMessageWithText(UpdateFilesFrame.this, "team-unresolved-conflicts", filesList);
+                        UpdateFilesFrame.this.setVisible(false);
+                        return;
+                    }
+
+                    // Build the actual set of files to update. If there are new or removed
+                    // directories, don't include files within.
+                    Set<File> updateFiles = new HashSet<File>();
+                    for (Iterator<File> i = filesToUpdate.iterator(); i.hasNext(); ) {
+                        File file = i.next();
+                        if (! filesToUpdate.contains(file.getParentFile())) {
+                            updateFiles.add(file);
+                        }
+                    }
+                    for (Iterator<File> i = forcedLayoutFiles.iterator(); i.hasNext(); ) {
+                        File file = (File) i.next();
+                        if (filesToUpdate.contains(file.getParentFile())) {
+                            i.remove();
+                        }
+                    }
+                    
+                    updateAction.setStatusHandle(statusHandle);
+                    updateAction.setFilesToUpdate(updateFiles);
+                    resetForcedFiles();
+
+                    if (includeLayout && ! changedLayoutFiles.isEmpty()) {
+                        addModifiedLayouts();
+                    }
+
+                    if(updateListModel.isEmpty()) {
+                        updateListModel.addElement(noFilesToUpdate);
+                    }
+                    else {
+                        updateAction.setEnabled(true);
+                    }
+                }
+            }
+        }
+        
+        /**
+         * Go through the status list, and figure out which files to update, and
+         * which to force update.
+         * 
+         * @param info  The list of files with status (List of TeamStatusInfo)
+         * @param filesToUpdate  The set to store the files to update in
+         * @param modifiedLayoutFiles  The set to store the files to be force updated in
+         * @param conflicts      The set to store unresolved conflicts in
+         *                       (any files in this set prevent update from occurring)
+         */
+        private void getUpdateFileSet(List<TeamStatusInfo> info, Set<File> filesToUpdate, Set<File> conflicts, Set<File> modifiedLayoutFiles)
+        {
+            UpdateFilter filter = new UpdateFilter();
+            TeamViewFilter viewFilter = new TeamViewFilter();
+            for (Iterator<TeamStatusInfo> it = info.iterator(); it.hasNext();) {
+                TeamStatusInfo statusInfo = it.next();
+                int status = statusInfo.getStatus();
+                if(filter.accept(statusInfo)) {
+                    if (!BlueJPackageFile.isPackageFileName(statusInfo.getFile().getName())) { 
+                        updateListModel.addElement(statusInfo);
+                        filesToUpdate.add(statusInfo.getFile());
+                    }
+                    else {
+                        if( !viewFilter.accept(statusInfo)) {
+                            // If the file should not be viewed, just ignore it.
+                        }
+                        else if (filter.updateAlways(statusInfo)) {
+                            // The package file is new or removed. There is no
+                            // option not to include it in the update.
+                            updateListModel.addElement(statusInfo);
+                            forcedLayoutFiles.add(statusInfo.getFile());
+                        }
+                        else {
+                            // add file to list of files that may be added to commit
+                            modifiedLayoutFiles.add(statusInfo.getFile());
+                            // keep track of StatusInfo objects representing changed diagrams
+                            changedLayoutFiles.add(statusInfo);
+                        }
+                    }
+                }
+                else {
+                    boolean conflict;
+                    conflict = status == TeamStatusInfo.STATUS_UNRESOLVED;
+                    conflict |= status == TeamStatusInfo.STATUS_CONFLICT_ADD;
+                    conflict |= status == TeamStatusInfo.STATUS_CONFLICT_LMRD;
+                    if (conflict) {
+                        if(!BlueJPackageFile.isPackageFileName(statusInfo.getFile().getName())) {
+                            conflicts.add(statusInfo.getFile());
+                        }
+                        else {
+                            // bluej package file will be force-updated
+                            modifiedLayoutFiles.add(statusInfo.getFile());
+                            changedLayoutFiles.add(statusInfo);
+                        }
+                    }
+                }
+            }
+            
+            if (! changedLayoutFiles.isEmpty()) {
+                setLayoutChanged();
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/AssistContent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/AssistContent.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f17d721432787bf822b25e8d279faeb185a84d9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/AssistContent.java
@@ -0,0 +1,63 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+/**
+ * Describes a possible code completion.
+ * 
+ * @author Marion Zalk
+ */
+public abstract class AssistContent
+{
+    /** Get just the name of the method, to display in the box */
+    public abstract String getDisplayMethodName();
+    /** Get the parameters of the method (including brackets), to display in the box */
+    public abstract String getDisplayMethodParams();
+    
+    /** Get the text to display in the code completion box for this completion */
+    public abstract String getDisplayName();
+    
+    /** Get the completion text (to appear in front of the cursor/selection) */
+    public abstract String getCompletionText();
+    
+    /** Get the completion text to appear selected */
+    public abstract String getCompletionTextSel();
+    
+    /** Get the completion text (portion to appear behind the cursor/selection) */
+    public abstract String getCompletionTextPost();
+
+    /** Get the return type for this completion (as a string) */
+    public abstract String getReturnType();
+
+    /** Get the declaring class of this completion (as a string) */
+    public abstract String getDeclaringClass();
+
+    /** Return true if this completion has parameters */
+    public abstract boolean hasParameters();
+    
+    /**
+     * Get the javadoc comment for this completion. The comment has been stripped of the
+     * delimiters (slash-star at the start and star-slash at the end) and intermediate
+     * star characters.
+     */
+    public abstract String getJavadoc();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CodeSuggestions.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CodeSuggestions.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3e4f7f7a7f8096523aea91d202ef80354102a46
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CodeSuggestions.java
@@ -0,0 +1,86 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.JavaType;
+import bluej.parser.lexer.LocatableToken;
+
+/**
+ * Wrapper for information about code suggestions.
+ * 
+ * @author Davin McCall
+ */
+public class CodeSuggestions
+{
+    private JavaType suggestionType;
+    private GenTypeClass accessType;
+    private LocatableToken suggestionToken;
+    private boolean staticRestricted=false;   //restrict suggestions to only static methods e.g for a class
+    
+    /**
+     * Construct a new set of CodeSuggestions.
+     * @param suggestionType  The type to suggest members from
+     * @param accessType      The type which is doing the access (for access control purposes).
+     *                        May be null.
+     * @param suggestionToken The token representing the suggestion prefix, i.e. the portion of the
+     *                        member name already typed by the user
+     * @param staticOnly    Indicates if true that non-static members should not be included
+     *                      in the returned results                 
+     */
+    public CodeSuggestions(JavaType suggestionType, GenTypeClass accessType, LocatableToken suggestionToken, boolean staticOnly)
+    {
+        this.suggestionToken = suggestionToken;
+        this.suggestionType = suggestionType;
+        this.accessType = accessType;
+        this.staticRestricted = staticOnly;
+    }
+    
+    public LocatableToken getSuggestionToken()
+    {
+        return suggestionToken;
+    }
+    
+    public JavaType getSuggestionType()
+    {
+        return suggestionType;
+    }
+    
+    /**
+     * Get the type in which the expression occurs (the "access type").
+     * This might return null.
+     */
+    public GenTypeClass getAccessType()
+    {
+        return accessType;
+    }
+
+    public void setStatic(boolean restricted)
+    {
+        this.staticRestricted = restricted;
+    }
+
+    public boolean isStatic()
+    {
+        return staticRestricted;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CodepadImportParser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CodepadImportParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e30099542e3360fac98be3480122477304070c9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CodepadImportParser.java
@@ -0,0 +1,151 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.UnresolvedEntity;
+import bluej.parser.lexer.LocatableToken;
+
+/**
+ * A parser to handle "import" statements for the Code Pad.
+ * 
+ * @author Davin McCall
+ */
+public class CodepadImportParser extends JavaParser
+{
+    private EntityResolver resolver;
+ 
+    private boolean importIsStatic = false;
+    private boolean importIsWildcard = false;
+    private JavaEntity importEntity;
+    private String memberName;  // for static imports
+    
+   /**
+    * Construct a codepad import parser. The next step is usually to
+    * call "parseImportStatement()".
+    */
+    public CodepadImportParser(EntityResolver resolver, Reader r)
+    {
+        super(r);
+        this.resolver = resolver;
+    }
+    
+    /**
+     * If import statement parse succeeded, this method reveals whether the
+     * import was a static import ("import static xyz.abc")
+     */
+    public boolean isStaticImport()
+    {
+        return importIsStatic;
+    }
+    
+    /**
+     * If import statement parse succeeded, this method reveals whether the
+     * import was a wildcard import ("import xyz.*", "import static xyz.*")
+     */
+    public boolean isWildcardImport()
+    {
+        return importIsWildcard;
+    }
+    
+    /**
+     * If import statement parse succeeded, this method returns an entity
+     * describing the imported entity. For wildcard imports this is the entity
+     * before the wildcard; for (non-wildcard) static imports this is the containing
+     * entity, and the imported member(s) name can be determined using getMemberName().
+     */
+    public JavaEntity getImportEntity()
+    {
+        return importEntity;
+    }
+    
+    /**
+     * If import statement parse succeeded, and the import is a non-wildcard static
+     * import, this method returns the imported member(s) name (otherwise returns
+     * null).
+     */
+    public String getMemberName()
+    {
+        return memberName;
+    }
+
+    @Override
+    protected void gotImport(List<LocatableToken> tokens, boolean isStatic)
+    {
+        importIsStatic = isStatic;
+        
+        if (isStatic) {
+            // Apparently static classes can be imported with or without the "static" keyword
+            // So, a static import imports a field and/or method and/or class.
+            // That's right - the same import statement pulls in all three.
+            
+            // We want to pull the name out
+            int newSize = tokens.size() - 2;
+            memberName = tokens.get(newSize + 1).getText();
+            
+            List<LocatableToken> newList = new ArrayList<LocatableToken>(newSize);
+            Iterator<LocatableToken> i = tokens.iterator();
+            while (newSize > 0) {
+                newList.add(i.next());
+                newSize--;
+            }
+            tokens = newList;
+        }
+        else {
+            memberName = tokens.get(tokens.size() - 1).getText();
+        }
+        
+        importEntity = getEntityForTokens(tokens);
+    }
+    
+    @Override
+    protected void gotWildcardImport(List<LocatableToken> tokens,
+            boolean isStatic)
+    {
+        importEntity = getEntityForTokens(tokens);
+        importIsWildcard = true;
+        importIsStatic = isStatic;
+    }
+    
+    /**
+     * Get an entity for the given tokens. The tokens should be a dotted identifier,
+     * eg "java.lang.String", "java.awt.Color.BLACK", etc.
+     */
+    protected JavaEntity getEntityForTokens(List<LocatableToken> tokens)
+    {
+        Iterator<LocatableToken> i = tokens.iterator();
+        String name = i.next().getText();
+        JavaEntity entity = UnresolvedEntity.getEntity(resolver, name, null);
+        while (entity != null && i.hasNext()) {
+            i.next(); // should be the '.' token
+            name = i.next().getText();
+            entity = entity.getSubentity(name, null);
+        }
+        return entity;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CodepadVarParser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CodepadVarParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..f82718b62dbbde9aa431ee62f887a44932999a8f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CodepadVarParser.java
@@ -0,0 +1,133 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugmgr.texteval.DeclaredVar;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+
+/**
+ * Parse variable declarations/initializations (for the codepad).
+ * 
+ * @author Davin McCall
+ */
+public class CodepadVarParser extends JavaParser
+{
+    private EntityResolver resolver;
+    
+    private int arrayCount = 0;
+    private int modifiers = 0;
+    private boolean gotFirstVar = false;
+    private JavaType baseType;
+    private List<DeclaredVar> variables = new ArrayList<DeclaredVar>();
+    
+    
+    public CodepadVarParser(EntityResolver resolver, Reader reader)
+    {
+        super(reader);
+        this.resolver = resolver;
+    }
+
+    public CodepadVarParser(EntityResolver resolver, String text)
+    {
+        this(resolver, new StringReader(text));
+    }
+    
+    /**
+     * Get the variables found to be declared by the parsed text. This should be called after
+     * first calling "parseVariableDeclarations()".
+     */
+    public List<DeclaredVar> getVariables()
+    {
+        return variables;
+    }
+    
+    @Override
+    protected void gotTypeSpec(List<LocatableToken> tokens)
+    {
+        if (! gotFirstVar) {
+            JavaEntity bent = ParseUtils.getTypeEntity(resolver, null, tokens);
+            if (bent == null) {
+                return;
+            }
+            bent = bent.resolveAsType();
+            if (bent != null) {
+                baseType = bent.getType();
+            }
+        }
+    }
+        
+    @Override
+    protected void gotArrayDeclarator()
+    {
+        arrayCount++;
+    }
+    
+    @Override
+    protected void gotVariableDecl(LocatableToken first, LocatableToken idToken, boolean inited)
+    {
+        gotFirstVar = true;
+        if (baseType != null) {
+            JavaType vtype = baseType;
+            while (arrayCount > 0) {
+                vtype = vtype.getArray();
+                arrayCount--;
+            }
+            variables.add(new DeclaredVar(inited, Modifier.isFinal(modifiers),
+                    vtype, idToken.getText()));
+        }
+    }
+    
+    @Override
+    protected void gotSubsequentVar(LocatableToken first, LocatableToken idToken, boolean inited)
+    {
+        if (baseType != null) {
+            JavaType vtype = baseType;
+            while (arrayCount > 0) {
+                vtype = vtype.getArray();
+                arrayCount--;
+            }
+            variables.add(new DeclaredVar(inited, Modifier.isFinal(modifiers),
+                    vtype, idToken.getText()));
+        }
+    }
+    
+    @Override
+    protected void gotModifier(LocatableToken token)
+    {
+        if (! gotFirstVar) {
+            if (token.getType() == JavaTokenTypes.FINAL) {
+                modifiers |= Modifier.FINAL;
+            }
+        }
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CompletionParser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CompletionParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..2646ef5768fdd1dfdcf8fc5e4090f57ff3843aa6
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/CompletionParser.java
@@ -0,0 +1,181 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.io.Reader;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeSolid;
+import bluej.debugger.gentype.MethodReflective;
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.lexer.LocatableToken;
+
+/**
+ * A parser which determines what code completions are available.
+ * 
+ * @author Davin McCall
+ */
+public class CompletionParser extends TextParser
+{
+    private Map<String,Set<MethodReflective>> methodSuggestions = Collections.emptyMap();
+    private JavaEntity suggestionEntity;
+    private LocatableToken suggestionToken;
+    private boolean staticRestricted=false;
+
+    /**
+     * Construct an expression parser, used for suggesting completions.
+     * 
+     * <p>Generally, after construction, call "parseExpression" and then
+     * "getFieldSuggestions".
+     * 
+     * @param resolver   The resolver used to resolve identifiers
+     * @param reader     The reader for the java source. This must return end-of-file
+     *                    at the point where suggestions are to be made.
+     * @param enclosingType  An entity representing the enclosing type of the cursor location
+     */
+    public CompletionParser(EntityResolver resolver, Reader reader, JavaEntity defaultEnt)
+    {
+        super(resolver, reader, defaultEnt, false);
+        suggestionEntity = defaultEnt;
+    }
+
+    /**
+     * Construct an expression parser, used for suggesting code completions,
+     * specifying the position within the document at which the expression
+     * begins.
+     * 
+     * <p>Generally, after construction, call "parseExpression" and then
+     * "getFieldSuggestions".
+     * 
+     * @param resolver   The resolver used to resolve identifiers
+     * @param reader     The reader for the java source. This must return end-of-file
+     *                    at the point where suggestions are to be made. The first
+     *                    character read should be the character at the specified line
+     *                    and column of the document.
+     * @param defaultEnt  An entity representing the enclosing type or value of the
+     *                    cursor location.
+     * @param  line    The source line where the expression begins
+     * @param  col     The source column where the expression begins
+     */
+    public CompletionParser(EntityResolver resolver, Reader reader,
+            JavaEntity defaultEnt, int line, int col, int pos)
+    {
+        super(resolver, reader, defaultEnt, false, line, col, pos);
+        suggestionEntity = defaultEnt;
+    }
+    
+    @Override
+    protected void error(String msg, int beginLine, int beginCol, int endLine, int endCol)
+    {
+        return;
+    }
+    
+    public Map<String,Set<MethodReflective>> getMethodSuggestions()
+    {
+        if (methodSuggestions == null) {
+            suggestFor(getSuggestionType());
+        }
+        return methodSuggestions;
+    }
+    
+    /**
+     * Get the type for which to make suggestions. The suggestions presented to the user
+     * should be members of the returned type.
+     */
+    public GenTypeSolid getSuggestionType()
+    {
+        if (suggestionEntity != null) {
+            JavaEntity valEnt = suggestionEntity.resolveAsValue();
+            if (valEnt != null) {
+                return valEnt.getType().getCapture().asSolid();
+            }
+            valEnt = suggestionEntity.resolveAsType();
+            if (valEnt != null) {
+                setStatic(true);
+                return valEnt.getType().getCapture().asSolid();
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Get the token, if any, which represents the partial identifier just before the
+     * completion point.
+     */
+    public LocatableToken getSuggestionToken()
+    {
+        return suggestionToken;
+    }
+    
+    @Override
+    protected void gotDotEOF(LocatableToken token)
+    {
+        suggestionEntity = popValueStack();
+    }
+    
+    @Override
+    protected void gotIdentifierEOF(LocatableToken token)
+    {
+        suggestionToken = token;
+    }
+    
+    @Override
+    protected void gotMemberAccessEOF(LocatableToken token)
+    {
+        suggestionToken = token;
+        suggestionEntity = popValueStack();
+    }
+    
+    @Override
+    protected void completeCompoundValueEOF(LocatableToken token)
+    {
+        suggestionToken = token;
+        suggestionEntity = popValueStack();
+    }
+    
+    private void suggestFor(GenTypeSolid type)
+    {
+        if (type != null) {
+            //JavaType type = valueEnt.getType().getCapture();
+            GenTypeClass ctype = type.asClass();
+            if (ctype != null) {
+                Reflective r = ctype.getReflective();
+                methodSuggestions = r.getDeclaredMethods();
+            }
+        }
+    }
+    
+    public boolean isSuggestionStatic()
+    {
+        return staticRestricted;
+    }
+
+    protected void setStatic(boolean restricted)
+    {
+        this.staticRestricted = restricted;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/DocumentReader.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/DocumentReader.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f9bdfbe94307a600b34e708aa1db08d3317fc22
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/DocumentReader.java
@@ -0,0 +1,110 @@
+package bluej.parser;
+
+import java.io.Reader;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Segment;
+
+/**
+ * An efficient reader which reads directly from the supplied Document.
+ * 
+ * @author Davin McCall
+ */
+public class DocumentReader extends Reader
+{
+    private Segment buffer;
+    private Document document;
+    private int bufpos;
+    private int docPosition;
+    private int docLength;
+    
+    /**
+     * Construct a DocumentReader to read an entire document.
+     */
+    public DocumentReader(Document document)
+    {
+        this(document, 0);
+    }
+    
+    /**
+     * Construct a DocumentReader to read a document starting from the given position.
+     */
+    public DocumentReader(Document document, int position)
+    {
+        buffer = new Segment();
+        buffer.setPartialReturn(true);
+        this.document = document;
+        docPosition = position;
+        docLength = document.getLength();
+        fillBuffer();
+    }
+    
+    /**
+     * Construct a new DocumentReader to read text between the two
+     * given document positions.
+     */
+    public DocumentReader(Document document, int position, int endpos)
+    {
+        buffer = new Segment();
+        buffer.setPartialReturn(true);
+        this.document = document;
+        docPosition = position;
+        docLength = endpos;
+        fillBuffer();
+    }
+    
+    public void close()
+    {
+        // Nothing to do
+    }
+
+    public int read()
+    {
+        if (bufpos == buffer.getEndIndex()) {
+            if (docPosition == docLength) {
+                return -1;
+            }
+            fillBuffer();
+        }
+        
+        return buffer.array[bufpos++];
+    }
+    
+    public int read(char[] cbuf, int off, int len)
+    {
+        int docAvail = Math.min(len, docLength - docPosition + buffer.getEndIndex() - bufpos);
+        
+        if (docAvail == 0) {
+            return -1;
+        }
+        
+        len = Math.min(len, docAvail);
+        int remaining = len;
+        
+        while (remaining > 0) {
+            int avail = Math.min(buffer.getEndIndex() - bufpos, remaining);
+            if (avail == 0) {
+                fillBuffer();
+                avail = Math.min(buffer.getEndIndex() - bufpos, remaining);
+            }
+            System.arraycopy(buffer.array, bufpos, cbuf, off, avail);
+            off += avail;
+            bufpos += avail;
+            remaining -= avail;
+        }
+        
+        return len;
+    }
+
+    private void fillBuffer()
+    {
+        int docAvail = docLength - docPosition;
+        try {
+            document.getText(docPosition, docAvail, buffer);
+            docPosition += (buffer.getEndIndex() - buffer.getBeginIndex());
+            bufpos = buffer.getBeginIndex();
+        }
+        catch (BadLocationException e) {}
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/DummyReflective.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/DummyReflective.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b984e5990715e5d2e6a766b8018b9df26a6d574
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/DummyReflective.java
@@ -0,0 +1,135 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.debugger.gentype.FieldReflective;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.MethodReflective;
+import bluej.debugger.gentype.Reflective;
+import bluej.utility.JavaReflective;
+
+/**
+ * This class acts as purely as an access source in TextAnalyzer. It
+ * is not a "real" reflective; it has a name, which can be used for
+ * access checks, but that's all.
+ * 
+ * @author Davin McCall
+ */
+public class DummyReflective extends Reflective
+{
+    private String name;
+    
+    public DummyReflective(String name)
+    {
+        this.name = name;
+    }
+    
+    @Override
+    public Reflective getArrayOf()
+    {
+        return null;
+    }
+
+    @Override
+    public Map<String, FieldReflective> getDeclaredFields()
+    {
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public Map<String, Set<MethodReflective>> getDeclaredMethods()
+    {
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public List<Reflective> getInners()
+    {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public Reflective getRelativeClass(String name)
+    {
+        return null;
+    }
+
+    @Override
+    public List<GenTypeClass> getSuperTypes()
+    {
+        List<GenTypeClass> l = new ArrayList<GenTypeClass>(1);
+        l.add(new GenTypeClass(new JavaReflective(Object.class)));
+        return l;
+    }
+
+    @Override
+    public List<Reflective> getSuperTypesR()
+    {
+        List<Reflective> l = new ArrayList<Reflective>(1);
+        l.add(new JavaReflective(Object.class));
+        return l;
+    }
+
+    @Override
+    public List<GenTypeDeclTpar> getTypeParams()
+    {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean isAssignableFrom(Reflective r)
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isInterface()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isPublic()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isStatic()
+    {
+        return false;
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/EditorParser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/EditorParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..95d47a01411d1c295ab48871b8eb53fdb69a2e32
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/EditorParser.java
@@ -0,0 +1,1263 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.io.Reader;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Stack;
+
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+
+import bluej.debugger.gentype.Reflective;
+import bluej.editor.moe.MoeSyntaxDocument;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.IntersectionTypeEntity;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.ParsedReflective;
+import bluej.parser.entity.PositionedResolver;
+import bluej.parser.entity.TparEntity;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.entity.UnresolvedArray;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+import bluej.parser.nodes.CommentNode;
+import bluej.parser.nodes.ContainerNode;
+import bluej.parser.nodes.DeclarationNode;
+import bluej.parser.nodes.ExpressionNode;
+import bluej.parser.nodes.FieldNode;
+import bluej.parser.nodes.ImportNode;
+import bluej.parser.nodes.InnerNode;
+import bluej.parser.nodes.JavaParentNode;
+import bluej.parser.nodes.MethodBodyNode;
+import bluej.parser.nodes.MethodNode;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+import bluej.parser.nodes.ParentParsedNode;
+import bluej.parser.nodes.ParsedCUNode;
+import bluej.parser.nodes.ParsedNode;
+import bluej.parser.nodes.ParsedTypeNode;
+import bluej.parser.nodes.PkgStmtNode;
+import bluej.parser.nodes.TypeInnerNode;
+import bluej.parser.symtab.Selection;
+
+/**
+ * Parser which builds parse node tree.
+ * 
+ * @author Davin McCall
+ */
+public class EditorParser extends JavaParser
+{
+    protected Stack<JavaParentNode> scopeStack = new Stack<JavaParentNode>();
+    private ParsedTypeNode innermostType;
+    
+    private LocatableToken pcuStmtBegin;
+    private ParsedCUNode pcuNode;
+    private List<LocatableToken> commentQueue = new LinkedList<LocatableToken>();
+    private List<LocatableToken> lastTypeSpec;
+    private FieldNode lastField;
+    private int arrayDecls;
+    private String declaredPkg = "";
+    
+    class TypeParam
+    {
+        String name;
+        List<List<LocatableToken>> bounds;
+        
+        TypeParam(String name, List<List<LocatableToken>> bounds)
+        {
+            this.name = name;
+            this.bounds = bounds;
+        }
+    }
+    
+    private List<TypeParam> typeParams;
+    private String lastTypeParamName;
+    private List<List<LocatableToken>> lastTypeParBounds;
+    
+    private List<JavaEntity> extendedTypes;
+    private List<JavaEntity> implementedTypes;
+    
+    private Document document;
+    
+    private boolean gotExtends = false;
+    private boolean gotImplements = false;
+    
+    private boolean gotNewType = true;  // whether we've seen the type in a "new TYPE(..." expression,
+        // assuming we're in such an expression. (If false, we have seen new, but not the type).
+    
+    /** Stack of types instantiated via "new ...()" expression */
+    private Stack<List<LocatableToken>> newTypes = new Stack<List<LocatableToken>>();
+    
+    private int currentModifiers = 0;
+    
+    /**
+     * Constructor for use by subclasses (InfoReader).
+     */
+    protected EditorParser(Reader r, EntityResolver resolver)
+    {
+        super(r);
+        pcuNode = new ParsedCUNode();
+        pcuNode.setParentResolver(resolver);
+    }
+    
+    /**
+     * Constructor for an EditorParser to parse a particular document.
+     * After construction the normal course of action is to call parseCU(ParsedCUNode).
+     */
+    public EditorParser(Document document)
+    {
+        super(new DocumentReader(document));
+        this.document = document;
+        //pcuNode = new ParsedCUNode(document);
+    }
+    
+    public EditorParser(Document document, Reader r, int line, int col, int pos, Stack<JavaParentNode> scopeStack)
+    {
+        super(r, line, col, pos);
+        this.document = document;
+        this.scopeStack = scopeStack;
+        pcuNode = (ParsedCUNode) scopeStack.get(0);
+    }
+    
+    /**
+     * Get the types following the "extends" keyword, if we have some. Used in incremental parsing.
+     */
+    public List<JavaEntity> getExtendedTypes()
+    {
+        return extendedTypes;
+    }
+    
+    @Override
+    protected void error(String msg, int beginLine, int beginColumn, int endLine, int endColumn)
+    {
+        // TODO make a proper listener interface
+        if (document instanceof MoeSyntaxDocument) {
+            MoeSyntaxDocument mdocument = (MoeSyntaxDocument) document;
+            Element lineEl = mdocument.getDefaultRootElement().getElement(beginLine - 1);
+            int position = lineEl.getStartOffset() + beginColumn - 1;
+            if (endLine != beginLine) {
+                lineEl = mdocument.getDefaultRootElement().getElement(endLine - 1);
+            }
+            int endPos = lineEl.getStartOffset() + endColumn - 1;
+            mdocument.parseError(position, endPos - position, msg);
+        }
+    }
+    
+    @Override
+    public void parseCU()
+    {
+        scopeStack.push(pcuNode);
+        super.parseCU();
+        scopeStack.pop();
+        completedNode(pcuNode, 0, pcuNode.getSize());
+    }
+    
+    /**
+     * Convert a line and column number to an absolute position within the document
+     * @param line  Line number (1..N)
+     * @param col   Column number (1..N)
+     * @return   The absolute position (0..N)
+     */
+    protected int lineColToPosition(int line, int col)
+    {
+        if (document == null) {
+            return 0;
+        }
+        return document.getDefaultRootElement().getElement(line - 1).getStartOffset() + col - 1;
+    }
+
+    /**
+     * Close the node which is currently at the top of the node stack.
+     * @param token     The token which finishes the node
+     * @param included  Whether the token itself is part of the node
+     */
+    private void endTopNode(LocatableToken token, boolean included)
+    {
+        int topPos = getTopNodeOffset();
+        ParsedNode top = scopeStack.pop();
+
+        int endPos;
+        if (included) {
+            endPos = lineColToPosition(token.getEndLine(), token.getEndColumn());
+        }
+        else {
+            endPos = lineColToPosition(token.getLine(), token.getColumn());
+        }
+        top.resize(endPos - topPos);
+        NodeAndPosition<ParsedNode> child = new NodeAndPosition<ParsedNode>(top, topPos, endPos - topPos);
+        scopeStack.peek().childResized(null, topPos - top.getOffsetFromParent(), child);
+        
+        completedNode(top, topPos, endPos - topPos);
+    }
+
+    /**
+     * A node end has been reached. This method adds any appropriate comment nodes as
+     * children of the new node.
+     * 
+     * @param node  The new node
+     * @param position  The absolute position of the new node
+     * @param size  The size of the new node
+     */
+    public void completedNode(ParsedNode node, int position, int size)
+    {
+        ListIterator<LocatableToken> i = commentQueue.listIterator();
+        while (i.hasNext()) {
+            LocatableToken token = i.next();
+            int startpos = lineColToPosition(token.getLine(), token.getColumn());
+            if (startpos >= position && startpos < (position + size)) {
+                int endpos = lineColToPosition(token.getEndLine(), token.getEndColumn());
+                CommentNode cn = new CommentNode(node, token);
+                node.insertNode(cn, startpos - position, endpos - startpos);
+                i.remove();
+            }
+        }
+    }
+    
+    /**
+     * Prepare to begin a new node at the given position (document position).
+     */
+    protected void beginNode(int position)
+    {
+        // If there are comments in the queue, and their position precedes that of the node
+        // just being created, then we have to create their nodes now.
+        ListIterator<LocatableToken> i = commentQueue.listIterator();
+        while (i.hasNext()) {
+            LocatableToken token = i.next();
+            int startpos = lineColToPosition(token.getLine(), token.getColumn());
+            int endpos = lineColToPosition(token.getEndLine(), token.getEndColumn());
+            if (startpos >= position) {
+                break;
+            }
+            i.remove();
+            int topOffset = getTopNodeOffset();
+            CommentNode cn = new CommentNode(scopeStack.peek(), token);
+            scopeStack.peek().insertNode(cn, startpos - topOffset, endpos - startpos);
+        }
+    }
+    
+    /**
+     * Get the start position of the top node in the scope stack.
+     */
+    protected int getTopNodeOffset()
+    {
+        Iterator<JavaParentNode> i = scopeStack.iterator();
+        if (!i.hasNext()) {
+            return 0;
+        }
+        
+        int rval = 0;
+        i.next();
+        while (i.hasNext()) {
+            rval += i.next().getOffsetFromParent();
+        }
+        return rval;
+    }
+    
+    /**
+     * Join a sequence of tokens together to form a string.
+     */
+    protected String joinTokens(List<LocatableToken> tokens)
+    {
+        StringBuffer r = new StringBuffer();
+        for (LocatableToken token : tokens) {
+            r.append(token.getText());
+        }
+        return r.toString();
+    }
+    
+    /**
+     * Get the current query source - a fully qualified class name representing
+     * the current context. (This is mainly used to determine what members of a
+     * class are accessible).
+     */
+    protected Reflective currentQuerySource()
+    {
+        ListIterator<JavaParentNode> i = scopeStack.listIterator(scopeStack.size());
+        while (i.hasPrevious()) {
+            ParsedNode pn = i.previous();
+            if (pn.getNodeType() == ParsedNode.NODETYPE_TYPEDEF) {
+                ParsedTypeNode ptn = (ParsedTypeNode)pn;
+                return new ParsedReflective(ptn);
+            }
+        }
+        
+        return null;
+    }
+    
+    
+    //  -------------- Callbacks from the superclass ----------------------
+
+    @Override
+    protected void gotModifier(LocatableToken token)
+    {
+        switch (token.getType()) {
+        case JavaTokenTypes.ABSTRACT:
+            currentModifiers |= Modifier.ABSTRACT;
+            break;
+        case JavaTokenTypes.LITERAL_private:
+            currentModifiers |= Modifier.PRIVATE;
+            break;
+        case JavaTokenTypes.LITERAL_public:
+            currentModifiers |= Modifier.PUBLIC;
+            break;
+        case JavaTokenTypes.LITERAL_protected:
+            currentModifiers |= Modifier.PROTECTED;
+            break;
+        case JavaTokenTypes.FINAL:
+            currentModifiers |= Modifier.FINAL;
+            break;
+        case JavaTokenTypes.LITERAL_synchronized:
+            currentModifiers |= Modifier.SYNCHRONIZED;
+            break;
+        case JavaTokenTypes.STRICTFP:
+            currentModifiers |= Modifier.STRICT;
+            break;
+        case JavaTokenTypes.LITERAL_native:
+            currentModifiers |= Modifier.NATIVE;
+            break;
+        case JavaTokenTypes.LITERAL_static:
+            currentModifiers |= Modifier.STATIC;
+            break;
+        default:
+        }
+    }
+    
+    @Override
+    protected void modifiersConsumed()
+    {
+        currentModifiers = 0;
+    }
+    
+    @Override
+    protected void beginPackageStatement(LocatableToken token)
+    {
+        pcuStmtBegin = token;
+    }
+    
+    @Override
+    protected void gotPackage(List<LocatableToken> pkgTokens)
+    {
+        super.gotPackage(pkgTokens);
+        declaredPkg = joinTokens(pkgTokens);
+    }
+
+    @Override
+    protected void gotImport(List<LocatableToken> tokens, boolean isStatic)
+    {
+        EntityResolver parentResolver = pcuNode.getParentResolver();
+        if (parentResolver == null) {
+            return;
+        }
+        
+        if (isStatic) {
+            // Apparently static inner classes can be imported with or without the "static" keyword
+            // So, a static import imports a field and/or method and/or class.
+            // That's right - the same import statement pulls in all three.
+            
+            // We want to pull the name out (and remove the intermediate dot)
+            int newSize = tokens.size() - 2;
+            String memberName = tokens.get(newSize + 1).getText();
+            
+            List<LocatableToken> newList = new ArrayList<LocatableToken>(newSize);
+            Iterator<LocatableToken> i = tokens.iterator();
+            while (newSize > 0) {
+                newList.add(i.next());
+                newSize--;
+            }
+            JavaEntity entity = ParseUtils.getImportEntity(parentResolver,
+                    currentQuerySource(), newList);
+            TypeEntity tentity = (entity != null) ? entity.resolveAsType() : null;
+            if (tentity != null) {
+                pcuNode.getImports().addStaticImport(memberName, tentity);
+            }
+        }
+        else {
+            String memberName = tokens.get(tokens.size() - 1).getText();
+            JavaEntity entity = ParseUtils.getImportEntity(parentResolver,
+                    currentQuerySource(), tokens);
+            if (entity != null) {
+                pcuNode.getImports().addNormalImport(memberName, entity);
+            }
+        }
+    }
+    
+    @Override
+    protected void gotWildcardImport(List<LocatableToken> tokens,
+            boolean isStatic)
+    {
+        EntityResolver parentResolver = pcuNode.getParentResolver();
+        if (parentResolver == null) {
+            return;
+        }
+
+        JavaEntity importEntity = ParseUtils.getImportEntity(parentResolver,
+                currentQuerySource(), tokens);
+        if (importEntity == null) {
+            return;
+        }
+        if (! isStatic) {
+            pcuNode.getImports().addWildcardImport(importEntity);
+        }
+        else {
+            TypeEntity tentity = importEntity.resolveAsType();
+            if (tentity != null) {
+                pcuNode.getImports().addStaticWildcardImport(tentity);
+            }
+        }
+    }
+    
+    @Override
+    protected void gotDeclBegin(LocatableToken token)
+    {
+        // This notifies us of the beginning of some sort of declaration, but we're not sure
+        // of the declaration type yet. We'll add in a placeholder node so that any child
+        // nodes (eg parts of annotations) have somewhere to go. We'll remove the placeholder
+        // node when we find out what sort of node we *really* want.
+        pcuStmtBegin = token;
+        DeclarationNode placeHolder = new DeclarationNode(scopeStack.peek());
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getLine(), token.getColumn());
+        // Note, we don't want to soak up comments yet, so we don't call beginNode(...) here.
+        scopeStack.peek().insertNode(placeHolder, insPos - curOffset, 0);
+        scopeStack.push(placeHolder);
+    }
+    
+    @Override
+    protected void endDecl(LocatableToken token)
+    {
+        // Failed declaration; just throw away the node
+        scopeStack.pop().remove();
+    }
+    
+    @Override
+    protected void gotTypeDef(LocatableToken firstToken, int tdType)
+    {
+        endDecl(firstToken); // remove placeholder
+        Reflective ref = currentQuerySource();
+        String prefix;
+        if (ref != null) {
+            prefix = ref.getName() + '$';
+        }
+        else {
+            prefix = (declaredPkg.length() == 0) ? "" : (declaredPkg + ".");
+        }
+        
+        innermostType = new ParsedTypeNode(scopeStack.peek(), innermostType, tdType, prefix, currentModifiers);
+        int curOffset = getTopNodeOffset();
+        LocatableToken hidden = firstToken.getHiddenBefore();
+        if (hidden != null && hidden.getType() == JavaTokenTypes.ML_COMMENT) {
+            firstToken = hidden;
+            innermostType.setCommentAttached(true);
+        }
+        int insPos = lineColToPosition(firstToken.getLine(), firstToken.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(innermostType, insPos - curOffset, 0);
+        scopeStack.push(innermostType);
+        initializeTypeExtras();
+    }
+    
+    /**
+     * Initialize the lists for holding type parameters, supertypes, etc.
+     */
+    public final void initializeTypeExtras()
+    {
+        typeParams = new LinkedList<TypeParam>();
+        extendedTypes = new LinkedList<JavaEntity>();
+        implementedTypes = new LinkedList<JavaEntity>();
+    }
+    
+    @Override
+    protected void gotMethodTypeParamsBegin()
+    {
+        typeParams = new LinkedList<TypeParam>();
+    }
+    
+    @Override
+    protected void gotTypeDefName(LocatableToken nameToken)
+    {
+        ParsedTypeNode tnode = (ParsedTypeNode) scopeStack.peek();
+        tnode.setName(nameToken.getText());
+    }
+    
+    @Override
+    protected void gotTypeParam(LocatableToken idToken)
+    {
+        if (lastTypeParamName != null) {
+            typeParams.add(new TypeParam(lastTypeParamName, lastTypeParBounds));
+        }
+        lastTypeParamName = idToken.getText();
+        lastTypeParBounds = new ArrayList<List<LocatableToken>>();
+    }
+    
+    @Override
+    protected void gotTypeParamBound(List<LocatableToken> tokens)
+    {
+        lastTypeParBounds.add(tokens);
+        typeParams.add(new TypeParam(lastTypeParamName, lastTypeParBounds));
+    }
+    
+    /**
+     * Get a list of the recently processed type parameters as a list of TparEntity.
+     * The given resolver must be able to resolve the type parameter names
+     * themselves before the returned type parameter entities are resolved (because
+     * type parameters may have other type parameters as bounds).
+     */
+    public final List<TparEntity> getTparList(EntityResolver resolver)
+    {
+        if (typeParams == null) {
+            return null;
+        }
+        
+        if (lastTypeParamName != null) {
+            typeParams.add(new TypeParam(lastTypeParamName, lastTypeParBounds));
+            lastTypeParamName = null;
+        }
+        
+        Reflective querySource = currentQuerySource();
+        List<TparEntity> rlist = new ArrayList<TparEntity>(typeParams.size());
+        for (TypeParam tpar : typeParams) {
+            List<JavaEntity> bounds = new ArrayList<JavaEntity>(tpar.bounds.size());
+            for (List<LocatableToken> boundTokens : tpar.bounds) {
+                bounds.add(ParseUtils.getTypeEntity(resolver, querySource, boundTokens));
+            }
+            JavaEntity boundsEnt = IntersectionTypeEntity.getIntersectionEntity(bounds, scopeStack.peek());
+            rlist.add(new TparEntity(tpar.name, boundsEnt));
+        }
+        
+        return rlist;
+    }
+    
+    @Override
+    protected void beginTypeBody(LocatableToken token)
+    {
+        ParsedTypeNode top = (ParsedTypeNode) scopeStack.peek();
+        top.setTypeParams(getTparList(top));
+        top.setExtendedTypes(extendedTypes);
+        top.setImplementedTypes(implementedTypes);
+        gotExtends = false;
+        gotImplements = false;
+        
+        TypeInnerNode bodyNode = new TypeInnerNode(scopeStack.peek());
+        bodyNode.setInner(true);
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getEndLine(), token.getEndColumn());
+        beginNode(insPos);
+        top.insertInner(bodyNode, insPos - curOffset, 0);
+        scopeStack.push(bodyNode);
+    }
+    
+    @Override
+    protected void beginForLoop(LocatableToken token)
+    {
+        JavaParentNode loopNode = new ContainerNode(scopeStack.peek(), ParsedNode.NODETYPE_ITERATION);
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getLine(), token.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(loopNode, insPos - curOffset, 0);
+        scopeStack.push(loopNode);
+    }
+    
+    @Override
+    protected void beginForLoopBody(LocatableToken token)
+    {
+        // If the token is an LCURLY, it will be seen as a compound statement and scope
+        // handling is done by beginStmtBlockBody
+        if (token.getType() != JavaTokenTypes.LCURLY) {
+            JavaParentNode loopNode = new InnerNode(scopeStack.peek());
+            loopNode.setInner(true);
+            int curOffset = getTopNodeOffset();
+            int insPos = lineColToPosition(token.getLine(), token.getColumn());
+            beginNode(insPos);
+            scopeStack.peek().insertNode(loopNode, insPos - curOffset, 0);
+            scopeStack.push(loopNode);
+        }
+    }
+    
+    @Override
+    protected void endForLoopBody(LocatableToken token, boolean included)
+    {
+        if (scopeStack.peek().getNodeType() != ParsedNode.NODETYPE_ITERATION) {
+            endTopNode(token, false);
+        }
+    }
+    
+    @Override
+    protected void beginWhileLoop(LocatableToken token)
+    {
+        JavaParentNode loopNode = new ContainerNode(scopeStack.peek(), ParsedNode.NODETYPE_ITERATION);
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getLine(), token.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(loopNode, insPos - curOffset, 0);
+        scopeStack.push(loopNode);
+    }
+    
+    @Override
+    protected void beginWhileLoopBody(LocatableToken token)
+    {
+        // If the token is an LCURLY, it will be seen as a compound statement and scope
+        // handling is done by beginStmtBlockBody
+        if (token.getType() != JavaTokenTypes.LCURLY) {
+            JavaParentNode loopNode = new InnerNode(scopeStack.peek());
+            loopNode.setInner(true);
+            int curOffset = getTopNodeOffset();
+            int insPos = lineColToPosition(token.getLine(), token.getColumn());
+            beginNode(insPos);
+            scopeStack.peek().insertNode(loopNode, insPos - curOffset, 0);
+            scopeStack.push(loopNode);
+        }
+    }
+    
+    @Override
+    protected void endWhileLoopBody(LocatableToken token, boolean included)
+    {
+        if (scopeStack.peek().getNodeType() != ParsedNode.NODETYPE_ITERATION) {
+            endTopNode(token, false);
+        }
+    }
+    
+    @Override
+    protected void beginDoWhile(LocatableToken token)
+    {
+        JavaParentNode loopNode = new ContainerNode(scopeStack.peek(), ParsedNode.NODETYPE_ITERATION);
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getLine(), token.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(loopNode, insPos - curOffset, 0);
+        scopeStack.push(loopNode);
+    }
+    
+    @Override
+    protected void beginDoWhileBody(LocatableToken token)
+    {
+        // If the token is an LCURLY, it will be seen as a compound statement and scope
+        // handling is done by beginStmtBlockBody
+        if (token.getType() != JavaTokenTypes.LCURLY) {
+            JavaParentNode loopNode = new InnerNode(scopeStack.peek());
+            loopNode.setInner(true);
+            int curOffset = getTopNodeOffset();
+            int insPos = lineColToPosition(token.getLine(), token.getColumn());
+            beginNode(insPos);
+            scopeStack.peek().insertNode(loopNode, insPos - curOffset, 0);
+            scopeStack.push(loopNode);
+        }
+    }
+    
+    @Override
+    protected void endDoWhileBody(LocatableToken token, boolean included)
+    {
+        if (scopeStack.peek().getNodeType() != ParsedNode.NODETYPE_ITERATION) {
+            endTopNode(token, false);
+        }
+    }
+        
+    @Override
+    protected void beginIfStmt(LocatableToken token)
+    {
+        JavaParentNode loopNode = new ContainerNode(scopeStack.peek(), ParsedNode.NODETYPE_SELECTION);
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getLine(), token.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(loopNode, insPos - curOffset, 0);
+        scopeStack.push(loopNode);
+    }
+    
+    @Override
+    protected void beginIfCondBlock(LocatableToken token)
+    {
+        // If the token is an LCURLY, it will be seen as a compound statement and scope
+        // handling is done by beginStmtBlockBody
+        if (token.getType() != JavaTokenTypes.LCURLY) {
+            JavaParentNode loopNode = new InnerNode(scopeStack.peek());
+            loopNode.setInner(true);
+            int curOffset = getTopNodeOffset();
+            int insPos = lineColToPosition(token.getLine(), token.getColumn());
+            beginNode(insPos);
+            scopeStack.peek().insertNode(loopNode, insPos - curOffset, 0);
+            scopeStack.push(loopNode);
+        }
+    }
+    
+    @Override
+    protected void endIfCondBlock(LocatableToken token, boolean included)
+    {
+        if (scopeStack.peek().getNodeType() != ParsedNode.NODETYPE_SELECTION) {
+            endTopNode(token, false);
+        }
+    }
+    
+    @Override
+    protected void endIfStmt(LocatableToken token, boolean included)
+    {
+        endTopNode(token, included);
+    }
+
+    @Override
+    protected void beginSwitchStmt(LocatableToken token)
+    {
+        beginIfStmt(token);
+    }
+    
+    @Override
+    protected void beginSwitchBlock(LocatableToken token)
+    {
+        JavaParentNode loopNode = new InnerNode(scopeStack.peek());
+        loopNode.setInner(true);
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getEndLine(), token.getEndColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(loopNode, insPos - curOffset, 0);
+        scopeStack.push(loopNode);
+    }
+    
+    @Override
+    protected void endSwitchBlock(LocatableToken token)
+    {
+        endTopNode(token, false);
+    }
+    
+    @Override
+    protected void endSwitchStmt(LocatableToken token, boolean included)
+    {
+        endTopNode(token, included);
+    }
+    
+    @Override
+    protected void beginTryCatchSmt(LocatableToken token)
+    {
+        JavaParentNode tryNode = new ContainerNode(scopeStack.peek(), ParsedNode.NODETYPE_SELECTION);
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getLine(), token.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(tryNode, insPos - curOffset, 0);
+        scopeStack.push(tryNode);
+    }
+    
+    @Override
+    protected void beginTryBlock(LocatableToken token)
+    {
+        JavaParentNode tryBlockNode = new InnerNode(scopeStack.peek());
+        tryBlockNode.setInner(true);
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getEndLine(), token.getEndColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(tryBlockNode, insPos - curOffset, 0);
+        scopeStack.push(tryBlockNode);
+    }
+    
+    @Override
+    protected void endTryBlock(LocatableToken token, boolean included)
+    {
+        endTopNode(token, false);
+    }
+    
+    @Override
+    protected void endTryCatchStmt(LocatableToken token, boolean included)
+    {
+        endTopNode(token, included);
+    }
+    
+    @Override
+    protected void beginStmtblockBody(LocatableToken token)
+    {
+        int curOffset = getTopNodeOffset();
+        if (! scopeStack.peek().isContainer()) {
+            // This is conditional, because the outer block may be a loop or selection
+            // statement which already exists.
+            JavaParentNode blockNode = new ContainerNode(scopeStack.peek(), ParsedNode.NODETYPE_NONE);
+            blockNode.setInner(false);
+            int insPos = lineColToPosition(token.getLine(), token.getColumn());
+            beginNode(insPos);
+            scopeStack.peek().insertNode(blockNode, insPos - curOffset, 0);
+            scopeStack.push(blockNode);
+            curOffset = insPos;
+        }
+        JavaParentNode blockInner = new InnerNode(scopeStack.peek());
+        blockInner.setInner(true);
+        int insPos = lineColToPosition(token.getEndLine(), token.getEndColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(blockInner, insPos - curOffset, 0);
+        scopeStack.push(blockInner);
+    }
+   
+    @Override
+    protected void endStmtblockBody(LocatableToken token, boolean included)
+    {
+        endTopNode(token, false); // inner
+        if (scopeStack.peek().getNodeType() == ParsedNode.NODETYPE_NONE) {
+            endTopNode(token, included);
+        }
+    }
+    
+    @Override
+    protected void beginSynchronizedBlock(LocatableToken token)
+    {
+        JavaParentNode tryNode = new ContainerNode(scopeStack.peek(), ParsedNode.NODETYPE_NONE);
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getLine(), token.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(tryNode, insPos - curOffset, 0);
+        scopeStack.push(tryNode);
+    }
+    
+    @Override
+    protected void beginInitBlock(LocatableToken first, LocatableToken lcurly)
+    {
+        endDecl(first); // remove placeholder node
+        int curOffset = getTopNodeOffset();
+        JavaParentNode blockNode = new ContainerNode(scopeStack.peek(), ParsedNode.NODETYPE_NONE);
+        blockNode.setInner(false);
+        int insPos = lineColToPosition(first.getLine(), first.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(blockNode, insPos - curOffset, 0);
+        scopeStack.push(blockNode);
+        curOffset = insPos;
+
+        JavaParentNode blockInner = new InnerNode(scopeStack.peek());
+        blockInner.setInner(true);
+        insPos = lineColToPosition(lcurly.getEndLine(), lcurly.getEndColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(blockInner, insPos - curOffset, 0);
+        scopeStack.push(blockInner);
+    }
+    
+    @Override
+    protected void endInitBlock(LocatableToken rcurly, boolean included)
+    {
+        endStmtblockBody(rcurly, included);
+    }
+    
+    @Override
+    protected void beginElement(LocatableToken token)
+    {
+        pcuStmtBegin = token;
+    }
+    
+    @Override
+    protected void endTypeBody(LocatableToken token, boolean included)
+    {
+        endTopNode(token, false);
+    }
+    
+    @Override
+    protected void gotTypeDefEnd(LocatableToken token, boolean included)
+    {
+        endTopNode(token, included);
+        innermostType = innermostType.getContainingClass();
+        gotExtends = false;
+        gotImplements = false;
+    }
+    
+    @Override
+    protected void endForLoop(LocatableToken token, boolean included)
+    {
+        endTopNode(token, included);
+    }
+    
+    @Override
+    protected void endWhileLoop(LocatableToken token, boolean included)
+    {
+        endTopNode(token, included);
+    }
+    
+    @Override
+    protected void endDoWhile(LocatableToken token, boolean included)
+    {
+        endTopNode(token, included);
+    }
+
+    /*
+     * We have the end of a package statement.
+     */
+    @Override
+    protected void gotPackageSemi(LocatableToken token)
+    {
+        Selection s = new Selection(pcuStmtBegin.getLine(), pcuStmtBegin.getColumn());
+        s.extendEnd(token.getLine(), token.getColumn() + token.getLength());
+        
+        int startpos = lineColToPosition(s.getLine(), s.getColumn());
+        int endpos = lineColToPosition(s.getEndLine(), s.getEndColumn());
+        
+        PkgStmtNode psn = new PkgStmtNode(pcuNode);
+        beginNode(startpos);
+        pcuNode.insertNode(psn, startpos, endpos - startpos);
+        completedNode(psn, startpos, endpos - startpos);
+    }
+    
+    @Override
+    protected void gotImportStmtSemi(LocatableToken token)
+    {
+        Selection s = new Selection(pcuStmtBegin.getLine(), pcuStmtBegin.getColumn());
+        s.extendEnd(token.getLine(), token.getColumn() + token.getLength());
+        
+        int startpos = lineColToPosition(s.getLine(), s.getColumn());
+        int endpos = lineColToPosition(s.getEndLine(), s.getEndColumn());
+        
+        ParentParsedNode cn = new ImportNode(pcuNode);
+        cn.setComplete(true);
+        beginNode(startpos);
+        pcuNode.insertNode(cn, startpos, endpos - startpos);
+        completedNode(cn, startpos, endpos - startpos);
+    }
+    
+    @Override
+    public void gotComment(LocatableToken token)
+    {
+        commentQueue.add(token);
+    }
+    
+    @Override
+    protected void gotConstructorDecl(LocatableToken token,
+            LocatableToken hiddenToken)
+    {
+        endDecl(token); // remove placeholder
+        LocatableToken start = pcuStmtBegin;
+        String jdcomment = null;
+        if (hiddenToken != null) {
+            start = hiddenToken;
+            jdcomment = hiddenToken.getText();
+        }
+        
+        MethodNode pnode = new MethodNode(scopeStack.peek(), token.getText(), jdcomment);
+        pnode.setModifiers(currentModifiers);
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(start.getLine(), start.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(pnode, insPos - curOffset, 0);
+        scopeStack.push(pnode);
+    }
+    
+    @Override
+    protected void gotMethodDeclaration(LocatableToken token,
+            LocatableToken hiddenToken)
+    {
+        endDecl(token); // remove placeholder
+        LocatableToken start = pcuStmtBegin;
+        String jdcomment = null;
+        if (hiddenToken != null) {
+            start = hiddenToken;
+            jdcomment = hiddenToken.getText();
+        }
+        
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(start.getLine(), start.getColumn());
+
+        MethodNode pnode = new MethodNode(scopeStack.peek(), token.getText(), jdcomment);
+        JavaEntity returnType = ParseUtils.getTypeEntity(pnode, currentQuerySource(), lastTypeSpec);
+        pnode.setReturnType(returnType);
+        pnode.setModifiers(currentModifiers);
+        pnode.setTypeParams(getTparList(pnode));
+        typeParams = null;
+        
+        beginNode(insPos);
+        scopeStack.peek().insertNode(pnode, insPos - curOffset, 0);
+        scopeStack.push(pnode);
+    }
+    
+    @Override
+    protected void gotMethodParameter(LocatableToken token, LocatableToken ellipsisToken)
+    {
+        JavaEntity paramType = ParseUtils.getTypeEntity(scopeStack.peek(),
+                currentQuerySource(), lastTypeSpec);
+        if (paramType == null) {
+            return;
+        }
+        while (arrayDecls-- > 0) {
+            paramType = new UnresolvedArray(paramType);
+        }
+        MethodNode mNode = (MethodNode) scopeStack.peek();
+        if (ellipsisToken != null) {
+            mNode.setVarArgs(true);
+            paramType = new UnresolvedArray(paramType);            
+        }
+        mNode.addParameter(token.getText(), paramType);
+    }
+    
+    @Override
+    protected void endMethodDecl(LocatableToken token, boolean included)
+    {
+        MethodNode mNode = (MethodNode) scopeStack.peek();
+        mNode.setComplete(included);
+        endTopNode(token, included);
+        TypeInnerNode topNode = (TypeInnerNode) scopeStack.peek();
+        topNode.methodAdded(mNode);
+    }
+    
+    @Override
+    protected void beginMethodBody(LocatableToken token)
+    {
+        JavaParentNode pnode = new MethodBodyNode(scopeStack.peek());
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(token.getEndLine(), token.getEndColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(pnode, insPos - curOffset, 0);
+        scopeStack.push(pnode);
+    }
+    
+    @Override
+    protected void endMethodBody(LocatableToken token, boolean included)
+    {
+        scopeStack.peek().setComplete(included);
+        endTopNode(token, false);
+    }
+    
+    @Override
+    protected void gotExprNew(LocatableToken token)
+    {
+        gotNewType = false;
+    }
+    
+    @Override
+    protected void endExprNew(LocatableToken token, boolean included)
+    {
+        if (gotNewType) {
+            // We have a type on the top of the stack
+            newTypes.pop();
+        }
+        gotNewType = true; // outer "new" has type
+    }
+    
+    @Override
+    protected void gotTypeSpec(List<LocatableToken> tokens)
+    {
+        if (gotExtends) {
+            JavaEntity supert = ParseUtils.getTypeEntity(scopeStack.peek(), currentQuerySource(), tokens);
+            if (supert != null) {
+                extendedTypes.add(supert);
+            }
+        }
+        else if (gotImplements) {
+            JavaEntity supert = ParseUtils.getTypeEntity(scopeStack.peek(), currentQuerySource(), tokens);
+            if (supert != null) {
+                implementedTypes.add(supert);
+            }
+        }
+        else if (! gotNewType) {
+            gotNewType = true;
+            newTypes.push(tokens);
+        }
+        else {
+            lastTypeSpec = tokens;
+            arrayDecls = 0;
+        }
+    }
+    
+    @Override
+    protected void gotArrayDeclarator()
+    {
+        arrayDecls++;
+    }
+        
+    @Override
+    protected void beginFieldDeclarations(LocatableToken first)
+    {
+        arrayDecls = 0;
+        endDecl(first); // remove placeholder
+    }
+    
+    @Override
+    protected void gotField(LocatableToken first, LocatableToken idToken)
+    {
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(first.getLine(), first.getColumn());
+        EntityResolver resolver = new PositionedResolver(scopeStack.peek(), insPos - curOffset);
+        JavaEntity fieldType = ParseUtils.getTypeEntity(resolver,
+                currentQuerySource(), lastTypeSpec);
+        
+        lastField = new FieldNode(scopeStack.peek(), idToken.getText(), fieldType,
+                arrayDecls, currentModifiers);
+        arrayDecls = 0;
+        beginNode(insPos);
+        
+        if (fieldType != null) {
+            JavaParentNode top = scopeStack.peek();
+            top.insertField(lastField, insPos - curOffset, 0);
+        }
+        else {
+            scopeStack.peek().insertNode(lastField, insPos - curOffset, 0);
+        }
+        
+        scopeStack.push(lastField);
+    }
+    
+    @Override
+    protected void gotSubsequentField(LocatableToken first,
+            LocatableToken idToken)
+    {
+        FieldNode field = new FieldNode(scopeStack.peek(), idToken.getText(), lastField, arrayDecls);
+        arrayDecls = 0;
+        int curOffset = getTopNodeOffset();
+        int insPos = lineColToPosition(first.getLine(), first.getEndColumn());
+        beginNode(insPos);
+        
+        if (lastField.getFieldType() != null) {
+            JavaParentNode top = scopeStack.peek();
+            top.insertField(field, insPos - curOffset, 0);
+        }
+        else {
+            scopeStack.peek().insertNode(field, insPos - curOffset, 0);
+        }
+        
+        scopeStack.push(field);
+    }
+    
+    @Override
+    protected void endField(LocatableToken token, boolean included)
+    {
+        endTopNode(token, included);
+    }
+    
+    // Variables can be treated exactly like fields:
+    
+    @Override
+    protected void beginVariableDecl(LocatableToken first)
+    {
+        beginFieldDeclarations(first);
+    }
+    
+    @Override
+    protected void gotVariableDecl(LocatableToken first, LocatableToken idToken, boolean inited)
+    {
+        gotField(first, idToken);
+    }
+    
+    @Override
+    protected void gotSubsequentVar(LocatableToken first, LocatableToken idToken, boolean inited)
+    {
+        gotSubsequentField(first, idToken);
+    }
+    
+    @Override
+    protected void endVariable(LocatableToken token, boolean included)
+    {
+        endField(token, included);
+    }
+    
+    // For-initializers are like variables/fields
+    
+    @Override
+    protected void beginForInitDecl(LocatableToken first)
+    {
+        arrayDecls = 0;
+    }
+    
+    @Override
+    protected void gotForInit(LocatableToken first, LocatableToken idToken)
+    {
+        gotField(first, idToken);
+    }
+    
+    @Override
+    protected void gotSubsequentForInit(LocatableToken first,
+            LocatableToken idToken)
+    {
+        gotSubsequentField(first, idToken);
+    }
+    
+    @Override
+    protected void endForInit(LocatableToken token, boolean included)
+    {
+        endField(token, included);
+    }
+    
+    @Override
+    protected void beginAnonClassBody(LocatableToken token, boolean isEnumMember)
+    {
+        ParsedTypeNode pnode = new ParsedTypeNode(scopeStack.peek(), innermostType,
+                JavaParser.TYPEDEF_CLASS, null, 0); // TODO generate Abc$1 ?
+                
+        innermostType = pnode;
+        int curOffset = getTopNodeOffset();
+        LocatableToken begin = token;
+        int insPos = lineColToPosition(begin.getLine(), begin.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(pnode, insPos - curOffset, 0);
+        scopeStack.push(pnode);
+        
+        JavaEntity supert;
+        if (! isEnumMember) {
+            EntityResolver resolver = new PositionedResolver(scopeStack.peek(), insPos - curOffset);
+            supert = ParseUtils.getTypeEntity(resolver, currentQuerySource(), newTypes.peek());
+        }
+        else {
+            supert = new TypeEntity(new ParsedReflective(innermostType));
+        }
+        List<JavaEntity> superts = new ArrayList<JavaEntity>(1);
+        superts.add(supert);
+        pnode.setExtendedTypes(superts);
+        
+        TypeInnerNode bodyNode = new TypeInnerNode(scopeStack.peek());
+        bodyNode.setInner(true);
+        curOffset = getTopNodeOffset();
+        insPos = lineColToPosition(token.getEndLine(), token.getEndColumn());
+        beginNode(insPos);
+        pnode.insertInner(bodyNode, insPos - curOffset, 0);
+        scopeStack.push(bodyNode);
+    }
+    
+    @Override
+    protected void endAnonClassBody(LocatableToken token, boolean included)
+    {
+        endTopNode(token, false);  // inner node
+        endTopNode(token, included);  // outer node
+        innermostType = innermostType.getContainingClass();
+    }
+    
+    @Override
+    protected void beginExpression(LocatableToken token)
+    {
+        ExpressionNode nnode = new ExpressionNode(scopeStack.peek());
+        int curOffset = getTopNodeOffset();
+        LocatableToken begin = token;
+        int insPos = lineColToPosition(begin.getLine(), begin.getColumn());
+        beginNode(insPos);
+        scopeStack.peek().insertNode(nnode, insPos - curOffset, 0);
+        scopeStack.push(nnode);
+    }
+    
+    @Override
+    protected void endExpression(LocatableToken token, boolean isEmpty)
+    {
+        endTopNode(token, false);
+        arrayDecls = 0;
+    }
+
+    @Override
+    protected void gotTypeDefExtends(LocatableToken extendsToken)
+    {
+        gotExtends = true;
+        gotImplements = false;
+    }
+    
+    @Override
+    protected void gotTypeDefImplements(LocatableToken implementsToken)
+    {
+        gotImplements = true;
+        gotExtends = false;
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/EscapedUnicodeReader.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/EscapedUnicodeReader.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6ba746d70df3e5131aa22b4e569a0800dae9501
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/EscapedUnicodeReader.java
@@ -0,0 +1,212 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * This is a Reader processes the stream from another reader, replacing unicode escape
+ * sequences (backslash-'u'-XXXX where XXXX is a four digit hexadecimal number) with the
+ * characters they represent.
+ * 
+ * This is suitable for a java pre-processor, before the lexer stage. It allows the lexer
+ * to correctly recognize keywords, identifiers etc. which have embedded unicode escape
+ * sequences.
+ * 
+ * @author Davin McCall
+ */
+public final class EscapedUnicodeReader extends Reader
+{
+    Reader sourceReader;
+
+    private boolean charIsBuffered;
+    private int bufferedChar;
+    
+    private int position; // position within source stream
+    private int line = 1;
+    private int column = 1;
+
+
+    public EscapedUnicodeReader(Reader source)
+    {
+        sourceReader = source;
+    }
+    
+    public void setLineColPos(int line, int column, int position)
+    {
+        this.line = line;
+        this.column = column;
+        this.position = position;
+    }
+
+    public int read(char [] buffer, int off, int len) throws IOException
+    {
+        int numRead = 0;
+        while (len > 0) {
+            try {
+                int r = getChar();
+                if (r == -1)
+                    break;
+                buffer[off++] = (char) r;
+                len--;
+                numRead++;
+            }
+            catch (IOException ioe) {
+                // If we got an exception, but successfully read some characters,
+                // we should return those characters.
+                if (numRead == 0) {
+                    throw ioe;
+                }
+                else { 
+                    break;
+                }
+            }
+        }
+
+        // if we failed to read anything, it's due to end-of-stream
+        if (numRead == 0 && len != 0)
+            numRead = -1;
+
+        return numRead;
+    }
+
+    public void close() throws IOException
+    {
+        sourceReader.close();
+    }
+
+    /**
+     * Get a single character, which may be an escaped unicode character (\\uXXXX, with a
+     * single leading backslash)
+     */
+    private int getChar() throws IOException
+    {
+        int rchar;
+        if (charIsBuffered) {
+            charIsBuffered = false;
+            if (bufferedChar != -1) {
+                processChar((char) bufferedChar);
+            }
+            return bufferedChar;
+        }
+        else {
+            rchar = readSourceChar();
+        }
+
+        if (rchar == '\\') {
+            // This could be the beginning of an escaped unicode sequence,
+            // \\uXXXX (with only a single backslash)
+            int nchar = sourceReader.read();
+
+            if (nchar == 'u') {
+                column++; position++;
+                return readEscapedUnicodeSequence();
+            }
+            else {
+                putBuffer(nchar);             
+                return '\\';
+            }
+        }
+
+        return rchar;
+    }
+
+    private void putBuffer(int nchar)
+    {
+        bufferedChar = nchar;
+        charIsBuffered = true;
+    }
+
+    private int readEscapedUnicodeSequence() throws IOException
+    {
+        // The Java Language Spec specifies that any number of 'u' characters may appear in sequence
+        // as part of a unicode escape.
+        int uc = sourceReader.read();
+        while (uc == 'u') {
+            processChar((char)uc);
+            uc = sourceReader.read();
+        }
+        
+        int val = Character.digit((char) uc, 16);
+        if (val == -1) {
+            putBuffer(uc);
+            return 0xFFFF;
+        }
+        processChar((char)uc);
+        
+        int i = 0;
+        do {
+            val *= 0x10;
+            uc = sourceReader.read();
+            int digitVal = Character.digit((char) uc, 16);
+            if (digitVal == -1) {
+                putBuffer(uc);
+                return 0xFFFF;
+            }
+            processChar((char)uc);
+            val += digitVal;
+            i++;
+        } while (i < 3);
+        
+        return val;
+    }
+
+    private int readSourceChar() throws IOException
+    {
+        int rchar = sourceReader.read();
+        if (rchar != -1) {
+            processChar((char) rchar);
+        }
+        return rchar;
+    }
+    
+    private void processChar(char ch)
+    {
+        position++;
+        if (ch == '\n') {
+            line++;
+            column = 1;
+        }
+        else {
+            column++;
+        }
+    }
+    
+    /**
+     * Get the position within the source stream (i.e. number of characters read).
+     */
+    public int getPosition()
+    {
+        return position;
+    }
+
+    public int getLine()
+    {
+        return line;
+    }
+
+    public int getColumn()
+    {
+        return column;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/ImportsCollection.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/ImportsCollection.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9661079a1d06cb2f5e33531878b1b25469c7fc4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/ImportsCollection.java
@@ -0,0 +1,274 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import bluej.Config;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.PackageOrClass;
+import bluej.parser.entity.TypeEntity;
+
+/**
+ * Maintain and manage a collection of import statements.
+ * 
+ * @author Davin McCall
+ */
+public class ImportsCollection
+{
+    /** non-wildcard non-static type imports. the entities should resolve to types. */
+    private Map<String,JavaEntity> normalImports;
+    /** non-static wildcard imports. The entities should resolve to PackageOrClass */
+    private List<JavaEntity> wildcardImports;
+    /** static wildcard imports. The entities should resolve to types. */
+    private List<JavaEntity> staticWildcardImports; // list of TypeEntity
+    private Map<String,List<JavaEntity>> staticImports; // The String gives
+                                // the name of the imported static member(s) from the given
+                                // class(es).
+    
+    public ImportsCollection()
+    {
+        normalImports = new HashMap<String,JavaEntity>();
+        wildcardImports = new ArrayList<JavaEntity>();
+        staticWildcardImports = new ArrayList<JavaEntity>(); 
+        staticImports = new HashMap<String,List<JavaEntity>>();
+    }
+    
+    /**
+     * Remove all imports from the collection.
+     */
+    public void clear()
+    {
+        normalImports.clear();
+        wildcardImports.clear();
+    }
+    
+    /**
+     * Add a (non-wildcard) import to the collection.
+     * @param name          The short name of the import
+     * @param importEntity  The entity corresponding to the imported type
+     */
+    public void addNormalImport(String name, JavaEntity importEntity)
+    {
+        normalImports.put(name, importEntity);
+    }
+    
+    /**
+     * Add a wildcard import to the collection.
+     * @param importEntity  The entity representing the import excluding the final '*' part.
+     */
+    public void addWildcardImport(JavaEntity importEntity)
+    {
+        wildcardImports.add(importEntity);
+    }
+    
+    /**
+     * Add a static (non-wildcard) import to the collection.
+     * @param name           The name of the imported member(s)
+     * @param importEntity   The class from which members are imported
+     */
+    public void addStaticImport(String name, JavaEntity importEntity)
+    {
+        List<JavaEntity> l = staticImports.get(name);
+        if (l == null) {
+            l = new ArrayList<JavaEntity>();
+            staticImports.put(name, l);
+        }
+        l.add(importEntity);
+    }
+    
+    /**
+     * Add a static wildcard import to the collection.
+     * @param importEntity  The class from which members are imported
+     */
+    public void addStaticWildcardImport(TypeEntity importEntity)
+    {
+        staticWildcardImports.add(importEntity);
+    }
+    
+    /**
+     * Try to find an imported type. Does not check wildcard imports (see 
+     * getTypeImportWC). Returns null if no imported type with the given
+     * name exists.
+     * @param name  The name of the imported type to retrieve
+     * @return      A TypeEntity representing the type
+     */
+    public TypeEntity getTypeImport(String name)
+    {
+        // See if there is a normal import for the given name
+        JavaEntity r = normalImports.get(name);
+        if (r != null)
+            return r.resolveAsType();
+        
+        // There might be a suitable static import
+        List<JavaEntity> l = staticImports.get(name);
+        if (l != null) {
+            Iterator<JavaEntity> i = l.iterator();
+            while (i.hasNext()) {
+                TypeEntity rt = i.next().resolveAsType();
+                if (rt == null) {
+                    continue;
+                }
+                rt = (TypeEntity) rt.getPackageOrClassMember(name);
+                if (rt != null) {
+                    return rt;
+                }
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Retrieve all the static import classes for a given import name. The
+     * returned list must not be modified.
+     * 
+     * @param name  The name of the import to retrieve.
+     */
+    public List<JavaEntity> getStaticImports(String name)
+    {
+        List<JavaEntity> l = staticImports.get(name);
+        if (l == null) {
+            l = Collections.emptyList();
+        }
+        return l;
+    }
+    
+    /**
+     * Retrieve a list of all the static wildcard imports.
+     * @return  A List of TypeEntity
+     */
+    public List<JavaEntity> getStaticWildcardImports()
+    {
+        return staticWildcardImports;
+    }
+    
+    /**
+     * Try to find a type accessible via a wildcard import.
+     * Return null if no such type can be found.
+     * @param name  The name of the imported type to find
+     * @return      A TypeEntity, or null if not found
+     */
+    public TypeEntity getTypeImportWC(String name)
+    {
+        // Try non-static wildcard imports first
+        Iterator<JavaEntity> i = wildcardImports.iterator();
+        
+        while (i.hasNext()) {
+            JavaEntity entity = i.next();
+            PackageOrClass importEntity = entity.resolveAsPackageOrClass();
+            if (importEntity == null) {
+                continue;
+            }
+            PackageOrClass member = importEntity.getPackageOrClassMember(name);
+            if (member == null) {
+                continue;
+            }
+            TypeEntity clMember = member.resolveAsType();
+            if (clMember != null) {
+                return clMember;
+            }
+        }
+        
+        // Now try static wildcard imports
+        Iterator<JavaEntity> j = staticWildcardImports.iterator();
+        while (j.hasNext()) {
+            TypeEntity importEntity = j.next().resolveAsType();
+            if (importEntity == null) {
+                continue;
+            }
+            GenTypeClass clType = importEntity.getClassType();
+            if (clType != null) {
+                List<Reflective> inners = clType.getReflective().getInners();
+                for (Reflective inner : inners) {
+                    String innerName = inner.getName();
+                    innerName = innerName.substring(innerName.lastIndexOf('$'));
+                    if (name.equals(innerName)) {
+                        return new TypeEntity(new GenTypeClass(inner));
+                    }
+                }
+            }
+        }
+        
+        return null;
+    }
+    
+    /*
+     * Convert the imports collection to a series of java "import" statements.
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        String rr = "";
+        
+        // First process the normal (non-wildcard non-static) imports
+        Iterator<? extends JavaEntity> i = normalImports.values().iterator();
+        while (i.hasNext()) {
+            // String importName = ()
+            JavaEntity importEntity = i.next();
+            
+            // build the statement string
+            rr += "import ";
+            rr += importEntity.getName() + ";" + Config.nl;
+        }
+        
+        // Now do the (non-static) wildcard imports
+        i = wildcardImports.iterator();
+        while (i.hasNext()) {
+            PackageOrClass importEntity = (PackageOrClass) i.next();
+            rr += "import ";
+            rr += importEntity.getName() + ".*;" + Config.nl;
+        }
+        
+        // Now the static imports (non-wildcard)
+        Iterator<String> ii = staticImports.keySet().iterator();
+        while (ii.hasNext()) {
+            String importName = ii.next();
+            List<JavaEntity> l = staticImports.get(importName);
+            Iterator<JavaEntity> j = l.iterator();
+            while (j.hasNext()) {
+                TypeEntity importEntity = j.next().resolveAsType();
+                if (importEntity != null) {
+                    rr += "import static " + importEntity.getName();
+                    rr += "." + importName + ";" + Config.nl;
+                }
+            }
+        }
+        
+        // Finally the wildcard static imports
+        Iterator<JavaEntity> iii = staticWildcardImports.iterator();
+        while (i.hasNext()) {
+            JavaEntity importEntity = iii.next();
+            rr += "import static " + importEntity.getName();
+            rr += ".*;" + Config.nl;
+        }
+        
+        return rr;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/InfoParser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/InfoParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..70be3545c052489d4f03e1cfa24038d885e64021
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/InfoParser.java
@@ -0,0 +1,700 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.GenTypeSolid;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.entity.ClassLoaderResolver;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.PackageResolver;
+import bluej.parser.entity.PositionedResolver;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.entity.UnresolvedArray;
+import bluej.parser.entity.UnresolvedEntity;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+import bluej.parser.nodes.JavaParentNode;
+import bluej.parser.nodes.MethodNode;
+import bluej.parser.symtab.ClassInfo;
+import bluej.parser.symtab.Selection;
+import bluej.pkgmgr.Package;
+import bluej.utility.JavaNames;
+
+/**
+ * The main BlueJ parser, which extracts various information from source code including:
+ * <ul>
+ * <li> The name of the class
+ * <li> The superclass
+ * <li> Any implemented interfaces
+ * <li> Constructor and method signatures, including parameter names and javadoc comments
+ * </ul>
+ * 
+ * <p>For most of the useful information that the InfoParser discovers, it needs to resolve
+ * names against an EntityResolver which must be supplied. If no resolver is supplied the InfoParser
+ * does little other than check for parse failure.
+ * 
+ * @author Davin McCall
+ */
+public class InfoParser extends EditorParser
+{
+    private String targetPkg;
+    private ClassInfo info;
+    private int classLevel = 0; // number of nested classes
+    private boolean isPublic;
+    private boolean isAbstract;
+    private int lastTdType; // last typedef type (TYPEDEF_CLASS, _INTERFACE etc)
+    private boolean storeCurrentClassInfo;
+    private int arrayCount = 0;
+
+    private List<LocatableToken> lastTypespecToks;
+    private boolean modPublic = false;
+    private boolean modAbstract = false;
+    private List<MethodDesc> methodDescs = new LinkedList<MethodDesc>();
+    private MethodDesc currentMethod;
+    
+    private JavaEntity superclassEntity;
+    
+    private List<JavaEntity> interfaceEntities;
+    //private List<Selection> interfaceSelections;
+    
+    /** Represents a method description */
+    class MethodDesc
+    {
+        String name;
+        JavaEntity returnType; // null for constructors
+        List<JavaEntity> paramTypes;
+        String paramNames; // space separated list
+        String javadocText;
+    }
+    
+    /** Represents an unresolved value identifier expression */
+    class UnresolvedVal
+    {
+        List<LocatableToken> components;
+        JavaParentNode resolver;
+        Reflective accessSource;
+        int accessPosition;
+    }
+    
+    private List<JavaEntity> typeReferences = new LinkedList<JavaEntity>();
+    private List<UnresolvedVal> valueReferences = new LinkedList<UnresolvedVal>();
+    private UnresolvedVal currentUnresolvedVal;
+    
+    private boolean gotExtends; // next type spec is the superclass/superinterfaces
+    private boolean gotImplements; // next type spec(s) are interfaces
+    private List<Selection> interfaceSelections;
+    private Selection lastCommaSelection;
+
+    private boolean hadError;
+
+    private LocatableToken pkgLiteralToken;
+    private List<LocatableToken> packageTokens;
+    private LocatableToken pkgSemiToken;
+
+    /**
+     * Construct an InfoParser which reads Java source using the given reader, and resolves
+     * reference via the given resolver.
+     */
+    public InfoParser(Reader r, EntityResolver resolver)
+    {
+        super(r, resolver);
+    }
+
+    /**
+     * Attempt to parse the specified source file. Returns null if the file could not be parsed.
+     */
+    public static ClassInfo parse(File f) throws FileNotFoundException
+    {
+        return parse(f, new ClassLoaderResolver(InfoParser.class.getClassLoader()));
+    }
+    
+    /**
+     * Attempt to parse the specified source file, and resolve references via the specified
+     * resolver. Returns null if the file could not be parsed.
+     */
+    public static ClassInfo parse(File f, EntityResolver resolver) throws FileNotFoundException
+    {
+        FileInputStream fis = new FileInputStream(f);
+        ClassInfo info = parse(new BufferedReader(new InputStreamReader(fis)), resolver, null);
+        try {
+            fis.close();
+        }
+        catch (IOException ioe) {}
+        return info;
+    }
+    
+    /**
+     * Attempt to parse the specified source file, and resolve references via the specified
+     * package (and its project). Returns null if the file could not be parsed.
+     */
+    public static ClassInfo parse(File f, Package pkg) throws FileNotFoundException
+    {
+        FileInputStream fis = new FileInputStream(f);
+        EntityResolver resolver = new PackageResolver(pkg.getProject().getEntityResolver(),
+                pkg.getQualifiedName());
+        Reader reader = new InputStreamReader(fis, pkg.getProject().getProjectCharset());
+        reader = new BufferedReader(reader);
+        ClassInfo info = parse(reader, resolver, pkg.getQualifiedName());
+        try {
+            fis.close();
+        }
+        catch (IOException ioe) {}
+        return info;
+    }
+
+    /**
+     * Attempt to parse the specified source file, and resolve references via the specified
+     * resolver. The source should be assumed to reside in the specified package.
+     * Returns null if the source could not be parsed.
+     */
+    public static ClassInfo parse(Reader r, EntityResolver resolver, String targetPkg)
+    {
+        InfoParser infoParser = null;
+        infoParser = new InfoParser(r, resolver);
+        infoParser.targetPkg = targetPkg;
+        infoParser.parseCU();
+
+        if (infoParser.info != null) {
+            infoParser.info.setParseError(infoParser.hadError);
+            infoParser.resolveComments();
+            return infoParser.info;
+        }
+        else {
+            return null;
+        }
+    }
+    
+    /**
+     * All type references and method declarations are unresolved after parsing.
+     * Call this method to resolve them.
+     */
+    public void resolveComments()
+    {
+        methodLoop:
+        for (MethodDesc md : methodDescs) {
+            // Build the method signature
+            String methodSig;
+            
+            if (md.returnType != null) {
+                md.returnType = md.returnType.resolveAsType();
+                if (md.returnType == null) {
+                    continue;
+                }
+                methodSig = getTypeString(md.returnType) + " " + md.name + "(";
+            }
+            else {
+                // constructor
+                methodSig = md.name + "(";
+            }
+            
+            Iterator<JavaEntity> i = md.paramTypes.iterator();
+            while (i.hasNext()) {
+                JavaEntity paramEnt = i.next();
+                if (paramEnt == null) {
+                    continue methodLoop;
+                }
+                TypeEntity paramType = paramEnt.resolveAsType();
+                if (paramType == null) {
+                    continue methodLoop;
+                }
+                methodSig += getTypeString(paramType);
+                if (i.hasNext()) {
+                    methodSig += ", ";
+                }
+            }
+            
+            methodSig += ")";
+            md.paramNames = md.paramNames.trim();
+            info.addComment(methodSig, md.javadocText, md.paramNames);
+        }
+    
+        // Now also resolve references
+        for (JavaEntity entity: typeReferences) {
+            entity = entity.resolveAsType();
+            if (entity != null) {
+                JavaType etype = entity.getType();
+                if (! etype.isPrimitive()) {
+                    addTypeReference(etype);
+                }
+            }
+        }
+        
+        refloop:
+        for (UnresolvedVal val: valueReferences) {
+            Iterator<LocatableToken> i = val.components.iterator();
+            String name = i.next().getText();
+            JavaEntity entity = val.resolver.getValueEntity(name, val.accessSource, val.accessPosition);
+            if (entity != null && entity.resolveAsValue() != null) {
+                continue refloop;
+            }
+            while (entity != null && i.hasNext()) {
+                TypeEntity typeEnt = entity.resolveAsType();
+                if (typeEnt != null && ! typeEnt.getType().isPrimitive()) {
+                    addTypeReference(entity.getType());
+                }
+                entity = entity.getSubentity(i.next().getText(), val.accessSource);
+                if (entity != null && entity.resolveAsValue() != null) {
+                    continue refloop;
+                }
+            }
+            if (! i.hasNext() && entity != null) {
+                TypeEntity typeEnt = entity.resolveAsType();
+                if (typeEnt != null && ! typeEnt.getType().isPrimitive()) {
+                    addTypeReference(entity.getType());
+                }
+            }
+        }
+        
+        if (superclassEntity != null) {
+            superclassEntity = superclassEntity.resolveAsType();
+            if (superclassEntity != null) {
+                JavaType sceType = superclassEntity.getType();
+                GenTypeClass scecType = sceType.asClass();
+                if (scecType != null) {
+                    info.setSuperclass(scecType.getReflective().getName());
+                }
+            }
+        }
+        
+        if (interfaceEntities != null && ! interfaceEntities.isEmpty()) {
+            for (JavaEntity ifaceEnt : interfaceEntities) {
+                TypeEntity iEnt = ifaceEnt.resolveAsType();
+                if (iEnt != null) {
+                    GenTypeClass iType = iEnt.getType().asClass();
+                    if (iType != null) {
+                        info.addImplements(iType.getReflective().getName());
+                        continue;
+                    }
+                }
+                info.addImplements(""); // gap filler
+            }
+        }
+    }
+    
+    /**
+     * Add a reference to a type, and recursively process its type arguments (if any)
+     */
+    private void addTypeReference(JavaType type)
+    {
+        GenTypeClass ctype = type.asClass();
+        if (ctype != null) {
+            addTypeReference(ctype.getErasedType().toString());
+            List<? extends GenTypeParameter> plist = ctype.getTypeParamList();
+            for (GenTypeParameter param : plist) {
+                GenTypeSolid [] ubounds = param.getUpperBounds();
+                for (GenTypeSolid ubound : ubounds) {
+                    GenTypeClass ubctype = ubound.asClass();
+                    if (ubctype != null) {
+                        addTypeReference(ubctype);
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Add a reference to a type (fully-qualified type name) to the information to return.
+     */
+    private void addTypeReference(String typeString)
+    {
+        String prefix = JavaNames.getPrefix(typeString);
+        if (prefix.equals(targetPkg)) {
+            String name = JavaNames.getBase(typeString);
+            int dollar = name.indexOf('$');
+            if (dollar != -1) {
+                name = name.substring(0, dollar);
+            }
+            info.addUsed(name);
+        }
+    }
+    
+    /**
+     * Get a String describing a type as suitable for writing to the ctxt file.
+     * This is the qualified, erased type name, with "." rather than "$" separating
+     * inner class names from the outer class names, and the package name (if it
+     * matches the target package) stripped.
+     */
+    private String getTypeString(JavaEntity entity)
+    {
+        String erasedType = entity.getType().getErasedType().toString();
+        if (targetPkg != null && targetPkg.length() != 0) {
+            if (erasedType.startsWith(targetPkg + ".")) {
+                erasedType = erasedType.substring(targetPkg.length() + 1);
+            }
+        }
+        return erasedType.replace("$", ".");
+    }
+    
+    @Override
+    protected void error(String msg, int beginLine, int beginColumn, int endLine, int endColumn)
+    {
+        hadError = true;
+        // Just try and recover.
+    }
+
+    @Override
+    protected void beginTypeBody(LocatableToken token)
+    {
+        super.beginTypeBody(token);
+        classLevel++;
+        gotExtends = false;
+        gotImplements = false;
+    }
+    
+    @Override
+    protected void endTypeBody(LocatableToken token, boolean included)
+    {
+        super.endTypeBody(token, included);
+        classLevel--;
+    }
+    
+    @Override
+    protected void gotTypeSpec(List<LocatableToken> tokens)
+    {
+        lastTypespecToks = tokens;
+        super.gotTypeSpec(tokens);
+        
+        // Dependency tracking
+        int tokpos = lineColToPosition(tokens.get(0).getLine(), tokens.get(0).getColumn());
+        int topOffset = getTopNodeOffset();
+        EntityResolver resolver = new PositionedResolver(scopeStack.peek(), tokpos - topOffset);
+        
+        JavaEntity tentity = ParseUtils.getTypeEntity(resolver, currentQuerySource(), tokens);
+        if (tentity != null && ! gotExtends && ! gotImplements) {
+            typeReferences.add(tentity);
+        }
+        
+        boolean isSuper = storeCurrentClassInfo && gotExtends && !info.isInterface();
+        boolean isInterface = storeCurrentClassInfo && (gotImplements ||
+                (info.isInterface() && gotExtends));
+
+        if (isSuper) {
+            // The list of tokens gives us the name of the class that we extend
+            superclassEntity = ParseUtils.getTypeEntity(scopeStack.get(0), null, tokens);
+            info.setSuperclass(""); // this will be corrected when the type is resolved
+            Selection superClassSelection = getSelection(tokens);
+            info.setSuperReplaceSelection(superClassSelection);
+            info.setImplementsInsertSelection(new Selection(superClassSelection.getEndLine(),
+                    superClassSelection.getEndColumn()));
+        }
+        else if (isInterface) {
+            Selection interfaceSel = getSelection(tokens);
+            if (lastCommaSelection != null) {
+                lastCommaSelection.extendEnd(interfaceSel.getLine(), interfaceSel.getColumn());
+                interfaceSelections.add(lastCommaSelection);
+                lastCommaSelection = null;
+            }
+            interfaceSelections.add(interfaceSel);
+            JavaEntity interfaceEnt = ParseUtils.getTypeEntity(scopeStack.get(0), null, tokens);
+            if (interfaceEnt != null) {
+                interfaceEntities.add(interfaceEnt);
+            }
+            if (tokenStream.LA(1).getType() == JavaTokenTypes.COMMA) {
+                lastCommaSelection = getSelection(tokenStream.LA(1));
+            }
+            else {
+                info.setInterfaceSelections(interfaceSelections);
+                if (! info.isInterface()) {
+                    info.setImplementsInsertSelection(new Selection(interfaceSel.getEndLine(),
+                            interfaceSel.getEndColumn()));
+                }
+                else {
+                    info.setExtendsInsertSelection(new Selection(interfaceSel.getEndLine(),
+                            interfaceSel.getEndColumn()));
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void gotTypeParamBound(List<LocatableToken> tokens)
+    {
+        super.gotTypeParamBound(tokens);
+        JavaEntity ent = ParseUtils.getTypeEntity(scopeStack.peek(), currentQuerySource(), tokens);
+        if (ent != null) {
+            typeReferences.add(ent);
+        }
+    }
+    
+    @Override
+    protected void gotIdentifier(LocatableToken token)
+    {
+        gotCompoundIdent(token);
+        valueReferences.add(currentUnresolvedVal);
+    }
+    
+    @Override
+    protected void gotCompoundIdent(LocatableToken token)
+    {
+        currentUnresolvedVal = new UnresolvedVal();
+        currentUnresolvedVal.components = new LinkedList<LocatableToken>();
+        currentUnresolvedVal.components.add(token);
+        currentUnresolvedVal.resolver = scopeStack.peek();
+        currentUnresolvedVal.accessSource = currentQuerySource();
+        int tokenPosition = lineColToPosition(token.getLine(), token.getColumn());
+        currentUnresolvedVal.accessPosition = tokenPosition - getTopNodeOffset();
+    }
+    
+    @Override
+    protected void gotCompoundComponent(LocatableToken token)
+    {
+        super.gotCompoundComponent(token);
+        currentUnresolvedVal.components.add(token);
+    }
+    
+    @Override
+    protected void completeCompoundValue(LocatableToken token)
+    {
+        super.completeCompoundValue(token);
+        currentUnresolvedVal.components.add(token);
+        valueReferences.add(currentUnresolvedVal);
+    }
+    
+    @Override
+    protected void completeCompoundClass(LocatableToken token)
+    {
+        super.completeCompoundClass(token);
+        List<LocatableToken> components = currentUnresolvedVal.components;
+        components.add(token);
+        Iterator<LocatableToken> i = components.iterator();
+        
+        int tokpos = lineColToPosition(token.getLine(), token.getColumn());
+        int offset = tokpos - getTopNodeOffset();
+        
+        JavaEntity entity = UnresolvedEntity.getEntity(new PositionedResolver(scopeStack.peek(), offset),
+                i.next().getText(), currentQuerySource());
+        while (entity != null && i.hasNext()) {
+            entity = entity.getSubentity(i.next().getText(), currentQuerySource());
+        }
+        if (entity != null) {
+            typeReferences.add(entity);
+        }
+    }
+    
+    protected void gotMethodDeclaration(LocatableToken token, LocatableToken hiddenToken)
+    {
+        super.gotMethodDeclaration(token, hiddenToken);
+        String lastComment = (hiddenToken != null) ? hiddenToken.getText() : null;
+        currentMethod = new MethodDesc();
+        currentMethod.returnType =  ((MethodNode) scopeStack.peek()).getReturnType();
+        currentMethod.name = token.getText();
+        currentMethod.paramNames = "";
+        currentMethod.paramTypes = new LinkedList<JavaEntity>();
+        currentMethod.javadocText = lastComment;
+        arrayCount = 0;
+    }
+
+    protected void gotConstructorDecl(LocatableToken token, LocatableToken hiddenToken)
+    {
+        super.gotConstructorDecl(token, hiddenToken);
+        String lastComment = (hiddenToken != null) ? hiddenToken.getText() : null;
+        currentMethod = new MethodDesc();
+        currentMethod.name = token.getText();
+        currentMethod.paramNames = "";
+        currentMethod.paramTypes = new LinkedList<JavaEntity>();
+        currentMethod.javadocText = lastComment;
+        arrayCount = 0;
+    }
+
+    protected void gotMethodParameter(LocatableToken token, LocatableToken ellipsisToken)
+    {
+        super.gotMethodParameter(token, ellipsisToken);
+        if (currentMethod != null) {
+            currentMethod.paramNames += token.getText() + " ";
+            JavaEntity ptype = ParseUtils.getTypeEntity(scopeStack.peek(),
+                    currentQuerySource(), lastTypespecToks);
+            while (arrayCount > 0) {
+                ptype = new UnresolvedArray(ptype);
+                arrayCount--;
+            }
+            if (ellipsisToken != null) {
+                ptype = new UnresolvedArray(ptype);                
+            }
+            currentMethod.paramTypes.add(ptype);
+        }
+    }
+    
+    @Override
+    protected void gotArrayDeclarator()
+    {
+        super.gotArrayDeclarator();
+        arrayCount++;
+    }
+
+    protected void gotAllMethodParameters()
+    {
+        super.gotAllMethodParameters();
+        if (storeCurrentClassInfo && classLevel == 1) {
+            methodDescs.add(currentMethod);
+            currentMethod = null;
+        }
+    }
+
+    @Override
+    protected void gotTypeDef(LocatableToken firstToken, int tdType)
+    {
+        isPublic = modPublic;
+        isAbstract = modAbstract;
+        super.gotTypeDef(firstToken, tdType);
+        lastTdType = tdType;
+    }
+
+    protected void gotTypeDefName(LocatableToken nameToken)
+    {
+        super.gotTypeDefName(nameToken);
+        gotExtends = false; // haven't seen "extends ..." yet
+        gotImplements = false;
+        if (classLevel == 0) {
+            if (info == null || isPublic && !info.foundPublicClass()) {
+                info = new ClassInfo();
+                info.setName(nameToken.getText(), isPublic);
+                info.setEnum(lastTdType == TYPEDEF_ENUM);
+                info.setInterface(lastTdType == TYPEDEF_INTERFACE);
+                info.setAbstract(isAbstract);
+                Selection insertSelection = new Selection(nameToken.getLine(), nameToken.getEndColumn());
+                info.setExtendsInsertSelection(insertSelection);
+                info.setImplementsInsertSelection(insertSelection);
+                if (pkgSemiToken != null) {
+                    info.setPackageSelections(getSelection(pkgLiteralToken), getSelection(packageTokens),
+                            joinTokens(packageTokens), getSelection(pkgSemiToken));
+                }
+                storeCurrentClassInfo = true;
+            } else {
+                storeCurrentClassInfo = false;
+            }
+        }
+    }
+
+    protected void gotTypeDefExtends(LocatableToken extendsToken)
+    {
+        super.gotTypeDefExtends(extendsToken);
+        if (classLevel == 0 && storeCurrentClassInfo) {
+            gotExtends = true;
+            SourceLocation extendsStart = info.getExtendsInsertSelection().getStartLocation();
+            int extendsEndCol = tokenStream.LA(1).getColumn();
+            int extendsEndLine = tokenStream.LA(1).getLine();
+            if (extendsStart.getLine() == extendsEndLine) {
+                info.setExtendsReplaceSelection(new Selection(extendsEndLine, extendsStart.getColumn(), extendsEndCol - extendsStart.getColumn()));
+            }
+            else {
+                info.setExtendsReplaceSelection(new Selection(extendsEndLine, extendsStart.getColumn(), extendsToken.getEndColumn() - extendsStart.getColumn()));
+            }
+            info.setExtendsInsertSelection(null);
+            
+            if (info.isInterface()) {
+                interfaceSelections = new LinkedList<Selection>();
+                interfaceSelections.add(getSelection(extendsToken));
+                interfaceEntities = new LinkedList<JavaEntity>();
+            }
+        }
+    }
+
+    protected void gotTypeDefImplements(LocatableToken implementsToken)
+    {
+        super.gotTypeDefImplements(implementsToken);
+        if (classLevel == 0 && storeCurrentClassInfo) {
+            gotExtends = false;
+            gotImplements = true;
+            interfaceSelections = new LinkedList<Selection>();
+            interfaceSelections.add(getSelection(implementsToken));
+            interfaceEntities = new LinkedList<JavaEntity>();
+        }
+    }
+
+    protected void beginPackageStatement(LocatableToken token)
+    {
+        super.beginPackageStatement(token);
+        pkgLiteralToken = token;
+    }
+
+    protected void gotPackage(List<LocatableToken> pkgTokens)
+    {
+        super.gotPackage(pkgTokens);
+        packageTokens = pkgTokens;
+    }
+
+    protected void gotPackageSemi(LocatableToken token)
+    {
+        super.gotPackageSemi(token);
+        pkgSemiToken = token;
+    }
+
+    @Override
+    protected void gotModifier(LocatableToken token)
+    {
+        super.gotModifier(token);
+        if (token.getType() == JavaTokenTypes.LITERAL_public) {
+            modPublic = true;
+        }
+        else if (token.getType() == JavaTokenTypes.ABSTRACT) {
+            modAbstract = true;
+        }
+    }
+    
+    @Override
+    protected void modifiersConsumed()
+    {
+        modPublic = false;
+        modAbstract = false;
+    }
+
+    private Selection getSelection(LocatableToken token)
+    {
+        if (token.getLine() <= 0 || token.getColumn() <= 0) {
+            System.out.println("" + token);
+        }
+        if (token.getLength() < 0) {
+            System.out.println("Bad length: " + token.getLength());
+            System.out.println("" + token);
+        }
+        return new Selection(token.getLine(), token.getColumn(), token.getLength());
+    }
+
+    private Selection getSelection(List<LocatableToken> tokens)
+    {
+        Iterator<LocatableToken> i = tokens.iterator();
+        Selection s = getSelection(i.next());
+        if (i.hasNext()) {
+            LocatableToken last = i.next();
+            while (i.hasNext()) {
+                last = i.next();
+            }
+            s.combineWith(getSelection(last));
+        }
+        return s;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/JavaErrorCodes.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/JavaErrorCodes.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ff95eb92705011c4a961ab020ac6a04e74b110a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/JavaErrorCodes.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+/**
+ * A wrapper for error message code strings.
+ * 
+ * <p>These codes are produced by the BlueJ parser, and correspond to parse errors occurring in
+ * certain contexts.
+ * 
+ * @author Davin McCall
+ */
+public class JavaErrorCodes
+{
+    /** Method declaration not followed by one of ';', method body, or "throws" clause */
+    public static final String BJ000 = "BJ000";
+    
+    /** Bracket expected (after "if" or "while" etc) - see also BJ02 */
+    public static final String BJ001 = "BJ001";
+    
+    /** Condition expected (after "if" or "while" etc) - occurs when a brace is found but a bracket was expected */
+    public static final String BJ002 = "BJ002";
+    
+    /** Expected semicolon (various contexts); no other token would be valid */
+    public static final String BJ003 = "BJ003";
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/JavaParser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/JavaParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce6623e9826a2b0f3af03193a7266e5301714524
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/JavaParser.java
@@ -0,0 +1,3335 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import static bluej.parser.JavaErrorCodes.*;
+import static bluej.parser.lexer.JavaTokenTypes.*;
+
+import java.io.Reader;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+import bluej.parser.lexer.JavaLexer;
+import bluej.parser.lexer.JavaTokenFilter;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+
+
+/**
+ * Base class for Java parsers.
+ * 
+ * <p>We parse the source, and when we see certain constructs we call a corresponding method
+ * which subclasses can override (for instance, beginForLoop, beginForLoopBody, endForLoop).
+ * In general it is arranged so that a call to beginXYZ() is always followed by a call to
+ * endXYZ(). 
+ * 
+ * @author Davin McCall
+ */
+public class JavaParser
+{
+    protected JavaTokenFilter tokenStream;
+    protected LocatableToken lastToken;
+
+    public static TokenStream getLexer(Reader r)
+    {
+        return new JavaLexer(r);
+    }
+    
+    private static TokenStream getLexer(Reader r, int line, int col, int pos)
+    {
+        return new JavaLexer(r, line, col, pos);
+    }
+    
+    public JavaParser(Reader r)
+    {
+        TokenStream lexer = getLexer(r);
+        tokenStream = new JavaTokenFilter(lexer, this);
+    }
+    
+    public JavaParser(Reader r, int line, int col, int pos)
+    {
+        TokenStream lexer = getLexer(r, line, col, pos);
+        tokenStream = new JavaTokenFilter(lexer, this);
+    }
+    
+    public JavaTokenFilter getTokenStream()
+    {
+        return tokenStream;
+    }
+    
+    /**
+     * Get the last token seen during the previous parse.
+     * Many parser methods return after having read a complete structure (such as a class definition). This
+     * method allows the retrieval of the last token which was actually part of the structure.
+     */
+    public LocatableToken getLastToken()
+    {
+        return lastToken;
+    }
+
+    /**
+     * Signal a parse error, occurring because the next token in the token stream is
+     * not valid in the current context.
+     * 
+     * @param msg A message/code describing the error
+     */
+    private void error(String msg)
+    {
+        errorBehind(msg, lastToken);
+    }
+    
+    /**
+     * Signal a parser error, occurring because the given token in the token stream is
+     * not valid in the current context, but for which a useful error diagnosis can be
+     * provided. The entire token will be highlighted as erroneous.
+     * 
+     * @param msg    A message/code describing the error
+     * @paran token  The invalid token
+     */
+    private void error(String msg, LocatableToken token)
+    {
+        error(msg, token.getLine(), token.getColumn(), token.getEndLine(), token.getEndColumn());
+    }
+    
+    private void errorBefore(String msg, LocatableToken token)
+    {
+        error(msg, token.getLine(), token.getColumn(), token.getLine(), token.getColumn());
+    }
+    
+    private void errorBehind(String msg, LocatableToken token)
+    {
+        error(msg, token.getEndLine(), token.getEndColumn(), token.getEndLine(), token.getEndColumn());
+    }
+    
+    /**
+     * An error occurred during parsing. Override this method to control error behaviour.
+     * @param msg A message describing the error
+     * @param beginLine  The line where the erroneous token begins
+     * @param beginCol   The column where the erroneous token begins
+     * @param endLine    The line where the erroneous token ends
+     * @param endCol     The column where the erroneous token ends
+     */
+    protected void error(String msg, int beginLine, int beginCol, int endLine, int endCol)
+    {
+        throw new ParseFailure("Parse error: (" + beginLine + ":" + beginCol + ") :" + msg);
+    }
+
+    /**
+     * Parse a compilation unit (from the beginning).
+     */
+    public void parseCU()
+    {
+        parseCU(0);
+    }
+    
+    protected void beginPackageStatement(LocatableToken token) {  }
+
+    /** We have the package name for this source */
+    protected void gotPackage(List<LocatableToken> pkgTokens) { }
+
+    /** We've seen the semicolon at the end of a "package" statement. */
+    protected void gotPackageSemi(LocatableToken token) { }
+
+    /** Saw a modifier (public,private etc) */
+    protected void gotModifier(LocatableToken token) { }
+    
+    /** 
+     * Modifiers were consumed. This is called after the entity to which the modifiers apply
+     * has been identified (eg gotTypeDef() called)
+     */
+    protected void modifiersConsumed() { }
+    
+    /** Beginning of some arbitrary grammatical element */
+    protected void beginElement(LocatableToken token) { }
+
+    /** End of some arbitrary grammatical element.
+     * 
+     * @param token  The end token 
+     * @param included  True if the end token is part of the element; false if it is part of the next element.
+     */
+    protected void endElement(LocatableToken token, boolean included) { }
+
+    /**
+     * Got the beginning (opening brace) of a method or constructor body.
+     */
+    protected void beginMethodBody(LocatableToken token) { }
+    
+    /**
+     * End of a method or constructor body reached.
+     */
+    protected void endMethodBody(LocatableToken token, boolean included) { }
+    
+    protected void endMethodDecl(LocatableToken token, boolean included)
+    {
+        endElement(token, included);
+    }
+        
+    /**
+     * Reached a compilation unit state.
+     * State 1 = package statement parsed. State 2 = one or more type definitions parsed
+     */
+    protected void reachedCUstate(int i) { }
+
+    /** We've seen the semicolon at the end of an "import" statement */
+    protected void gotImportStmtSemi(LocatableToken token)
+    {
+        endElement(token, true);
+    }
+
+    protected void beginForLoop(LocatableToken token) { beginElement(token); }
+    
+    protected void beginForLoopBody(LocatableToken token) { }
+    
+    protected void endForLoopBody(LocatableToken token, boolean included) { }
+
+    protected void endForLoop(LocatableToken token, boolean included) { }
+    
+    protected void beginWhileLoop(LocatableToken token) { }
+
+    protected void beginWhileLoopBody(LocatableToken token) { }
+
+    protected void endWhileLoopBody(LocatableToken token, boolean included) { }
+    
+    protected void endWhileLoop(LocatableToken token, boolean included) { }
+    
+    protected void beginIfStmt(LocatableToken token) { }
+    
+    /** Begin an "if" conditional block (the part that is executed conditionally) */
+    protected void beginIfCondBlock(LocatableToken token) { }
+    
+    protected void endIfCondBlock(LocatableToken token, boolean included) { }
+    
+    protected void endIfStmt(LocatableToken token, boolean included) { }
+    
+    protected void beginSwitchStmt(LocatableToken token) { }
+    
+    protected void beginSwitchBlock(LocatableToken token) { }
+    
+    protected void endSwitchBlock(LocatableToken token) { }
+    
+    protected void endSwitchStmt(LocatableToken token, boolean included) { }
+    
+    protected void beginDoWhile(LocatableToken token) { beginElement(token); }
+    
+    protected void beginDoWhileBody(LocatableToken token) { }
+    
+    protected void endDoWhileBody(LocatableToken token, boolean included) { }
+    
+    protected void endDoWhile(LocatableToken token, boolean included) { }
+    
+    protected void beginTryCatchSmt(LocatableToken token) { }
+    
+    protected void beginTryBlock(LocatableToken token) { }
+    
+    protected void endTryBlock(LocatableToken token, boolean included) { }
+    
+    protected void endTryCatchStmt(LocatableToken token, boolean included) { }
+    
+    protected void beginSynchronizedBlock(LocatableToken token) { }
+    
+    protected void endSynchronizedBlock(LocatableToken token, boolean included) { }
+    
+    /** A list of a parameters to a method or constructor */
+    protected void beginArgumentList(LocatableToken token) { }
+    
+    /** An individual argument has ended */
+    protected void endArgument() { }
+    
+    /** The end of the argument list has been reached. */
+    protected void endArgumentList(LocatableToken token) { }
+    
+    /**
+     * got a "new ..." expression. Will be followed by a type spec (gotTypeSpec())
+     * and possibly by array size declarations, then endExprNew()
+     */
+    protected void gotExprNew(LocatableToken token) { }
+    
+    protected void endExprNew(LocatableToken token, boolean included) { }
+    
+    protected void beginArrayInitList(LocatableToken token) { }
+    
+    protected void endArrayInitList(LocatableToken token) { }
+    
+    /** An anonymous class body. Preceded by a type spec (see gotTypeSpec()) except in the case of an enum member body. */
+    protected void beginAnonClassBody(LocatableToken token, boolean isEnumMember) { }
+    
+    protected void endAnonClassBody(LocatableToken token, boolean included) { }
+    
+    /**
+     * Beginning of a statement block. This includes anonymous statement blocks, and static
+     * initializer blocks
+     */
+    protected void beginStmtblockBody(LocatableToken token)
+    {
+        beginElement(token);
+    }
+    
+    protected void endStmtblockBody(LocatableToken token, boolean included)
+    {
+        endElement(token, included);
+    }
+    
+    /**
+     * Begin a (possibly static) initialisation block.
+     * @param first   The first token (should be either "static" or the "{")
+     * @param lcurly  The "{" token which opens the block body
+     */
+    protected void beginInitBlock(LocatableToken first, LocatableToken lcurly) { }
+    
+    /**
+     * End of a (possibly static) initialisation block
+     * @param rcurly    The last token (should be "}")
+     * @param included  True if the last token is actually a "}"
+     */
+    protected void endInitBlock(LocatableToken rcurly, boolean included) { }
+
+    /** Begin the type definition body. */
+    protected void beginTypeBody(LocatableToken leftCurlyToken) { }
+    
+    /** End of type definition body. This should be a '}' unless an error occurred */
+    protected void endTypeBody(LocatableToken endCurlyToken, boolean included) { }
+    
+    /** 
+     * Got the beginning of a declaration - either a type, a field/variable, or a
+     * method constructor, or an initialisation block. This will be followed by one of:
+     * 
+     * <ul>
+     * <li>gotTypeDef(...) - if a type definition
+     * <li>gotMethodDeclaration(...) - if a method declaration
+     * <li>gotConstructorDecl(...) - if a constructor declaration
+     * <li>beginInitBlock(...) - if an initialiser block
+     * <li>beginFieldDeclarations(...) - if a field declaration
+     * <li>beginVariableDecl(...) - if a variable declaration
+     * <li>endDecl(...) - if not a valid declaration
+     * </ul>
+     */
+    protected void gotDeclBegin(LocatableToken token) { beginElement(token); }
+    
+    /**
+     * End a declaration (unsuccessfully).
+     */
+    protected void endDecl(LocatableToken token) { endElement(token, false); }
+    
+    /**
+     * Called when the current element is recognised as a type definition.
+     * @param tdType  one of TYPEDEF_CLASS, _INTERFACE, _ANNOTATION or _ENUM
+     */
+    protected void gotTypeDef(LocatableToken firstToken, int tdType) { }
+
+    /** Called when we have the identifier token for a class/interface/enum definition */
+    protected void gotTypeDefName(LocatableToken nameToken) { }
+
+    /** Called when we have seen the "extends" literal token */
+    protected void gotTypeDefExtends(LocatableToken extendsToken) { }
+
+    /** Called when we have seen the "implements" literal token */
+    protected void gotTypeDefImplements(LocatableToken implementsToken) { }
+
+    protected void gotTypeDefEnd(LocatableToken token, boolean included)
+    {
+        endElement(token, included);
+    }
+    
+    /** 
+     * Got a variable declaration, which might declare multiple variables. Each
+     * variable will generate gotVariable() or gotSubsequentVar().
+     * @param first  The first token in the declaration
+     */
+    protected void beginVariableDecl(LocatableToken first) { }
+    
+    /**
+     * Got the (first) variable in a variable declaration.
+     * @param first    The first token in the declaration
+     * @param idToken  The token with the variable identifier
+     * @param inited   Whether the variable is initialized as part of the declaration
+     */
+    protected void gotVariableDecl(LocatableToken first, LocatableToken idToken, boolean inited) { }
+
+    protected void gotSubsequentVar(LocatableToken first, LocatableToken idToken, boolean inited) { }
+
+    protected void endVariable(LocatableToken token, boolean included) { }
+
+    protected void endVariableDecls(LocatableToken token, boolean included) { }
+    
+    protected void beginForInitDecl(LocatableToken first) { }
+    
+    protected void gotForInit(LocatableToken first, LocatableToken idToken) { }
+    
+    protected void gotSubsequentForInit(LocatableToken first, LocatableToken idToken) { }
+    
+    protected void endForInit(LocatableToken token, boolean included) { }
+    
+    protected void endForInitDecls(LocatableToken token, boolean included) { }
+    
+    /** 
+     * Got a field declaration, which might declare multiple fields. Each field will generate
+     * gotField() or gotSubsequentField().
+     * @param first  The first token in the declaration
+     */
+    protected void beginFieldDeclarations(LocatableToken first) { }
+    
+    /**
+     * Got a field (inside a type definition).
+     * @param first     The first token that forms part of the field declaration
+     * @param idToken   The token with the name of the field.
+     */
+    protected void gotField(LocatableToken first, LocatableToken idToken) { }
+
+    protected void gotSubsequentField(LocatableToken first, LocatableToken idToken) { }
+    
+    /** End a single field declaration (but not necessarily the field declaration statement) */
+    protected void endField(LocatableToken token, boolean included) { }
+    
+    /** End a field declaration statement */
+    protected void endFieldDeclarations(LocatableToken token, boolean included) { }
+
+    /** We've seen a type specification or something that looks a lot like one. */
+    protected void gotTypeSpec(List<LocatableToken> tokens) { }
+
+    /** Seen a type cast operator. The tokens list contains the type to which is cast. */
+    protected void gotTypeCast(List<LocatableToken> tokens)
+    {
+        gotTypeSpec(tokens);
+    }
+    
+    /** Saw the beginning of an expression */
+    protected void beginExpression(LocatableToken token) { }
+    
+    /** Reached the end of an expression. The given token is the first one past the end. */
+    protected void endExpression(LocatableToken token, boolean emptyExpression) { }
+    
+    /** Saw a literal as part of an expression */
+    protected void gotLiteral(LocatableToken token) { }
+    
+    /**
+     * Saw a primitive type literal in an expression; usually occurs as "int.class"
+     * or "int[].class" for example.
+     * @param token  The primitive token
+     */
+    protected void gotPrimitiveTypeLiteral(LocatableToken token) { }
+    
+    /** Saw an identifier as (part of) an expression */
+    protected void gotIdentifier(LocatableToken token) { }
+    /**
+     * Got an identifier (possibly part of a compound identifier) immediately followed by
+     * end of input stream.
+     */
+    protected void gotIdentifierEOF(LocatableToken token) { gotIdentifier(token); }
+    
+    protected void gotMemberAccessEOF(LocatableToken token) { gotMemberAccess(token); }
+    
+    protected void gotCompoundIdent(LocatableToken token) { gotIdentifier(token); }
+    protected void gotCompoundComponent(LocatableToken token) { gotMemberAccess(token); }
+    protected void completeCompoundValue(LocatableToken token) { gotMemberAccess(token); }
+    protected void completeCompoundValueEOF(LocatableToken token) { completeCompoundValue(token); }
+    protected void completeCompoundClass(LocatableToken token) { gotMemberAccess(token); }
+    
+    protected void gotMemberAccess(LocatableToken token) { }
+    
+    /** Saw a member method call (expr.methodName()), token is the method name; arguments to follow */
+    protected void gotMemberCall(LocatableToken token, List<LocatableToken> typeArgs) { }
+    
+    /** Saw a "naked" method call - "methodName(...)" */
+    protected void gotMethodCall(LocatableToken token) { }
+    
+    /** Saw a call to the constructor as this(...) or super(...) */
+    protected void gotConstructorCall(LocatableToken token) { }
+    
+    /** Saw a dot operator followed by end-of-file */
+    protected void gotDotEOF(LocatableToken token)
+    {
+        gotBinaryOperator(token);
+    }
+    
+    protected void gotClassLiteral(LocatableToken token) { }
+    
+    /** Saw a binary operator as part of an expression */
+    protected void gotBinaryOperator(LocatableToken token) { }
+    
+    protected void gotUnaryOperator(LocatableToken token) { }
+    
+    /** Saw a "?" operator. This will be followed by the left-hand-side expression
+     * (demarked by beginExpression() and endExpression()) followed by a continuation
+     * of the current expression (for the right-hand-side).
+     */
+    protected void gotQuestionOperator(LocatableToken token) { }
+    
+    /**
+     * Saw the "instanceof" operator. The type spec will follow.
+     */
+    protected void gotInstanceOfOperator(LocatableToken token) { }
+    
+    protected void gotArrayElementAccess() { }
+    
+    protected void gotImport(List<LocatableToken> tokens, boolean isStatic) { }
+    
+    protected void gotWildcardImport(List<LocatableToken> tokens, boolean isStatic) { }
+    
+    /**
+     * We've seen a constructor declaration. The token supplied is the constructor name.
+     * The hiddenToken is the comment before the constructor.
+     */
+    protected void gotConstructorDecl(LocatableToken token, LocatableToken hiddenToken) {}
+
+    /**
+     * We've seen a method declaration; the token parameter is the method name;
+     * the hiddenToken parameter is the comment before the method
+     */
+    protected void gotMethodDeclaration(LocatableToken token, LocatableToken hiddenToken) {}
+
+    /** 
+     * We saw a method (or constructor) parameter. The given token specifies the parameter name. 
+     * The last type parsed by parseTypeSpec(boolean) is the parameter type, after any additonal
+     * array declarators (see gotArrayDeclarator()) are applied.
+     * 
+     * @param token   The token giving the parameter name
+     * @param ellipsisToken  The token, if any, with the ellipsis indicating a varargs parameter. May be null.
+     */
+    protected void gotMethodParameter(LocatableToken token, LocatableToken ellipsisToken) { }
+    
+    /**
+     * Called when, after a parameter/field/variable name, array declarators "[]" are seen.
+     * Will be called once for each set of "[]", immediately before gotField() or equivalent
+     * is called.
+     */
+    protected void gotArrayDeclarator() { }
+
+    /**
+     * Called for the array components when we get "new xyz[]".
+     */
+    protected void gotNewArrayDeclarator(boolean withDimension) { }
+    
+    protected void gotAllMethodParameters() { }
+    
+    protected void gotTypeParam(LocatableToken idToken) { }
+    
+    protected void gotTypeParamBound(List<LocatableToken> tokens) { }
+
+    protected void gotMethodTypeParamsBegin() { }
+
+    /**
+     * Called by the lexer when it sees a comment.
+     */
+    public void gotComment(LocatableToken token) { }
+    
+    /**
+     * Check whether a particular token is a type declaration initiator, i.e "class", "interface"
+     * or "enum"
+     */
+    public boolean isTypeDeclarator(LocatableToken token)
+    {
+        return token.getType() == JavaTokenTypes.LITERAL_class
+        || token.getType() == JavaTokenTypes.LITERAL_enum
+        || token.getType() == JavaTokenTypes.LITERAL_interface;
+    }
+
+    /**
+     * Check whether a token is a primitive type - "int" "float" etc
+     */
+    public static boolean isPrimitiveType(LocatableToken token)
+    {
+        return token.getType() == JavaTokenTypes.LITERAL_void
+        || token.getType() == JavaTokenTypes.LITERAL_boolean
+        || token.getType() == JavaTokenTypes.LITERAL_byte
+        || token.getType() == JavaTokenTypes.LITERAL_char
+        || token.getType() == JavaTokenTypes.LITERAL_short
+        || token.getType() == JavaTokenTypes.LITERAL_int
+        || token.getType() == JavaTokenTypes.LITERAL_long
+        || token.getType() == JavaTokenTypes.LITERAL_float
+        || token.getType() == JavaTokenTypes.LITERAL_double;
+    }
+
+    public static final int TYPEDEF_CLASS = 0;
+    public static final int TYPEDEF_INTERFACE = 1;
+    public static final int TYPEDEF_ENUM = 2;
+    public static final int TYPEDEF_ANNOTATION = 3;
+    /** looks like a type definition, but has an error */
+    public static final int TYPEDEF_ERROR = 4;
+    /** doesn't parse as a type definition at all */
+    public static final int TYPEDEF_EPIC_FAIL = 5;
+
+    /**
+     * Get the next token from the token stream.
+     */
+    protected final LocatableToken nextToken()
+    {
+        lastToken = tokenStream.nextToken();
+        return lastToken;
+    }
+    
+    /**
+     * Parse a compilation unit.
+     * @param state  The current parse state
+     */
+    public void parseCU(int state)
+    {
+        while (tokenStream.LA(1).getType() != JavaTokenTypes.EOF) {
+            state = parseCUpart(state);
+        }
+    }
+    
+    public final int parseCUpart(int state)
+    {
+        LocatableToken token = nextToken();
+        if (token.getType() == JavaTokenTypes.LITERAL_package) {
+            if (state != 0) {
+                error("Only one 'package' statement is allowed", token);
+            }
+            token = parsePackageStmt(token);
+            reachedCUstate(1); state = 1;
+        }
+        else if (token.getType() == JavaTokenTypes.LITERAL_import) {
+            parseImportStatement(token);
+            reachedCUstate(1); state = 1;
+        }
+        else if (isModifier(token) || isTypeDeclarator(token)) {
+            // optional: class/interface/enum
+            gotDeclBegin(token);
+            tokenStream.pushBack(token);
+            parseModifiers();
+            parseTypeDef(token);
+            reachedCUstate(2); state = 2;
+        }
+        else if (token.getType() == JavaTokenTypes.EOF) {
+            return state;
+        }
+        else {
+            // TODO give different diagnostic depending on state
+            error("Expected: Type definition (class, interface or enum)", token);
+        }
+        return state;
+    }
+    
+    /**
+     * Parse a "package xyz;"-type statement. The "package"-literal token must have already
+     * been read from the token stream.
+     */
+    public final LocatableToken parsePackageStmt(LocatableToken token)
+    {
+        beginPackageStatement(token);
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.IDENT) {
+            error("Expected identifier after 'package'");
+            return null;
+        }
+        List<LocatableToken> pkgTokens = parseDottedIdent(token);
+        gotPackage(pkgTokens);
+        LocatableToken lastPkgToken = lastToken;
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.SEMI) {
+            tokenStream.pushBack(token);
+            error(BJ003, lastPkgToken.getEndLine(), lastPkgToken.getEndColumn(),
+                    lastPkgToken.getEndLine(), lastPkgToken.getEndColumn());
+            return null;
+        }
+        else {
+            gotPackageSemi(token);
+            return token;
+        }
+    }
+    
+    /**
+     * Parse an import statement.
+     */
+    public void parseImportStatement()
+    {
+        LocatableToken token = nextToken();
+        if (token.getType() == JavaTokenTypes.LITERAL_import) {
+            parseImportStatement(token);
+        }
+        else {
+            error("Import statements must start with \"import\".");
+        }
+    }
+    
+    public void parseImportStatement(LocatableToken token)
+    {
+        beginElement(token);
+        boolean isStatic = false;
+        token = tokenStream.nextToken();
+        if (token.getType() == JavaTokenTypes.LITERAL_static) {
+            isStatic = true;
+            token = tokenStream.nextToken();
+        }
+        if (token.getType() != JavaTokenTypes.IDENT) {
+            tokenStream.pushBack(token);
+            error("Expecting identifier (package containing element to be imported)");
+            endElement(token, false);
+            return;
+        }
+        
+        List<LocatableToken> tokens = parseDottedIdent(token);
+        LocatableToken lastIdentToken = lastToken;
+        if (tokenStream.LA(1).getType() == JavaTokenTypes.DOT) {
+            LocatableToken lastToken = nextToken(); // DOT
+            token = nextToken();
+            if (token.getType() == JavaTokenTypes.SEMI) {
+                error("Trailing '.' in import statement", lastToken.getLine(), lastToken.getColumn(),
+                        lastToken.getEndLine(), lastToken.getEndColumn());
+            }
+            else if (token.getType() == JavaTokenTypes.STAR) {
+                lastToken = token;
+                token = nextToken();
+                if (token.getType() != JavaTokenTypes.SEMI) {
+                    tokenStream.pushBack(token);
+                    error("Expected ';' following import statement", lastToken.getEndLine(), lastToken.getEndColumn(),
+                            lastToken.getEndLine(), lastToken.getEndColumn());
+                }
+                else {
+                    gotWildcardImport(tokens, isStatic);
+                    gotImportStmtSemi(token);
+                }
+            }
+            else {
+                error("Expected package/class identifier, or '*', in import statement.");
+                if (tokenStream.LA(1).getType() == JavaTokenTypes.SEMI) {
+                    nextToken();
+                }
+            }
+        }
+        else {
+            token = nextToken();
+            if (token.getType() != JavaTokenTypes.SEMI) {
+                tokenStream.pushBack(token);
+                error("Expected ';' following import statement", lastIdentToken.getEndLine(), lastIdentToken.getEndColumn(),
+                        lastIdentToken.getEndLine(), lastIdentToken.getEndColumn());
+            }
+            else {
+                gotImport(tokens, isStatic);
+                gotImportStmtSemi(token);
+            }
+        }
+    }
+    
+    /**
+     * Parse a type definition (class, interface, enum).
+     * Returns with {@code lastToken} set to the last token seen as part of the definition.
+     */
+    public final void parseTypeDef()
+    {
+        parseModifiers();
+        parseTypeDef(tokenStream.LA(1));
+    }
+    
+    /**
+     * Parse a type definition (class, interface, enum).
+     * Returns with {@code lastToken} set to the last token seen as part of the definition.
+     * 
+     * @param firstToken  the first token of the type definition, which might still be in the token
+     *                    stream, or which might be a modifier already read.
+     */
+    public final void parseTypeDef(LocatableToken firstToken)
+    {
+        int tdType = parseTypeDefBegin();
+        if (tdType != TYPEDEF_EPIC_FAIL) {
+            gotTypeDef(firstToken, tdType);
+        }
+        modifiersConsumed();
+        if (tdType == TYPEDEF_EPIC_FAIL) {
+            endDecl(tokenStream.LA(1));
+            return;
+        }
+        
+        // Class name
+        LocatableToken token = tokenStream.nextToken();
+        if (token.getType() != JavaTokenTypes.IDENT) {
+            tokenStream.pushBack(token);
+            gotTypeDefEnd(token, false);
+            error("Expected identifier (in type definition)");
+            return;
+        }
+        gotTypeDefName(token);
+
+        token = parseTypeDefPart2();
+
+        // Body!
+        if (token == null) {
+            gotTypeDefEnd(tokenStream.LA(1), false);
+            return;
+        }
+
+        lastToken = parseTypeBody(tdType, token);
+        gotTypeDefEnd(lastToken, lastToken.getType() == JavaTokenTypes.RCURLY);
+    }
+    
+    /**
+     * Parse a type body. Returns the last seen token, which might be the '}' closing the
+     * type body or might be something else (if there is a parse error).
+     * 
+     * @param tdType  the type of the type definition (TYPEDEF_ constant specifying class, 
+     *                interface, enum, annotation)
+     * @param token  the '{' token opening the type body
+     */
+    public final LocatableToken parseTypeBody(int tdType, LocatableToken token)
+    {
+        beginTypeBody(token);
+
+        if (tdType == TYPEDEF_ENUM) {
+            parseEnumConstants();
+        }
+        parseClassBody();
+
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.RCURLY) {
+            error("Expected '}' (in class definition)");
+        }
+
+        endTypeBody(token, token.getType() == JavaTokenTypes.RCURLY);
+        return token;
+    }
+    
+    // Possibilities:
+    // 1 - parses ok, body should follow
+    //       - class/interface TYPEDEF_CLAS / TYPEDEF_INTERFACE
+    //       - enum            TYPEDEF_ENUM
+    //       - annotation      TYPEDEF_ANNOTATION
+    // 2 - doesn't even look like a type definition (TYPEDEF_EPIC_FAIL)
+    public final int parseTypeDefBegin()
+    {
+        parseModifiers();
+        LocatableToken token = nextToken();
+        
+        boolean isAnnotation = token.getType() == JavaTokenTypes.AT;
+        if (isAnnotation) {
+            LocatableToken tdToken = nextToken();
+            if (tdToken.getType() != JavaTokenTypes.LITERAL_interface) {
+                error("Expected 'interface' after '@' in interface definition");
+                tokenStream.pushBack(tdToken);
+                return TYPEDEF_EPIC_FAIL;
+            }
+            token = tdToken;
+        }
+        
+        if (isTypeDeclarator(token)) {
+            int tdType = -1;
+            if (token.getType() == JavaTokenTypes.LITERAL_class) {
+                tdType = TYPEDEF_CLASS;
+            }
+            else if (token.getType() == JavaTokenTypes.LITERAL_interface) {
+                tdType = TYPEDEF_INTERFACE;
+                //check for annotation type
+                if(isAnnotation) {
+                    tdType = TYPEDEF_ANNOTATION;                                                 
+                }
+            }
+            else {
+                tdType = TYPEDEF_ENUM;
+            }
+            
+            return tdType;
+        }
+        else {
+            error("Expected type declarator: 'class', 'interface', or 'enum'");
+            return TYPEDEF_EPIC_FAIL;
+        }
+    }
+    
+    /**
+     * Parse the part of a type definition after the name - the type parameters,
+     * extended classes/interfaces and implemented interfaces. Returns the '{' token
+     * (which begins the type definition body) on success or null on failure.
+     */
+    public LocatableToken parseTypeDefPart2()
+    {
+        // template arguments
+        LocatableToken token = nextToken();
+        if (token.getType() == JavaTokenTypes.LT) {
+            parseTypeParams();
+            token = tokenStream.nextToken();
+        }
+
+        // extends...
+        if (token.getType() == JavaTokenTypes.LITERAL_extends) {
+            gotTypeDefExtends(token);
+            do {
+                parseTypeSpec(true);
+                token = nextToken();
+            }
+            while (token.getType() == JavaTokenTypes.COMMA);
+            
+            if (token.getType() == JavaTokenTypes.DOT) {
+                // Incomplete type spec
+                error("Incomplete type specificiation", token);
+                // Don't push the token back on the token stream - it really is part of the type
+                return null;
+            }
+        }
+
+        // implements...
+        if (token.getType() == JavaTokenTypes.LITERAL_implements) {
+            gotTypeDefImplements(token);
+            do {
+                parseTypeSpec(true);
+                token = nextToken();
+            }
+            while (token.getType() == JavaTokenTypes.COMMA);
+
+            if (token.getType() == JavaTokenTypes.DOT) {
+                // Incomplete type spec
+                error("Incomplete type specificiation", token);
+                // Don't push the token back on the token stream - it really is part of the type
+                return null;
+            }
+        }
+        
+        if (token.getType() == JavaTokenTypes.LCURLY) {
+            return token;
+        }
+        else {
+            tokenStream.pushBack(token);
+            error("Expected '{' (in type definition)");
+            return null;
+        }
+    }
+        
+    public void parseEnumConstants()
+    {
+        LocatableToken token = nextToken();
+        while (token.getType() == JavaTokenTypes.IDENT) {
+            // The identifier is the constant name - there may be constructor arguments as well
+            token = nextToken();
+            if (token.getType() == JavaTokenTypes.LPAREN) {
+                parseArgumentList(token);
+                token = nextToken();
+            }
+            
+            // "body"
+            if (token.getType() == JavaTokenTypes.LCURLY) {
+                beginAnonClassBody(token, true);
+                parseClassBody();
+                token = nextToken();
+                if (token.getType() != JavaTokenTypes.RCURLY) {
+                    error("Expected '}' at end of enum constant body");
+                    endAnonClassBody(token, false);
+                }
+                else {
+                    endAnonClassBody(token, true);
+                    token = nextToken();
+                }
+            }
+
+            if (token.getType() == JavaTokenTypes.SEMI) {
+                return;
+            }
+
+            if (token.getType() == JavaTokenTypes.RCURLY) {
+                // This is valid
+                tokenStream.pushBack(token);
+                return;
+            }
+
+            if (token.getType() != JavaTokenTypes.COMMA) {
+                error("Expecting ',' or ';' after enum constant declaration");
+                tokenStream.pushBack(token);
+                return;
+            }
+            token = nextToken();
+        }
+    }
+        
+    /**
+     * Parse formal type parameters. The opening '<' should have been read already.
+     */
+    public void parseTypeParams()
+    {
+        DepthRef dr = new DepthRef();
+        dr.depth = 1;
+
+        while (true) {
+            LocatableToken idToken = nextToken();
+            if (idToken.getType() != JavaTokenTypes.IDENT) {
+                error("Expected identifier (in type parameter list)");
+                tokenStream.pushBack(idToken);
+                return;
+            }
+            gotTypeParam(idToken);
+
+            LocatableToken token = nextToken();
+            if (token.getType() == JavaTokenTypes.LITERAL_extends) {
+                do {
+                    LinkedList<LocatableToken> boundTokens = new LinkedList<LocatableToken>();
+                    if (parseTargType(false, boundTokens, dr)) {
+                        gotTypeParamBound(boundTokens);
+                    }
+                    if (dr.depth <= 0) {
+                        return;
+                    }
+                    token = nextToken();
+                } while (token.getType() == JavaTokenTypes.BAND);
+            }
+
+            if (token.getType() != JavaTokenTypes.COMMA) {
+                if (token.getType() != JavaTokenTypes.GT) {
+                    error("Expecting '>' at end of type parameter list");
+                    tokenStream.pushBack(token);
+                }
+                break;
+            }
+        }
+    }
+
+    /**
+     * Check whether a token represents a modifier (or an "at" symbol,
+     * denoting an annotation).
+     */
+    public static boolean isModifier(LocatableToken token)
+    {
+        int tokType = token.getType();
+        return (tokType == JavaTokenTypes.LITERAL_public
+                || tokType == JavaTokenTypes.LITERAL_private
+                || tokType == JavaTokenTypes.LITERAL_protected
+                || tokType == JavaTokenTypes.ABSTRACT
+                || tokType == JavaTokenTypes.FINAL
+                || tokType == JavaTokenTypes.LITERAL_static
+                || tokType == JavaTokenTypes.LITERAL_volatile
+                || tokType == JavaTokenTypes.LITERAL_native
+                || tokType == JavaTokenTypes.STRICTFP
+                || tokType == JavaTokenTypes.LITERAL_transient
+                || tokType == JavaTokenTypes.LITERAL_synchronized
+                || tokType == JavaTokenTypes.AT);
+    }
+
+    /**
+     * Parse a modifier list (and return all modifier tokens in a list)
+     */
+    public List<LocatableToken> parseModifiers()
+    {
+        List<LocatableToken> rval = new LinkedList<LocatableToken>();
+        
+        LocatableToken token = tokenStream.nextToken();
+        while (isModifier(token)) {
+            if (token.getType() == JavaTokenTypes.AT) {
+                if( tokenStream.LA(1).getType() == JavaTokenTypes.IDENT) {
+                    lastToken = token;
+                    parseAnnotation();
+                }
+                else {
+                    tokenStream.pushBack(token);
+                    return rval;
+                }
+            }
+            else {
+                gotModifier(token);
+            }
+            lastToken = token;
+            rval.add(token);
+            token = nextToken();
+        }                       
+        tokenStream.pushBack(token);
+        
+        return rval;
+    }
+
+    /**
+     * Having seen '{', parse the rest of a class body.
+     */
+    public void parseClassBody()
+    {
+        LocatableToken token = tokenStream.nextToken();
+        while (token.getType() != JavaTokenTypes.RCURLY) {
+            if (token.getType() == JavaTokenTypes.EOF) {
+                error("Unexpected end-of-file in type body; missing '}'", token);
+                return;
+            }
+            parseClassElement(token);
+            token = nextToken();
+        }
+        tokenStream.pushBack(token);
+    }
+    
+    public final void parseClassElement(LocatableToken token)
+    {
+        if (token.getType() == JavaTokenTypes.SEMI) {
+            // A spurious semicolon.
+            return;
+        }
+        
+        gotDeclBegin(token);
+        tokenStream.pushBack(token);
+        LocatableToken hiddenToken = (LocatableToken) token.getHiddenBefore();
+        
+        // field declaration, method declaration, inner class
+        List<LocatableToken> modifiers = parseModifiers();
+        LocatableToken firstMod = null;
+        if (! modifiers.isEmpty()) {
+            firstMod = modifiers.get(0);
+        }
+        
+        token = nextToken();
+        if (token.getType() == JavaTokenTypes.LITERAL_class
+                || token.getType() == JavaTokenTypes.LITERAL_interface
+                || token.getType() == JavaTokenTypes.LITERAL_enum
+                || token.getType() == JavaTokenTypes.AT) {
+            tokenStream.pushBack(token);
+            parseTypeDef(firstMod != null ? firstMod : token);
+        }
+        else {
+            // Not an inner type: should be a method/constructor or field,
+            // or (possibly static) a initialisation block
+            if (token.getType() == JavaTokenTypes.LCURLY) {
+                // initialisation block
+                LocatableToken firstToken = firstMod == null ? token : firstMod;
+                beginInitBlock(firstToken, token);
+                modifiersConsumed();
+                parseStmtBlock();
+                token = nextToken();
+                if (token.getType() != JavaTokenTypes.RCURLY) {
+                    error("Expecting '}' (at end of initialisation block)");
+                    tokenStream.pushBack(token);
+                    endInitBlock(token, false);
+                    endElement(token, false);
+                }
+                else {
+                    endInitBlock(token, true);
+                    endElement(token, true);
+                }
+            }
+            else if (token.getType() == JavaTokenTypes.IDENT
+                    && tokenStream.LA(1).getType() == JavaTokenTypes.LPAREN) {
+                // constructor
+                gotConstructorDecl(token, hiddenToken);
+                modifiersConsumed();
+                nextToken();
+                parseMethodParamsBody();
+            }
+            else if (token.getType() == JavaTokenTypes.LT
+                    || token.getType() == JavaTokenTypes.IDENT
+                    || isPrimitiveType(token)) {
+                // method/constructor, field
+                LocatableToken first = firstMod != null ? firstMod : token;
+                if (token.getType() == JavaTokenTypes.LT) {
+                    // generic method
+                    gotMethodTypeParamsBegin();
+                    parseTypeParams();
+                }
+                else {
+                    tokenStream.pushBack(token);
+                }
+                // Might be a constructor:
+                boolean isConstructor = tokenStream.LA(1).getType() == JavaTokenTypes.IDENT
+                        && tokenStream.LA(2).getType() == JavaTokenTypes.LPAREN;
+                if (!isConstructor && !parseTypeSpec(true)) {
+                    endDecl(tokenStream.LA(1));
+                    return;
+                }
+                LocatableToken idToken = tokenStream.nextToken(); // identifier
+                if (idToken.getType() != JavaTokenTypes.IDENT) {
+                    modifiersConsumed();
+                    tokenStream.pushBack(idToken);
+                    errorBefore("Expected identifier (method or field name).", idToken);
+                    endDecl(idToken);
+                    return;
+                }
+
+                token = nextToken();
+                int ttype = token.getType();
+                if (ttype == JavaTokenTypes.LBRACK || ttype == JavaTokenTypes.SEMI
+                        || ttype == JavaTokenTypes.ASSIGN || ttype == JavaTokenTypes.COMMA) {
+                    // This must be a field declaration
+                    beginFieldDeclarations(first);
+                    if (ttype == JavaTokenTypes.LBRACK) {
+                        tokenStream.pushBack(token);
+                        parseArrayDeclarators();
+                        token = nextToken();
+                        ttype = token.getType();
+                    }
+                    gotField(first, idToken);
+                    if (ttype == JavaTokenTypes.SEMI) {
+                        endField(token, true);
+                        endFieldDeclarations(token, true);
+                    }
+                    else if (ttype == JavaTokenTypes.ASSIGN) {
+                        parseExpression();
+                        parseSubsequentDeclarations(DECL_TYPE_FIELD, true);
+                    }
+                    else if (ttype == JavaTokenTypes.COMMA) {
+                        tokenStream.pushBack(token);
+                        parseSubsequentDeclarations(DECL_TYPE_FIELD, true);
+                    }
+                    else {
+                        error("Expected ',', '=' or ';' after field declaration");
+                        tokenStream.pushBack(token);
+                        endField(token, false);
+                        endFieldDeclarations(token, false);
+                    }
+                    modifiersConsumed();
+                }
+                else if (ttype == JavaTokenTypes.LPAREN) {
+                    // method declaration
+                    if (isConstructor) {
+                        gotConstructorDecl(idToken, hiddenToken);
+                    }
+                    else {
+                        gotMethodDeclaration(idToken, hiddenToken);
+                    }
+                    modifiersConsumed();
+                    parseMethodParamsBody();
+                }
+                else {
+                    modifiersConsumed();
+                    tokenStream.pushBack(token);
+                    error("Expected ';' or '=' or '(' (in field or method declaration).");
+                    endDecl(token);
+                }
+            }
+            else {
+                error("Unexpected token \"" + token.getText() + "\" in type declaration body");
+                endDecl(tokenStream.LA(1));
+            }
+        }
+        
+    }
+
+    protected void parseArrayDeclarators()
+    {
+        if (tokenStream.LA(1).getType() != JavaTokenTypes.LBRACK) {
+            return;
+        }
+
+        LocatableToken token = nextToken();
+        while (token.getType() == JavaTokenTypes.LBRACK) {
+            token = nextToken();
+            if (token.getType() != JavaTokenTypes.RBRACK) {
+                errorBefore("Expecting ']' (to match '[')", token);
+                if (tokenStream.LA(1).getType() == JavaTokenTypes.RBRACK) {
+                    // Try and recover
+                    token = nextToken(); // ']'
+                }
+                else {
+                    tokenStream.pushBack(token);
+                    return;
+                }
+            }
+            gotArrayDeclarator();
+            token = nextToken();
+        }
+        tokenStream.pushBack(token);
+    }
+        
+    /**
+     * We've got the return type, name, and opening parenthesis of a method/constructor
+     * declaration. Parse the rest.
+     */
+    public void parseMethodParamsBody()
+    {
+        parseParameterList();
+        gotAllMethodParameters();
+        LocatableToken token = nextToken();
+        if (token.getType() != JavaTokenTypes.RPAREN) {
+            error("Expected ')' at end of parameter list (in method declaration)");
+            tokenStream.pushBack(token);
+            endMethodDecl(token, false);
+            return;
+        }
+        token = nextToken();
+        if (token.getType() == JavaTokenTypes.LITERAL_throws) {
+            do {
+                parseTypeSpec(true);
+                token = nextToken();
+            } while (token.getType() == JavaTokenTypes.COMMA);
+        }
+        if (token.getType() == JavaTokenTypes.LCURLY) {
+            // method body
+            beginMethodBody(token);
+            parseStmtBlock();
+            token = nextToken();
+            if (token.getType() != JavaTokenTypes.RCURLY) {
+                error("Expected '}' at end of method body");
+                tokenStream.pushBack(token);
+                endMethodBody(token, false);
+                endMethodDecl(token, false);
+            }
+            else {
+                endMethodBody(token, true);
+                endMethodDecl(token, true);
+            }
+            return;
+        }
+        else if (token.getType() == JavaTokenTypes.LITERAL_default) {
+            parseExpression();
+            token = nextToken();
+        }
+        
+        if (token.getType() != JavaTokenTypes.SEMI) {
+            tokenStream.pushBack(token);
+            error(BJ000);
+            endMethodDecl(token, false);
+        }
+        else {
+            endMethodDecl(token, true);
+        }
+    }
+        
+    /**
+     * Parse a statement block - such as a method body
+     */
+    public void parseStmtBlock()
+    {
+        while(true) {
+            LocatableToken token = nextToken();
+            if (token.getType() == JavaTokenTypes.EOF
+                    || token.getType() == JavaTokenTypes.RCURLY) {
+                tokenStream.pushBack(token);
+                return;
+            }
+            beginElement(token);
+            LocatableToken ntoken = parseStatement(token, false);
+            if (ntoken != null) {
+                endElement(ntoken, true);
+            }
+            else {
+                ntoken = tokenStream.LA(1);
+                endElement(tokenStream.LA(1), false);
+                if (ntoken == token) {
+                    nextToken();
+                    error("Invalid beginning of statement.", token);
+                    continue;
+                    // TODO we can just skip the token and keep processing, but we should be
+                    // context aware. For instance if token is "catch" and we are in a try block,
+                    // should bail out altogether now so that processing can continue upstream.
+                }
+            }
+        }
+    }
+
+    public void parseStatement()
+    {
+        parseStatement(nextToken(), false);
+    }
+
+    private static int [] statementTokenIndexes = new int[JavaTokenTypes.INVALID + 1];
+    
+    static {
+        statementTokenIndexes[JavaTokenTypes.SEMI] = 1;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_return] = 2;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_for] = 3;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_while] = 4;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_if] = 5;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_do] = 6;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_assert] = 7;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_switch] = 8;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_case] = 9;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_default] = 10;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_continue] = 11;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_break] = 12;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_throw] = 13;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_try] = 14;
+        statementTokenIndexes[JavaTokenTypes.IDENT] = 15;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_synchronized] = 16;
+        
+        // Modifiers
+        statementTokenIndexes[JavaTokenTypes.LITERAL_public] = 17;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_private] = 18;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_protected] = 19;
+        statementTokenIndexes[JavaTokenTypes.ABSTRACT] = 20;
+        statementTokenIndexes[JavaTokenTypes.FINAL] = 21;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_static] = 22;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_volatile] = 23;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_native] = 24;
+        statementTokenIndexes[JavaTokenTypes.STRICTFP] = 25;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_transient] = 26;
+        // statementTokenIndexes[JavaTokenTypes.LITERAL_synchronized] = 27;
+        statementTokenIndexes[JavaTokenTypes.AT] = 27;
+        
+        // type declarators
+        statementTokenIndexes[JavaTokenTypes.LITERAL_class] = 28;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_enum] = 29;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_interface] = 30;
+        
+        // primitive types
+        statementTokenIndexes[JavaTokenTypes.LITERAL_void] = 31;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_boolean] = 32;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_byte] = 33;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_char] = 34;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_short] = 35;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_int] = 36;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_long] = 37;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_float] = 38;
+        statementTokenIndexes[JavaTokenTypes.LITERAL_double] = 39;
+        
+        statementTokenIndexes[JavaTokenTypes.LCURLY] = 40;
+    }
+    
+    /**
+     * Parse a statement. Return the last token that is part of the statement (i.e the ';' or '}'
+     * terminator), or null if an error was encountered.
+     * 
+     * @param token  The first token of the statement
+     * @param allowComma  if true, allows multiple statements separated by commas. Each
+     *                    statement will be parsed.
+     */
+    public LocatableToken parseStatement(LocatableToken token, boolean allowComma)
+    {
+        while (true) {
+            switch (statementTokenIndexes[token.getType()]) {
+            case 1: // SEMI
+                return token; // empty statement
+            case 2: // LITERAL_return
+                token = nextToken();
+                if (token.getType() != JavaTokenTypes.SEMI) {
+                    tokenStream.pushBack(token);
+                    parseExpression();
+                    token = nextToken();
+                }
+                if (token.getType() != JavaTokenTypes.SEMI) {
+                    tokenStream.pushBack(token);
+                    error(BJ003);
+                    return null;
+                }
+                return token;
+            case 3: // LITERAL_for
+                return parseForStatement(token);
+            case 4: // LITERAL_while
+                return parseWhileStatement(token);
+            case 5: // LITERAL_if    
+                return parseIfStatement(token);
+            case 6: // LITERAL_do
+                return parseDoWhileStatement(token);
+            case 7: // LITERAL_assert
+                return parseAssertStatement(token);
+            case 8: // LITERAL_switch
+                return parseSwitchStatement(token);
+            case 9: // LITERAL_case
+                parseExpression();
+                token = nextToken();
+                if (token.getType() != JavaTokenTypes.COLON) {
+                    error("Expecting ':' at end of case expression");
+                    tokenStream.pushBack(token);
+                    return null;
+                }
+                return token;
+            case 10: // LITERAL_default
+                token = nextToken();
+                if (token.getType() != JavaTokenTypes.COLON) {
+                    error("Expecting ':' at end of case expression");
+                    tokenStream.pushBack(token);
+                    return null;
+                }
+                return token;
+            case 11: // LITERAL_continue
+            case 12: // LITERAL_break
+                // There might be a label afterwards
+                token = nextToken();
+                if (token.getType() == JavaTokenTypes.IDENT) {
+                    token = nextToken();
+                }
+                if (token.getType() != JavaTokenTypes.SEMI) {
+                    tokenStream.pushBack(token);
+                    error(BJ003);
+                    return null;
+                }
+                return token;
+            case 13: // LITERAL_throw
+                parseExpression();
+                token = nextToken();
+                if (token.getType() != JavaTokenTypes.SEMI) {
+                    tokenStream.pushBack(token);
+                    error(BJ003);
+                    return null;
+                }
+                return token;
+            case 14: // LITERAL_try
+                return parseTryCatchStmt(token);
+            case 15: // IDENT
+                // A label?
+                LocatableToken ctoken = nextToken();
+                if (ctoken.getType() == JavaTokenTypes.COLON) {
+                    return ctoken;
+                }
+                tokenStream.pushBack(ctoken);
+                tokenStream.pushBack(token);
+
+                // A declaration of a variable?
+                List<LocatableToken> tlist = new LinkedList<LocatableToken>();
+                boolean isTypeSpec = parseTypeSpec(true, true, tlist);
+                token = tokenStream.LA(1);
+                pushBackAll(tlist);
+                if (isTypeSpec && token.getType() == JavaTokenTypes.IDENT) {
+                    token = tlist.get(0);
+                    gotDeclBegin(token);
+                    return parseVariableDeclarations(token, true);
+                }
+                else {
+                    parseExpression();                                              
+                    token = tokenStream.nextToken();
+                    if (token.getType() == JavaTokenTypes.COMMA && allowComma) {
+                        token = tokenStream.nextToken();
+                        continue;
+                    }
+                    if (token.getType() != JavaTokenTypes.SEMI) {
+                        tokenStream.pushBack(token);
+                        error("Expected ';' at end of previous statement");
+                        return null;
+                    }
+                    return token;
+                }
+            case 16: // LITERAL_synchronized
+                // Synchronized block
+                beginSynchronizedBlock(token);
+                token = nextToken();
+                if (token.getType() == JavaTokenTypes.LPAREN) {
+                    parseExpression();
+                    token = nextToken();
+                    if (token.getType() != JavaTokenTypes.RPAREN) {
+                        errorBefore("Expecting ')' at end of expression", token);
+                        tokenStream.pushBack(token);
+                        endSynchronizedBlock(token, false);
+                        return null;
+                    }
+                    token = tokenStream.nextToken();
+                }
+                if (token.getType() == JavaTokenTypes.LCURLY) {
+                    beginStmtblockBody(token);
+                    parseStmtBlock();
+                    token = nextToken();
+                    if (token.getType() != JavaTokenTypes.RCURLY) {
+                        error("Expecting '}' at end of synchronized block");
+                        tokenStream.pushBack(token);
+                        endStmtblockBody(token, false);
+                        endSynchronizedBlock(token, false);
+                        return null;
+                    }
+                    endStmtblockBody(token, true);
+                    endSynchronizedBlock(token, true);
+                    return token;
+                }
+                else {
+                    error("Expecting statement block after 'synchronized'");
+                    tokenStream.pushBack(token);
+                    endSynchronizedBlock(token, false);
+                    return null;
+                }
+            case 17: // LITERAL_public
+            case 18: // LITERAL_private
+            case 19: // LITERAL_protected
+            case 20: // ABSTRACT
+            case 21: // FINAL
+            case 22: // LITERAL_static
+            case 23: // LITERAL_volatile
+            case 24: // LITERAL_native
+            case 25: // STRICTFP
+            case 26: // LITERAL_transient
+            case 27: // AT
+                tokenStream.pushBack(token);
+                gotDeclBegin(token);
+                parseModifiers();
+                if (isTypeDeclarator(tokenStream.LA(1)) || tokenStream.LA(1).getType() == JavaTokenTypes.AT) {
+                    parseTypeDef(token);
+                }
+                else {
+                    parseVariableDeclarations(token, true);
+                }
+                return null;
+            case 28: // LITERAL_class
+            case 29: // LITERAL_enum
+            case 30: // LITERAL_interface
+                tokenStream.pushBack(token);
+                gotDeclBegin(token);
+                parseTypeDef(token);
+                return null;
+            case 31: // LITERAL_void
+            case 32: // LITERAL_boolean
+            case 33: // LITERAL_byte
+            case 34: // LITERAL_char
+            case 35: // LITERAL_short
+            case 36: // LITERAL_int
+            case 37: // LITERAL_long
+            case 38: // LITERAL_float
+            case 39: // LITERAL_double
+                // primitive
+                tokenStream.pushBack(token);
+                tlist = new LinkedList<LocatableToken>();
+                parseTypeSpec(false, true, tlist);
+
+                if (tokenStream.LA(1).getType() == JavaTokenTypes.DOT) {
+                    // int.class, or int[].class are possible
+                    pushBackAll(tlist);
+                    parseExpression();
+                    token = nextToken();
+                    if (token.getType() != JavaTokenTypes.SEMI) {
+                        error("Expected ';' after expression-statement");
+                        return null;
+                    }
+                    return token;
+                }
+                else {
+                    pushBackAll(tlist);
+                    gotDeclBegin(token);
+                    return parseVariableDeclarations(token, true);
+                }
+            case 40: // LCURLY
+                beginStmtblockBody(token);
+                parseStmtBlock();
+                token = nextToken();
+                if (token.getType() != JavaTokenTypes.RCURLY) {
+                    error("Expecting '}' at end of statement block");
+                    if (token.getType() != JavaTokenTypes.RPAREN) {
+                        tokenStream.pushBack(token);
+                    }
+                    endStmtblockBody(token, false);
+                    return null;
+                }
+                endStmtblockBody(token, true);
+                return token;
+            }
+
+            // Expression, or not valid.
+            if (! isExpressionTokenType(token.getType())) {
+                error("Not a valid statement beginning.", token);
+                return null;
+            }
+
+            tokenStream.pushBack(token);
+            parseExpression();
+            token = tokenStream.nextToken();
+            if (token.getType() != JavaTokenTypes.SEMI) {
+                tokenStream.pushBack(token);
+                error("Expected ';' at end of previous statement");
+                return null;
+            }
+            return token;
+        }
+    }
+    
+    /**
+     * Parse a try/catch/finally. The first token is 'try'.
+     * @param token  The first token (must be 'try').
+     * @return  the last token that is part of the try/catch/finally, or null
+     */
+    public LocatableToken parseTryCatchStmt(LocatableToken token)
+    {
+        beginTryCatchSmt(token);
+        token = nextToken();
+        if (token.getType() == JavaTokenTypes.LPAREN) {
+            // Java 7 try-with-resource
+            do {
+                token = tokenStream.LA(1);
+                // Specification allows either a variable declaration (with initializer) or
+                // expression.
+                if (token.getType() == JavaTokenTypes.IDENT) {
+                    List<LocatableToken> tlist = new LinkedList<LocatableToken>();
+                    boolean isTypeSpec = parseTypeSpec(true, true, tlist);
+                    token = tokenStream.LA(1);
+                    pushBackAll(tlist);
+                    if (isTypeSpec && token.getType() == JavaTokenTypes.IDENT) {
+                        gotDeclBegin(tlist.get(0));
+                        parseVariableDeclarations(tlist.get(0), false);
+                    }
+                    else {
+                        parseExpression();                                              
+                    }
+                }
+                else if (isModifier(token)) {
+                    tokenStream.nextToken(); // remove the modifier from the token stream
+                    parseVariableDeclarations();
+                }
+                else {
+                    parseExpression();
+                }
+                token = tokenStream.nextToken();
+            } while (token.getType() == JavaTokenTypes.SEMI);
+            if (token.getType() != JavaTokenTypes.RPAREN) {
+                errorBefore("Missing closing ')' after resources in 'try' statement", token);
+            }
+            token = nextToken();
+        }
+        if (token.getType() != JavaTokenTypes.LCURLY) {
+            error ("Expecting '{' after 'try'");
+            tokenStream.pushBack(token);
+            endTryCatchStmt(token, false);
+            return null;
+        }
+        beginTryBlock(token);
+        parseStmtBlock();
+        token = nextToken();
+        if (token.getType() == JavaTokenTypes.RCURLY) {
+            endTryBlock(token, true);
+        }
+        else if (token.getType() == JavaTokenTypes.LITERAL_catch
+                || token.getType() == JavaTokenTypes.LITERAL_finally) {
+            // Invalid, but we can recover
+            tokenStream.pushBack(token);
+            error("Missing '}' at end of 'try' block");
+            endTryBlock(token, false);
+        }
+        else {
+            tokenStream.pushBack(token);
+            error("Missing '}' at end of 'try' block");
+            endTryBlock(token, false);
+            endTryCatchStmt(token, false);
+            return null;
+        }
+
+        int laType = tokenStream.LA(1).getType();
+        while (laType == JavaTokenTypes.LITERAL_catch
+                || laType == JavaTokenTypes.LITERAL_finally) {
+            token = nextToken();
+            if (laType == JavaTokenTypes.LITERAL_catch) {
+                token = nextToken();
+                if (token.getType() != JavaTokenTypes.LPAREN) {
+                    error("Expecting '(' after 'catch'");
+                    tokenStream.pushBack(token);
+                    endTryCatchStmt(token, false);
+                    return null;
+                }
+                
+                while (true) {
+                    if (tokenStream.LA(1).getType() == JavaTokenTypes.FINAL) {
+                        // Java 7 "final re-throw"
+                        token = nextToken();
+                    }
+                    
+                    parseTypeSpec(true);
+                    token = nextToken();
+                    if (token.getType() != JavaTokenTypes.BOR) {
+                        // Java 7 multi-catch
+                        break;
+                    }
+                }
+                
+                if (token.getType() != JavaTokenTypes.IDENT) {
+                    error("Expecting identifier after type (in 'catch' expression)");
+                    tokenStream.pushBack(token);
+                    endTryCatchStmt(token, false);
+                    return null;
+                }
+                token = nextToken();
+                
+                if (token.getType() != JavaTokenTypes.RPAREN) {
+                    error("Expecting ')' after identifier (in 'catch' expression)");
+                    tokenStream.pushBack(token);
+                    endTryCatchStmt(token, false);
+                    return null;
+                }
+            }
+            token = nextToken();
+            if (token.getType() != JavaTokenTypes.LCURLY) {
+                error("Expecting '{' after 'catch'/'finally'");
+                tokenStream.pushBack(token);
+                endTryCatchStmt(token, false);
+                return null;
+            }
+            token = parseStatement(token, false); // parse as a statement block
+            laType = tokenStream.LA(1).getType();
+        }
+        if (token != null) {
+            endTryCatchStmt(token, true);
+        }
+        else {
+            endTryCatchStmt(tokenStream.LA(1), false);
+        }
+        return token;
+    }
+        
+    /**
+     * Parse an "assert" statement. Returns the concluding semi-colon token, or null on error.
+     * {@code lastToken} will be set to the last token which is part of the statement.
+     * 
+     * @param token   The token corresponding to the "assert" keyword.
+     */
+    public LocatableToken parseAssertStatement(LocatableToken token)
+    {
+        parseExpression();
+        token = tokenStream.nextToken();
+        if (token.getType() == JavaTokenTypes.COLON) {
+            // Should be followed by a string
+            lastToken = token;
+            parseExpression();
+            token = tokenStream.nextToken();
+        }
+        if (token.getType() != JavaTokenTypes.SEMI) {
+            error("Expected ';' at end of assertion statement");
+            tokenStream.pushBack(token);
+            return null;
+        }
+        lastToken = token;
+        return token;
+    }
+
+    /** Parse a "switch(...) {  }" statement. */
+    public LocatableToken parseSwitchStatement(LocatableToken token)
+    {
+        beginSwitchStmt(token);
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.LPAREN) {
+            error("Expected '(' after 'switch'");
+            tokenStream.pushBack(token);
+            endSwitchStmt(token, false);
+            return null;
+        }
+        parseExpression();
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.RPAREN) {
+            error("Expected ')' at end of expression (in 'switch(...)')");
+            tokenStream.pushBack(token);
+            endSwitchStmt(token, false);
+            return null;
+        }
+        token = tokenStream.nextToken();
+        if (token.getType() != JavaTokenTypes.LCURLY) {
+            error("Expected '{' after 'switch(...)'");
+            tokenStream.pushBack(token);
+            endSwitchStmt(token, false);
+            return null;
+        }
+        beginSwitchBlock(token);
+        parseStmtBlock();
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.RCURLY) {
+            error("Missing '}' at end of 'switch' statement block");
+            tokenStream.pushBack(token);
+            endSwitchBlock(token);
+            endSwitchStmt(token, false);
+            return null;
+        }
+        endSwitchBlock(token);
+        endSwitchStmt(token, true);
+        return token;
+    }
+    
+    public LocatableToken parseDoWhileStatement(LocatableToken token)
+    {
+        beginDoWhile(token);
+        token = nextToken(); // '{' or a statement
+        LocatableToken ntoken = parseStatement(token, false);
+        if (ntoken != null || token != tokenStream.LA(1)) {
+            beginDoWhileBody(token);
+            if (ntoken == null) {
+                endDoWhileBody(tokenStream.LA(1), false);
+            }
+            else {
+                endDoWhileBody(ntoken, true);
+            }
+        }
+
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.LITERAL_while) {
+            error("Expecting 'while' after statement block (in 'do ... while')");
+            tokenStream.pushBack(token);
+            endDoWhile(token, false);
+            return null;
+        }
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.LPAREN) {
+            error("Expecting '(' after 'while'");
+            tokenStream.pushBack(token);
+            endDoWhile(token, false);
+            return null;
+        }
+        parseExpression();
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.RPAREN) {
+            error("Expecting ')' after conditional expression (in 'while' statement)");
+            tokenStream.pushBack(token);
+            endDoWhile(token, false);
+            return null;
+        }
+        token = nextToken(); // should be ';'
+        endDoWhile(token, true);
+        return token;
+    }
+        
+    public LocatableToken parseWhileStatement(LocatableToken token)
+    {
+        beginWhileLoop(token);
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.LPAREN) {
+            error("Expecting '(' after 'while'");
+            tokenStream.pushBack(token);
+            endWhileLoop(token, false);
+            return null;
+        }
+        parseExpression();
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.RPAREN) {
+            error("Expecting ')' after conditional expression (in 'while' statement)");
+            tokenStream.pushBack(token);
+            endWhileLoop(token, false);
+            return null;
+        }
+        token = nextToken();
+        beginWhileLoopBody(token);
+        token = parseStatement(token, false);
+        if (token != null) {
+            endWhileLoopBody(token, true);
+            endWhileLoop(token, true);
+        }
+        else {
+            token = tokenStream.LA(1);
+            endWhileLoopBody(token, false);
+            endWhileLoop(token, false);
+            token = null;
+        }
+        return token;
+    }
+
+    /**
+     * Parse a "for(...)" loop (old or new style).
+     * @param forToken  The "for" token, which has already been extracted from the token stream.
+     * @return The last token that is part of the loop (or null).
+     */
+    public LocatableToken parseForStatement(LocatableToken forToken)
+    {
+        // TODO: if we get an unexpected token in the part between '(' and ')' check
+        // if it is ')'. If so we might still expect a loop body to follow.
+        beginForLoop(forToken);
+        LocatableToken token = nextToken();
+        if (token.getType() != JavaTokenTypes.LPAREN) {
+            error("Expecting '(' after 'for'");
+            tokenStream.pushBack(token);
+            endForLoop(token, false);
+            return null;
+        }
+        if (tokenStream.LA(1).getType() != JavaTokenTypes.SEMI) {
+            // Could be an old or new style for-loop.
+            List<LocatableToken> tlist = new LinkedList<LocatableToken>();
+
+            LocatableToken first = tokenStream.LA(1);
+            boolean isTypeSpec = false;
+            if (isModifier(tokenStream.LA(1))) {
+                parseModifiers();
+                isTypeSpec = true;
+                parseTypeSpec(false, true, tlist);
+            }
+            else {
+                isTypeSpec = parseTypeSpec(true, true, tlist);
+            }
+            
+            if (isTypeSpec && tokenStream.LA(1).getType() == JavaTokenTypes.IDENT) {
+                // for (type var ...
+                beginForInitDecl(first);
+                gotTypeSpec(tlist);
+                LocatableToken idToken = nextToken(); // identifier
+                gotForInit(first, idToken);
+                token = nextToken();
+                if (token.getType() == JavaTokenTypes.COLON) {
+                    // This is a "new" for loop (Java 5)
+                    endForInit(idToken, true);
+                    endForInitDecls(idToken, true);
+                    parseExpression();
+                    token = nextToken();
+                    if (token.getType() != JavaTokenTypes.RPAREN) {
+                        error("Expecting ')' (in for statement)");
+                        tokenStream.pushBack(token);
+                        endForLoop(token, false);
+                        return null;
+                    }
+                    token = nextToken();
+                    beginForLoopBody(token);
+                    token = parseStatement(token, false); // loop body
+                    endForLoopBody(token);
+                    endForLoop(token);
+                    return token;
+                }
+                else {
+                    // Old style loop with initialiser
+                    if (token.getType() == JavaTokenTypes.ASSIGN) {
+                        parseExpression();
+                    }
+                    else {
+                        tokenStream.pushBack(token);
+                    }
+                    if (parseSubsequentDeclarations(DECL_TYPE_FORINIT, true) == null) {
+                        endForLoop(tokenStream.LA(1), false);
+                        modifiersConsumed();
+                        return null;
+                    }
+                    modifiersConsumed();
+                }
+            }
+            else {
+                // Not a type spec, so, we might have a general statement
+                pushBackAll(tlist);
+                token = nextToken();
+                parseStatement(token, true);
+            }
+        }
+        else {
+            token = nextToken(); // SEMI
+        }
+
+        // We're expecting a regular (old-style) statement at this point
+        if (tokenStream.LA(1).getType() != JavaTokenTypes.SEMI) {
+            // test expression
+            parseExpression();
+        }
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.SEMI) {
+            tokenStream.pushBack(token);
+            if (token.getType() == JavaTokenTypes.COMMA) {
+                error(BJ003, token);  // common mistake: use ',' instead of ';'
+            }
+            else {
+                error(BJ003);
+            }
+            endForLoop(token, false);
+            return null;
+        }
+        if (tokenStream.LA(1).getType() != JavaTokenTypes.RPAREN) {
+            // loop increment expression
+            parseExpression();
+            while (tokenStream.LA(1).getType() == JavaTokenTypes.COMMA) {
+                nextToken();
+                parseExpression();
+            }
+        }
+        token = nextToken(); // ')'?
+        if (token.getType() != JavaTokenTypes.RPAREN) {
+            error("Expecting ')' (or ',') after 'for(...'");
+            tokenStream.pushBack(token);
+            endForLoop(token, false);
+            return null;
+        }
+        token = nextToken();
+        if (token.getType() == JavaTokenTypes.RCURLY
+                || token.getType() == JavaTokenTypes.EOF) {
+            error("Expecting statement after 'for(...)'");
+            tokenStream.pushBack(token);
+            endForLoop(token, false);
+            return null;
+        }
+        beginForLoopBody(token);
+        token = parseStatement(token, false);
+        endForLoopBody(token);
+        endForLoop(token);
+        return token;
+    }
+    
+    private void endForLoop(LocatableToken token)
+    {
+        if (token == null) {
+            endForLoop(tokenStream.LA(1), false);
+        }
+        else {
+            endForLoop(token, true);
+        }
+    }
+    
+    private void endForLoopBody(LocatableToken token)
+    {
+        if (token == null) {
+            endForLoopBody(tokenStream.LA(1), false);
+        }
+        else {
+            endForLoopBody(token, true);
+        }
+    }
+        
+    /**
+     * Parse an "if" statement.
+     * @param token  The token corresponding to the "if" literal.
+     */
+    public LocatableToken parseIfStatement(LocatableToken token)
+    {
+        beginIfStmt(token);
+        
+        mainLoop:
+        while(true) {
+            token = nextToken(); // "("
+            if (token.getType() != LPAREN) {
+                tokenStream.pushBack(token);
+                if (token.getType() == LCURLY) {
+                    error(BJ002, token);
+                }
+                else {
+                    errorBefore(BJ001, token);
+                }
+                endIfStmt(token, false);
+                return null;
+            }
+            parseExpression();
+            token = nextToken();
+            if (token.getType() != JavaTokenTypes.RPAREN) {
+                error("Expecting ')' after conditional expression (in 'if' statement)");
+                tokenStream.pushBack(token);
+                if (token.getType() != JavaTokenTypes.LCURLY) {
+                    endIfStmt(token, false);
+                    return null;
+                }
+            }
+            token = nextToken();
+            beginIfCondBlock(token);
+            token = parseStatement(token, false);
+            endIfCondBlock(token);
+            while (tokenStream.LA(1).getType() == JavaTokenTypes.LITERAL_else) {
+                tokenStream.nextToken(); // "else"
+                if (tokenStream.LA(1).getType() == JavaTokenTypes.LITERAL_if) {
+                    nextToken(); // "if"
+                    continue mainLoop;
+                }
+                token = nextToken();
+                beginIfCondBlock(token);
+                token = parseStatement(token, false);
+                endIfCondBlock(token);
+            }
+            endIfStmt(token);
+            return token;
+        }
+    }
+    
+    private void endIfCondBlock(LocatableToken token)
+    {
+        if (token != null) {
+            endIfCondBlock(token, true);
+        }
+        else {
+            endIfCondBlock(tokenStream.LA(1), false);
+        }
+    }
+    
+    private void endIfStmt(LocatableToken token)
+    {
+        if (token != null) {
+            endIfStmt(token, true);
+        }
+        else {
+            endIfStmt(tokenStream.LA(1), false);
+        }
+    }
+       
+    public LocatableToken parseVariableDeclarations()
+    {
+        LocatableToken first = tokenStream.LA(1);
+        gotDeclBegin(first);
+        return parseVariableDeclarations(first, true);
+    }
+    
+    /**
+     * Parse a variable declaration, possibly with an initialiser, usually followed by ';'
+     * 
+     * @param first   The first token of the declaration (should still be
+     *                in the token stream, unless it is a modifier)
+     * @param mustEndWithSemi  If false, specifies that the declaration need not be terminated by a semi-colon,
+     *                and that furthermore, the character terminating the declaration should be left in the token
+     *                stream.
+     */
+    public LocatableToken parseVariableDeclarations(LocatableToken first, boolean mustEndWithSemi)
+    {
+        beginVariableDecl(first);
+        parseModifiers();
+        boolean r = parseVariableDeclaration(first);
+        // parseVariableDeclaration calls modifiersConsumed(); i.e. we act as if
+        // the modifiers are consumed by the type rather than the variables.
+        // This is necessary because an initializer expression might contain an anonymous
+        // class containing modifiers.
+        if (r) {
+            return parseSubsequentDeclarations(DECL_TYPE_VAR, mustEndWithSemi);
+        }
+        else {
+            endVariableDecls(tokenStream.LA(1), false);
+            return null;
+        }
+    }
+
+    /* Types for parseSubsequentDeclarations and friends */
+    
+    /** for loop initializer */
+    protected static final int DECL_TYPE_FORINIT = 0;
+    /** variable */
+    protected static final int DECL_TYPE_VAR = 1;
+    /** field */
+    protected static final int DECL_TYPE_FIELD = 2;
+    
+    /**
+     * After seeing a type and identifier declaration, this will parse any
+     * the subsequent declarations, and check for a terminating semicolon.
+     * 
+     * @return  the last token that is part of the declarations, or null on error (or mustEndWithSemi == false).
+     */
+    protected LocatableToken parseSubsequentDeclarations(int type, boolean mustEndWithSemi)
+    {
+        LocatableToken prevToken = lastToken;
+        LocatableToken token = nextToken();
+        while (token.getType() == JavaTokenTypes.COMMA) {
+            endDeclaration(type, token, false);
+            LocatableToken first = token;
+            token = nextToken();
+            if (token.getType() != JavaTokenTypes.IDENT) {
+                endDeclarationStmt(type, token, false);
+                error("Expecting variable identifier (or change ',' to ';')");
+                return null;
+            }
+            parseArrayDeclarators();
+            LocatableToken idtoken = token;
+            prevToken = lastToken;
+            token = nextToken();
+            gotSubsequentDecl(type, first, idtoken, token.getType() == JavaTokenTypes.ASSIGN);
+            if (token.getType() == JavaTokenTypes.ASSIGN) {
+                parseExpression();
+                prevToken = lastToken;
+                token = nextToken();
+            }
+        }
+
+        if (! mustEndWithSemi) {
+            tokenStream.pushBack(token);
+            endDeclaration(type, token, false);
+            endDeclarationStmt(type, token, false);
+            return null;
+        }
+        
+        if (token.getType() != JavaTokenTypes.SEMI) {
+            tokenStream.pushBack(token);
+            errorBehind(BJ003, prevToken);
+            endDeclaration(type, token, false);
+            endDeclarationStmt(type, token, false);
+            return null;
+        }
+        else {
+            endDeclaration(type, token, true);
+            endDeclarationStmt(type, token, true);
+            return token;
+        }
+    }
+
+    private void endDeclaration(int type, LocatableToken token, boolean included)
+    {
+        if (type == DECL_TYPE_FIELD) {
+            endField(token, included);
+        }
+        else if (type == DECL_TYPE_VAR) {
+            endVariable(token, included);
+        }
+        else {
+            endForInit(token, included);
+        }
+    }
+    
+    private void endDeclarationStmt(int type, LocatableToken token, boolean included)
+    {
+        if (type == DECL_TYPE_FIELD) {
+            endFieldDeclarations(token, included);
+        }
+        else if (type == DECL_TYPE_VAR) {
+            endVariableDecls(token, included);
+        }
+        else {
+            endForInitDecls(token, included);
+        }
+    }
+    
+    private void gotSubsequentDecl(int type, LocatableToken firstToken,
+            LocatableToken nameToken, boolean inited)
+    {
+        if (type == DECL_TYPE_FIELD) {
+            gotSubsequentField(firstToken, nameToken);
+        }
+        else if (type == DECL_TYPE_VAR) {
+            gotSubsequentVar(firstToken, nameToken, inited);
+        }
+        else {
+            gotSubsequentForInit(firstToken, nameToken);
+        }
+    }
+    
+    /**
+     * Parse a variable (or field or parameter) declaration, possibly including an initialiser
+     * (but not including modifiers)
+     */
+    private boolean parseVariableDeclaration(LocatableToken first)
+    {
+        List<LocatableToken> typeSpecTokens = new LinkedList<LocatableToken>();
+        if (!parseTypeSpec(false, true, typeSpecTokens)) {
+            return false;
+        }
+        gotTypeSpec(typeSpecTokens);
+        
+        LocatableToken token = nextToken();
+        modifiersConsumed();
+        if (token.getType() != JavaTokenTypes.IDENT) {
+            error("Expecting identifier (in variable/field declaration)");
+            tokenStream.pushBack(token);
+            return false;
+        }
+        
+        // Array declarators can follow name
+        parseArrayDeclarators();
+
+        LocatableToken idToken = token;
+        token = nextToken();
+        gotVariableDecl(first, idToken, token.getType() == JavaTokenTypes.ASSIGN);
+
+        if (token.getType() == JavaTokenTypes.ASSIGN) {
+            parseExpression();
+        }
+        else {
+            tokenStream.pushBack(token);
+        }
+        return true;
+    }
+        
+    /**
+     * Parse a type specification. This includes class name(s) (Xyz.Abc), type arguments
+     * to generic types, and array declarators.
+     * 
+     * <p>The final set of array declarators will not be parsed if they contain a dimension value.
+     * Eg for "Abc[10][][]" this method will leave "[10][][]" unprocessed and still in the token stream.
+     * 
+     *  @param processArray   if false, no '[]' sequences will be parsed, only the element type.
+     *  @return  true iff a type specification was successfully parsed
+     */
+    public boolean parseTypeSpec(boolean processArray)
+    {
+        List<LocatableToken> tokens = new LinkedList<LocatableToken>();
+        boolean rval = parseTypeSpec(false, processArray, tokens);
+        if (rval) {
+            gotTypeSpec(tokens);
+        }
+        return rval;
+    }
+        
+    /**
+     * Parse a type specification. This could be a primitive type (including void),
+     * or a class type (qualified or not, possibly with type parameters). This can
+     * do a speculative parse if the following tokens might either be a type specification
+     * or a statement-expression.
+     * 
+     * @param speculative  Whether this is a speculative parse, i.e. we might not actually
+     *                     have a type specification. If this is set some parse errors will
+     *                     simply return false.
+     * @param processArray  Whether to parse '[]' array declarators. If false only the
+     *                     element type will be parsed.
+     * @param ttokens   A list which will be filled with tokens. If the return is true, the tokens
+     *                  make up a possible type specification; otherwise the tokens should be
+     *                  pushed back on the token stream.
+     * 
+     * @return true if we saw what might be a type specification (even if it
+     *                         contains errors), or false if it does not appear to be
+     *                     a type specification.
+     */
+    public boolean parseTypeSpec(boolean speculative, boolean processArray, List<LocatableToken> ttokens)
+    {
+        int ttype = parseBaseType(speculative, ttokens);
+        if (ttype == TYPE_ERROR) {
+            return false;
+        }
+        else if (ttype == TYPE_PRIMITIVE) {
+            speculative = false;
+        }
+        else {
+            LocatableToken token = nextToken();
+            if (token.getType() == JavaTokenTypes.LT) {
+                ttokens.add(token);
+
+                // Type parameters? (or is it a "less than" comparison?)
+                DepthRef dr = new DepthRef();
+                dr.depth = 1;
+                if (!parseTargs(speculative, ttokens, dr)) {
+                    return false;
+                }
+            }
+            else {
+                tokenStream.pushBack(token);
+            }
+        }
+
+        // check for inner type
+        LocatableToken token = nextToken();
+        if (token.getType() == JavaTokenTypes.DOT) {
+            if (tokenStream.LA(1).getType() == JavaTokenTypes.IDENT) {
+                ttokens.add(token);
+                return parseTypeSpec(speculative, true, ttokens);
+            }
+            else {
+                tokenStream.pushBack(token);
+                return true;
+            }
+        }
+        else if (processArray)
+        {
+            // check for array declarators
+            while (token.getType() == JavaTokenTypes.LBRACK
+                    && tokenStream.LA(1).getType() == JavaTokenTypes.RBRACK) {
+                ttokens.add(token);
+                token = nextToken(); // RBRACK
+                ttokens.add(token);
+                token = nextToken();
+            }
+        }
+
+        tokenStream.pushBack(token);
+        return true;
+    }
+
+    private static final int TYPE_PRIMITIVE = 0;
+    private static final int TYPE_OTHER = 1;
+    private static final int TYPE_ERROR = 2;
+
+    /**
+     * Parse a type "base" - a primitive type or a class type without type parameters.
+     * The type parameters may follow.
+     * 
+     * @param speculative
+     * @param ttokens
+     * @return
+     * @throws TokenStreamException
+     */
+    private int parseBaseType(boolean speculative, List<LocatableToken> ttokens)
+    {
+        LocatableToken token = nextToken();
+        if (isPrimitiveType(token)) {
+            // Ok, we have a base type
+            ttokens.add(token);
+            return TYPE_PRIMITIVE;
+        }
+        else {
+            if (token.getType() != JavaTokenTypes.IDENT) {
+                if (! speculative) {
+                    error("Expected type identifier");
+                }
+                tokenStream.pushBack(token);
+                return TYPE_ERROR;
+            }
+
+            ttokens.addAll(parseDottedIdent(token));
+        }
+        return TYPE_OTHER;
+    }
+
+    private boolean parseTargs(boolean speculative, List<LocatableToken> ttokens, DepthRef dr)
+    {
+        // We already have opening '<' and depth reflects this.
+
+        int beginDepth = dr.depth;
+        LocatableToken token;
+        boolean needBaseType = true;
+
+        while (dr.depth >= beginDepth) {
+
+            if (tokenStream.LA(1).getType() == JavaTokenTypes.QUESTION) {
+                // Wildcard
+                token = nextToken();
+                ttokens.add(token);
+                token = nextToken();
+                if (token.getType() == JavaTokenTypes.LITERAL_extends
+                        || token.getType() == JavaTokenTypes.LITERAL_super) {
+                    ttokens.add(token);
+                    needBaseType = true;
+                }
+                else {
+                    tokenStream.pushBack(token);
+                    needBaseType = false;
+                }
+            }
+
+            if (needBaseType) {
+                boolean r = parseTargType(speculative, ttokens, dr);
+                if (!r) {
+                    return false;
+                }
+                if (dr.depth < beginDepth) {
+                    break;
+                }
+            }
+
+            token = nextToken();
+            // Type parameters being closed
+            if (token.getType() == JavaTokenTypes.GT
+                    || token.getType() == JavaTokenTypes.SR
+                    || token.getType() == JavaTokenTypes.BSR) {
+                ttokens.add(token);
+                if (token.getType() == JavaTokenTypes.GT) {
+                    dr.depth--;
+                }
+                else if (token.getType() == JavaTokenTypes.SR) {
+                    dr.depth -= 2;
+                }
+                else if (token.getType() == JavaTokenTypes.BSR) {
+                    dr.depth -= 3;
+                }
+            }
+            else if (token.getType() == JavaTokenTypes.COMMA) {
+                needBaseType = true;
+                ttokens.add(token);
+            }
+            else {
+                if (! speculative) {
+                    error("Expected '>' to close type parameter list");
+                }
+                tokenStream.pushBack(token);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Parse a type argument, type part. The "? super" or "? extends" have already been dealt
+     * with. The type part may itself have type arguments, and might be followed by a comma
+     * or a closing '>' sequence.
+     * 
+     * @param speculative  Should be true if this is a speculative type parse
+     * @param ttokens  A list of tokens. All tokens processed will be added to this list.
+     * @param dr  Depth reference.
+     */
+    private boolean parseTargType(boolean speculative, List<LocatableToken> ttokens, DepthRef dr)
+    {
+        LocatableToken token;
+        int beginDepth = dr.depth;
+        
+        if (tokenStream.LA(1).getType() == JavaTokenTypes.GT) {
+            // Java 7 Diamond operator
+            ttokens.add(tokenStream.nextToken());
+            dr.depth--;
+            return true;
+        }
+        
+        int ttype = parseBaseType(speculative, ttokens);
+        if (ttype == TYPE_ERROR) {
+            return false;
+        }
+
+        if (ttype == TYPE_OTHER) {
+            // May be type parameters
+            if (tokenStream.LA(1).getType() == JavaTokenTypes.LT) {
+                dr.depth++;
+                ttokens.add(nextToken());
+                if (!parseTargs(speculative, ttokens, dr)) {
+                    return false;
+                }
+                if (dr.depth < beginDepth) {
+                    return true;
+                }
+            }
+
+            token = nextToken();
+            if (token.getType() == JavaTokenTypes.DOT && tokenStream.LA(1).getType() == JavaTokenTypes.IDENT) {
+                ttokens.add(token);
+                if (!parseTargType(speculative, ttokens, dr)) {
+                    return false;
+                }
+                return true;
+            }
+        }
+        else {
+            token = nextToken();
+        }
+
+        // Array declarators?
+        while (token.getType() == JavaTokenTypes.LBRACK
+                && tokenStream.LA(1).getType() == JavaTokenTypes.RBRACK) {
+            ttokens.add(token);
+            token = nextToken(); // RBRACK
+            ttokens.add(token);
+            token = nextToken();
+        }
+
+        tokenStream.pushBack(token);
+
+        return true;
+    }
+        
+    /**
+     * Parse a dotted identifier. This could be a variable, method or type name.
+     * @param first The first token in the dotted identifier (should be an IDENT)
+     * @return A list of tokens making up the dotted identifier
+     */
+    public List<LocatableToken> parseDottedIdent(LocatableToken first)
+    {
+        List<LocatableToken> rval = new LinkedList<LocatableToken>();
+        rval.add(first);
+        LocatableToken token = nextToken();
+        while (token.getType() == JavaTokenTypes.DOT) {
+            LocatableToken ntoken = nextToken();
+            if (ntoken.getType() != JavaTokenTypes.IDENT) {
+                // This could be for example "xyz.class"
+                tokenStream.pushBack(ntoken);
+                break;
+            }
+            rval.add(token);
+            rval.add(ntoken);
+            token = nextToken();
+        }
+        tokenStream.pushBack(token);
+        return rval;
+    }
+        
+    /**
+     * Check whether a token is an operator. Note that the LPAREN token can be an operator
+     * (method call) or value (parenthesized expression).
+     * 
+     * "new" is not classified as an operator here (an operator operates on a value).
+     */
+    public static boolean isOperator(LocatableToken token)
+    {
+        int ttype = token.getType();
+        return ttype == JavaTokenTypes.PLUS
+        || ttype == JavaTokenTypes.MINUS
+        || ttype == JavaTokenTypes.STAR
+        || ttype == JavaTokenTypes.DIV
+        || ttype == JavaTokenTypes.LBRACK
+        || ttype == JavaTokenTypes.LPAREN
+        || ttype == JavaTokenTypes.PLUS_ASSIGN
+        || ttype == JavaTokenTypes.STAR_ASSIGN
+        || ttype == JavaTokenTypes.MINUS_ASSIGN
+        || ttype == JavaTokenTypes.DIV_ASSIGN
+        || ttype == JavaTokenTypes.DOT
+        || ttype == JavaTokenTypes.EQUAL
+        || ttype == JavaTokenTypes.NOT_EQUAL
+        || ttype == JavaTokenTypes.LT
+        || ttype == JavaTokenTypes.LE
+        || ttype == JavaTokenTypes.GT
+        || ttype == JavaTokenTypes.GE
+        || ttype == JavaTokenTypes.ASSIGN
+        || ttype == JavaTokenTypes.BNOT
+        || ttype == JavaTokenTypes.LNOT
+        || ttype == JavaTokenTypes.INC
+        || ttype == JavaTokenTypes.DEC
+        || ttype == JavaTokenTypes.BOR
+        || ttype == JavaTokenTypes.BOR_ASSIGN
+        || ttype == JavaTokenTypes.BAND
+        || ttype == JavaTokenTypes.BAND_ASSIGN
+        || ttype == JavaTokenTypes.BXOR
+        || ttype == JavaTokenTypes.BXOR_ASSIGN
+        || ttype == JavaTokenTypes.LOR
+        || ttype == JavaTokenTypes.LAND
+        || ttype == JavaTokenTypes.SL
+        || ttype == JavaTokenTypes.SL_ASSIGN
+        || ttype == JavaTokenTypes.SR
+        || ttype == JavaTokenTypes.SR_ASSIGN
+        || ttype == JavaTokenTypes.BSR
+        || ttype == JavaTokenTypes.BSR_ASSIGN
+        || ttype == JavaTokenTypes.MOD
+        || ttype == JavaTokenTypes.MOD_ASSIGN
+        || ttype == JavaTokenTypes.LITERAL_instanceof;
+    }
+        
+    /**
+     * Check whether an operator is a binary operator.
+     * 
+     * "instanceof" is not considered to be a binary operator (operates on only one value).
+     */
+    public boolean isBinaryOperator(LocatableToken token)
+    {
+        int ttype = token.getType();
+        return ttype == JavaTokenTypes.PLUS
+        || ttype == JavaTokenTypes.MINUS
+        || ttype == JavaTokenTypes.STAR
+        || ttype == JavaTokenTypes.DIV
+        || ttype == JavaTokenTypes.MOD
+        || ttype == JavaTokenTypes.BOR
+        || ttype == JavaTokenTypes.BXOR
+        || ttype == JavaTokenTypes.BAND
+        || ttype == JavaTokenTypes.SL
+        || ttype == JavaTokenTypes.SR
+        || ttype == JavaTokenTypes.BSR
+        || ttype == JavaTokenTypes.BSR_ASSIGN
+        || ttype == JavaTokenTypes.SR_ASSIGN
+        || ttype == JavaTokenTypes.SL_ASSIGN
+        || ttype == JavaTokenTypes.BAND_ASSIGN
+        || ttype == JavaTokenTypes.BXOR_ASSIGN
+        || ttype == JavaTokenTypes.BOR_ASSIGN
+        || ttype == JavaTokenTypes.MOD_ASSIGN
+        || ttype == JavaTokenTypes.DIV_ASSIGN
+        || ttype == JavaTokenTypes.STAR_ASSIGN
+        || ttype == JavaTokenTypes.MINUS_ASSIGN
+        || ttype == JavaTokenTypes.PLUS_ASSIGN
+        || ttype == JavaTokenTypes.ASSIGN
+        || ttype == JavaTokenTypes.DOT
+        || ttype == JavaTokenTypes.EQUAL
+        || ttype == JavaTokenTypes.NOT_EQUAL
+        || ttype == JavaTokenTypes.LT
+        || ttype == JavaTokenTypes.LE
+        || ttype == JavaTokenTypes.GT
+        || ttype == JavaTokenTypes.GE
+        || ttype == JavaTokenTypes.LAND
+        || ttype == JavaTokenTypes.LOR;
+    }
+        
+    public boolean isUnaryOperator(LocatableToken token)
+    {
+        int ttype = token.getType();
+        return ttype == JavaTokenTypes.PLUS
+        || ttype == JavaTokenTypes.MINUS
+        || ttype == JavaTokenTypes.LNOT
+        || ttype == JavaTokenTypes.BNOT
+        || ttype == JavaTokenTypes.INC
+        || ttype == JavaTokenTypes.DEC;
+    }
+
+    /**
+     * Parse an annotation (having already seen '@', and having an identifier next in the token stream)
+     */
+    public void parseAnnotation()
+    {
+        LocatableToken token = nextToken(); // IDENT
+        parseDottedIdent(token);
+        if (tokenStream.LA(1).getType() == JavaTokenTypes.LPAREN) {
+            // arguments
+            token = tokenStream.nextToken(); // LPAREN
+            parseArgumentList(token);
+        }
+    }
+        
+    private static int [] expressionTokenIndexes = new int[JavaTokenTypes.INVALID+1];
+    
+    static {
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_new] = 1;
+        expressionTokenIndexes[JavaTokenTypes.LCURLY] = 2;
+        expressionTokenIndexes[JavaTokenTypes.IDENT] = 3;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_this] = 4;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_super] = 5;
+        
+        expressionTokenIndexes[JavaTokenTypes.STRING_LITERAL] = 6;
+        expressionTokenIndexes[JavaTokenTypes.CHAR_LITERAL] = 7;
+        expressionTokenIndexes[JavaTokenTypes.NUM_INT] = 8;
+        expressionTokenIndexes[JavaTokenTypes.NUM_LONG] = 9;
+        expressionTokenIndexes[JavaTokenTypes.NUM_DOUBLE] = 10;
+        expressionTokenIndexes[JavaTokenTypes.NUM_FLOAT] = 11;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_null] = 12;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_true] = 13;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_false] = 14;
+        
+        expressionTokenIndexes[JavaTokenTypes.LPAREN] = 15;
+        
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_void] = 16;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_boolean] = 17;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_byte] = 18;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_char] = 19;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_short] = 20;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_int] = 21;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_long] = 22;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_float] = 23;
+        expressionTokenIndexes[JavaTokenTypes.LITERAL_double] = 24;
+        
+        expressionTokenIndexes[JavaTokenTypes.PLUS] = 25;
+        expressionTokenIndexes[JavaTokenTypes.MINUS] = 26;
+        expressionTokenIndexes[JavaTokenTypes.LNOT] = 27;
+        expressionTokenIndexes[JavaTokenTypes.BNOT] = 28;
+        expressionTokenIndexes[JavaTokenTypes.INC] = 29;
+        expressionTokenIndexes[JavaTokenTypes.DEC] = 30;
+    }
+    
+    private static int [] expressionOpIndexes = new int[JavaTokenTypes.INVALID+1];
+    
+    static {
+        expressionOpIndexes[JavaTokenTypes.RPAREN] = 1;
+        expressionOpIndexes[JavaTokenTypes.SEMI] = 2;
+        expressionOpIndexes[JavaTokenTypes.RBRACK] = 3;
+        expressionOpIndexes[JavaTokenTypes.COMMA] = 4;
+        expressionOpIndexes[JavaTokenTypes.COLON] = 5;
+        expressionOpIndexes[JavaTokenTypes.EOF] = 6;
+        expressionOpIndexes[JavaTokenTypes.RCURLY] = 7;
+        
+        expressionOpIndexes[JavaTokenTypes.LBRACK] = 8;
+        expressionOpIndexes[JavaTokenTypes.LITERAL_instanceof] = 9;
+        expressionOpIndexes[JavaTokenTypes.DOT] = 10;
+        
+        // Binary operators (not DOT)
+        expressionOpIndexes[JavaTokenTypes.PLUS] = 11;
+        expressionOpIndexes[JavaTokenTypes.MINUS] = 11;
+        expressionOpIndexes[JavaTokenTypes.STAR] = 11;
+        expressionOpIndexes[JavaTokenTypes.DIV] = 11;
+        expressionOpIndexes[JavaTokenTypes.MOD] = 11;
+        expressionOpIndexes[JavaTokenTypes.BOR] = 11;
+        expressionOpIndexes[JavaTokenTypes.BXOR] = 11;
+        expressionOpIndexes[JavaTokenTypes.BAND] = 11;
+        expressionOpIndexes[JavaTokenTypes.SL] = 11;
+        expressionOpIndexes[JavaTokenTypes.SR] = 11;
+        expressionOpIndexes[JavaTokenTypes.BSR] = 11;
+        expressionOpIndexes[JavaTokenTypes.BSR_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.SR_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.SL_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.BAND_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.BXOR_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.BOR_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.MOD_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.DIV_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.STAR_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.MINUS_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.PLUS_ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.ASSIGN] = 11;
+        expressionOpIndexes[JavaTokenTypes.EQUAL] = 11;
+        expressionOpIndexes[JavaTokenTypes.NOT_EQUAL] = 11;
+        expressionOpIndexes[JavaTokenTypes.LT] = 11;
+        expressionOpIndexes[JavaTokenTypes.LE] = 11;
+        expressionOpIndexes[JavaTokenTypes.GT] = 11;
+        expressionOpIndexes[JavaTokenTypes.GE] = 11;
+        expressionOpIndexes[JavaTokenTypes.LAND] = 11;
+        expressionOpIndexes[JavaTokenTypes.LOR] = 11;
+    }
+    
+    /**
+     * Check whether the given token type can lead an
+     * expression.
+     */
+    private boolean isExpressionTokenType(int ttype)
+    {
+        return expressionTokenIndexes[ttype] != 0;
+    }
+    
+    /**
+     * Parse an expression
+     */
+    public void parseExpression()
+    {
+        LocatableToken token = nextToken();
+        beginExpression(token);
+
+        exprLoop:
+        while (true) {
+            int index = expressionTokenIndexes[token.getType()];
+            switch (index) {
+            case 1: // LITERAL_new
+                // new XYZ(...)
+                if (tokenStream.LA(1).getType() == JavaTokenTypes.EOF) {
+                    gotIdentifierEOF(token);
+                    endExpression(tokenStream.LA(1), true);
+                    return;
+                }
+                parseNewExpression(token);
+                break;
+            case 2: // LCURLY
+                // an initialiser list for an array
+                do {
+                    if (tokenStream.LA(1).getType() == JavaTokenTypes.RCURLY) {
+                        token = nextToken(); // RCURLY
+                        break;
+                    }
+                    parseExpression();
+                    token = nextToken();
+                } while (token.getType() == JavaTokenTypes.COMMA);
+                if (token.getType() != JavaTokenTypes.RCURLY) {
+                    errorBefore("Expected '}' at end of initialiser list expression", token);
+                    tokenStream.pushBack(token);
+                }
+                break;
+            case 3: // IDENT
+                if (tokenStream.LA(1).getType() == JavaTokenTypes.LPAREN) {
+                    // Method call
+                    gotMethodCall(token);
+                    parseArgumentList(nextToken());
+                }
+                else if (tokenStream.LA(1).getType() == JavaTokenTypes.DOT &&
+                        tokenStream.LA(2).getType() == JavaTokenTypes.IDENT &&
+                        tokenStream.LA(3).getType() != JavaTokenTypes.LPAREN) {
+                    gotCompoundIdent(token);
+                    nextToken(); // dot
+                    token = tokenStream.nextToken();
+                    while (tokenStream.LA(1).getType() == JavaTokenTypes.DOT &&
+                            tokenStream.LA(2).getType() == JavaTokenTypes.IDENT &&
+                            tokenStream.LA(3).getType() != JavaTokenTypes.LPAREN &&
+                            tokenStream.LA(3).getType() != JavaTokenTypes.EOF)
+                    {
+                        gotCompoundComponent(token);
+                        nextToken(); // dot
+                        token = tokenStream.nextToken();
+                    }
+                    
+                    // We either don't have a dot, or we do have a dot but not an
+                    // identifier after it.
+                    if (tokenStream.LA(1).getType() == JavaTokenTypes.DOT) {
+                        LocatableToken dotToken = nextToken();
+                        LocatableToken ntoken = nextToken();
+                        if (ntoken.getType() == JavaTokenTypes.LITERAL_class) {
+                            completeCompoundClass(token);
+                            gotClassLiteral(ntoken);
+                        }
+                        else if (ntoken.getType() == JavaTokenTypes.LITERAL_this) {
+                            completeCompoundClass(token);
+                            // TODO gotThisAccessor
+                        }
+                        else if (ntoken.getType() == JavaTokenTypes.LITERAL_super) {
+                            completeCompoundClass(token);
+                            // TODO gotSuperAccessor
+                        }
+                        else {
+                            completeCompoundValue(token);
+                            // Treat dot as an operator (below)
+                            tokenStream.pushBack(ntoken);
+                            tokenStream.pushBack(dotToken);
+                        }
+                    }
+                    else {
+                        // No dot follows; last member
+                        if (tokenStream.LA(1).getType() == JavaTokenTypes.EOF) {
+                            completeCompoundValueEOF(token);
+                        }
+                        else {
+                            if (tokenStream.LA(1).getType() == JavaTokenTypes.LBRACK
+                                    && tokenStream.LA(2).getType() == JavaTokenTypes.RBRACK) {
+                                completeCompoundClass(token);
+                                parseArrayDeclarators();
+                                if (tokenStream.LA(1).getType() == JavaTokenTypes.DOT &&
+                                        tokenStream.LA(2).getType() == JavaTokenTypes.LITERAL_class) {
+                                    token = nextToken();
+                                    token = nextToken();
+                                    gotClassLiteral(token);
+                                }
+                                else {
+                                    error("Expecting \".class\"");
+                                }
+                            }
+                            completeCompoundValue(token);
+                        }
+                    }
+                }
+                else if (tokenStream.LA(1).getType() == JavaTokenTypes.DOT) {
+                    gotIdentifier(token);
+                    if (tokenStream.LA(2).getType() == JavaTokenTypes.LITERAL_class) {
+                        token = nextToken(); // dot
+                        token = nextToken(); // class
+                        gotClassLiteral(token);
+                    }
+                }
+                else if (tokenStream.LA(1).getType() == JavaTokenTypes.LBRACK
+                        && tokenStream.LA(2).getType() == JavaTokenTypes.RBRACK) {
+                    gotIdentifier(token);
+                    parseArrayDeclarators();
+                    if (tokenStream.LA(1).getType() == JavaTokenTypes.DOT &&
+                            tokenStream.LA(2).getType() == JavaTokenTypes.LITERAL_class) {
+                        token = nextToken();
+                        token = nextToken();
+                        gotClassLiteral(token);
+                    }
+                    else {
+                        error("Expecting \".class\"");
+                    }
+                }
+                else if (tokenStream.LA(1).getType() == JavaTokenTypes.EOF) {
+                    gotIdentifierEOF(token);
+                }
+                else {
+                    gotIdentifier(token);
+                }
+                break;
+            case 4: // LITERAL_this
+            case 5: // LITERAL_super
+                if (tokenStream.LA(1).getType() == JavaTokenTypes.LPAREN) {
+                    // call to constructor or superclass constructor
+                    gotConstructorCall(token);
+                    parseArgumentList(nextToken());
+                }
+                else {
+                    gotLiteral(token);
+                }
+                break;
+            case 6: // STRING_LITERAL
+            case 7: // CHAR_LITERAL
+            case 8: // NUM_INT
+            case 9: // NUM_LONG
+            case 10: // NUM_DOUBLE
+            case 11: // NUM_FLOAT
+            case 12: // LITERAL_null
+            case 13: // LITERAL_true
+            case 14: // LITERAL_false
+                // Literals need no further processing
+                gotLiteral(token);
+                break;
+            case 15: // LPAREN
+                // Either a parenthesised expression, or a type cast
+                // We handle cast to primitive specially - it can be followed by +, ++, -, --
+                // and yet be a cast.
+                boolean isPrimitive = isPrimitiveType(tokenStream.LA(1));
+
+                List<LocatableToken> tlist = new LinkedList<LocatableToken>();
+                boolean isTypeSpec = parseTypeSpec(true, true, tlist);
+                
+                // We have a cast if
+                // -it's a type spec
+                // -it's followed by ')'
+                // -it's not followed by an operator OR
+                //  the type is primitive and the following operator is a unary operator
+                //  OR following the ')' is '('
+                // -it's not followed by an expression terminator - ; : , ) } ] EOF
+
+                int tt2 = tokenStream.LA(2).getType();
+                boolean isCast = isTypeSpec && tokenStream.LA(1).getType() == JavaTokenTypes.RPAREN;
+                if (tt2 != JavaTokenTypes.LPAREN) {
+                    isCast &= !isOperator(tokenStream.LA(2)) || (isPrimitive
+                            && isUnaryOperator(tokenStream.LA(2)));
+                    isCast &= tt2 != JavaTokenTypes.SEMI && tt2 != JavaTokenTypes.RPAREN
+                            && tt2 != JavaTokenTypes.RCURLY && tt2 != JavaTokenTypes.EOF;
+                    isCast &= tt2 != JavaTokenTypes.COMMA && tt2 != JavaTokenTypes.COLON
+                            && tt2 != JavaTokenTypes.RBRACK;
+                }
+
+                if (isCast) {
+                    // This surely must be type cast
+                    gotTypeCast(tlist);
+                    token = nextToken(); // RPAREN
+                    token = nextToken();
+                    continue exprLoop;
+                }
+                else {
+                    pushBackAll(tlist);
+                    parseExpression();
+                    token = nextToken();
+                    if (token.getType() != JavaTokenTypes.RPAREN) {
+                        tokenStream.pushBack(token);
+                        error("Unmatched '(' in expression; expecting ')'");
+                        endExpression(token, false);
+                        return;
+                    }
+                }
+                break;
+            case 16: // LITERAL_void
+            case 17: // LITERAL_boolean
+            case 18: // LITERAL_byte
+            case 19: // LITERAL_char
+            case 20: // LITERAL_short
+            case 21: // LITERAL_int
+            case 22: // LITERAL_long
+            case 23: // LITERAL_float
+            case 24: // LITERAL_double
+                // Not really part of an expression, but may be followed by
+                // .class or [].class  (eg int.class, int[][].class)
+                gotPrimitiveTypeLiteral(token);
+                parseArrayDeclarators();
+                if (tokenStream.LA(1).getType() == JavaTokenTypes.DOT &&
+                        tokenStream.LA(2).getType() == JavaTokenTypes.LITERAL_class) {
+                    token = nextToken();
+                    token = nextToken();
+                    gotClassLiteral(token);
+                }
+                else {
+                    error("Expecting \".class\"");
+                }
+                break;
+            case 25: // PLUS
+            case 26: // MINUS
+            case 27: // LNOT
+            case 28: // BNOT
+            case 29: // INC
+            case 30: // DEC
+                // Unary operator
+                gotUnaryOperator(token);
+                token = nextToken();
+                continue exprLoop;
+            default:
+                tokenStream.pushBack(token);
+                error("Invalid expression token: " + token.getText());
+                endExpression(token, true);
+                return;
+            }
+
+            // Now we get an operator, or end of expression
+            opLoop:
+            while (true) {
+                token = tokenStream.nextToken();
+                switch (expressionOpIndexes[token.getType()]) {
+                case 1: // RPAREN
+                case 2: // SEMI
+                case 3: // RBRACK
+                case 4: // COMMA
+                case 5: // COLON
+                case 6: // EOF
+                case 7: // RCURLY
+                    // These are all legitimate expression endings
+                    tokenStream.pushBack(token);
+                    endExpression(token, false);
+                    return;
+                case 8: // LBRACK
+                    // Array subscript?
+                    if (tokenStream.LA(1).getType() == JavaTokenTypes.RBRACK) {
+                        // No subscript means that this is a type - must be followed by
+                        // ".class" normally. Eg Object[].class
+                        token = nextToken(); // RBRACK
+                        continue;
+                    }
+                    parseExpression();
+                    token = nextToken();
+                    if (token.getType() != JavaTokenTypes.RBRACK) {
+                        error("Expected ']' after array subscript expression");
+                        tokenStream.pushBack(token);
+                    }
+                    gotArrayElementAccess();
+                    break;
+                case 9: // LITERAL_instanceof
+                    gotInstanceOfOperator(token);
+                    parseTypeSpec(true);
+                    break;
+                case 10: // DOT
+                    // Handle dot operator specially, as there are some special cases
+                    LocatableToken opToken = token;
+                    token = nextToken();
+                    if (token.getType() == JavaTokenTypes.EOF) {
+                        // Not valid, but may be useful for subclasses
+                        gotDotEOF(opToken);
+                        break opLoop;
+                    }
+                    LocatableToken la1 = tokenStream.LA(1);
+                    if (la1.getType() == JavaTokenTypes.EOF
+                            && la1.getColumn() == token.getEndColumn()
+                            && la1.getLine() == token.getEndLine()) {
+                        // Something that might look like a keyword, but might in fact
+                        // be partially complete identifier.
+                        String tokText = token.getText();
+                        if (tokText != null && tokText.length() > 0) {
+                            if (Character.isJavaIdentifierStart(tokText.charAt(0))) {
+                                gotMemberAccessEOF(token);
+                                // break opLoop;
+                                continue;
+                            }
+                        }
+                    }
+                    
+                    if (token.getType() == JavaTokenTypes.LITERAL_class) {
+                        // Class literal: continue and look for another operator
+                        continue;
+                    }
+                    else if (token.getType() == JavaTokenTypes.IDENT) {
+                        if (tokenStream.LA(1).getType() == JavaTokenTypes.LPAREN) {
+                            // Method call
+                            gotMemberCall(token, Collections.<LocatableToken>emptyList());
+                            parseArgumentList(nextToken());
+                        }
+                        else {
+                            gotMemberAccess(token);
+                        }
+                        continue;
+                    }
+                    else if (token.getType() == JavaTokenTypes.LT) {
+                        // generic method call
+                        DepthRef dr = new DepthRef();
+                        List<LocatableToken> ttokens = new LinkedList<LocatableToken>();
+                        ttokens.add(token);
+                        dr.depth = 1;
+                        if (!parseTargs(false, ttokens, dr)) {
+                            continue;  // we're a bit lost now really...
+                        }
+                        token = nextToken();
+                        if (token.getType() != JavaTokenTypes.IDENT) {
+                            error("Expecting method name (in call to generic method)");
+                            continue;
+                        }
+                        gotMemberCall(token, ttokens);
+                        token = nextToken();
+                        if (token.getType() != JavaTokenTypes.LPAREN) {
+                            error("Expecting '(' after method name");
+                            continue;
+                        }
+                        parseArgumentList(token);
+                        continue;
+                    }
+                    gotBinaryOperator(opToken);
+                    break opLoop;
+                case 11: // binary operator
+                    // Binary operators - need another operand
+                    gotBinaryOperator(token);
+                    token = nextToken();
+                    break opLoop;
+                    
+                default:
+                    if (token.getType() == JavaTokenTypes.INC
+                            || token.getType() == JavaTokenTypes.DEC) {
+                        // post operators (unary)
+                        continue;
+                    }
+                    else if (token.getType() == JavaTokenTypes.QUESTION) {
+                        gotQuestionOperator(token);
+                        parseExpression();
+                        token = nextToken();
+                        if (token.getType() != JavaTokenTypes.COLON) {
+                            error("Expecting ':' (in ?: operator)");
+                            tokenStream.pushBack(token);
+                            endExpression(token, true);
+                            return;
+                        }
+                        token = nextToken();
+                        break opLoop;
+                    }
+                    else {
+                        tokenStream.pushBack(token);
+                        endExpression(token, false);
+                        return;
+                    }
+                }
+            }
+        }
+    }
+    
+    public LocatableToken parseArrayInitializerList(LocatableToken token)
+    {
+        // an initialiser list for an array
+        do {
+            if (tokenStream.LA(1).getType() == JavaTokenTypes.RCURLY) {
+                token = nextToken(); // RCURLY
+                break;
+            }
+            parseExpression();
+            token = nextToken();
+        } while (token.getType() == JavaTokenTypes.COMMA);
+        if (token.getType() != JavaTokenTypes.RCURLY) {
+            errorBefore("Expected '}' at end of initialiser list expression", token);
+            tokenStream.pushBack(token);
+        }
+        return token;
+    }
+    
+    public void parseNewExpression(LocatableToken token)
+    {
+        // new XYZ(...)
+        gotExprNew(token);
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.IDENT && !isPrimitiveType(token)) {
+            tokenStream.pushBack(token);
+            error("Expected type identifier after \"new\" (in expression)");
+            endExprNew(token, false);
+            return;
+        }
+        tokenStream.pushBack(token);
+        parseTypeSpec(false);
+        token = nextToken();
+
+        if (token.getType() == JavaTokenTypes.LBRACK) {
+            while (true) {
+                // array dimensions
+                boolean withDimension = false;
+                if (tokenStream.LA(1).getType() != JavaTokenTypes.RBRACK) {
+                    withDimension = true;
+                    parseExpression();
+                }
+                token = nextToken();
+                if (token.getType() != JavaTokenTypes.RBRACK) {
+                    tokenStream.pushBack(token);
+                    errorBefore("Expecting ']' after array dimension (in new ... expression)", token);
+                    endExprNew(token, false);
+                    return;
+                }
+                else {
+                    gotNewArrayDeclarator(withDimension);
+                }
+                if (tokenStream.LA(1).getType() != JavaTokenTypes.LBRACK) {
+                    break;
+                }
+                token = nextToken();
+            }
+            
+            if (tokenStream.LA(1).getType() == JavaTokenTypes.LCURLY) {
+                // Array initialiser list
+                token = nextToken();
+                beginArrayInitList(token);
+                token = parseArrayInitializerList(token);
+                endArrayInitList(token);
+                endExprNew(token, token.getType() == JavaTokenTypes.RCURLY);
+                return;
+            }
+
+            endExprNew(token, true);
+            return;
+        }
+
+        if (token.getType() != JavaTokenTypes.LPAREN) {
+            tokenStream.pushBack(token);
+            error("Expected '(' or '[' after type name (in 'new ...' expression)");
+            endExprNew(token, false);
+            return;
+        }
+        parseArgumentList(token);
+
+        if (tokenStream.LA(1).getType() == JavaTokenTypes.LCURLY) {
+            // a class body (anonymous inner class)
+            token = nextToken(); // LCURLY
+            beginAnonClassBody(token, false);
+            parseClassBody();
+            token = nextToken();
+            if (token.getType() != JavaTokenTypes.RCURLY) {
+                error("Expected '}' at end of inner class body");
+                tokenStream.pushBack(token);
+                tokenStream.pushBack(token);
+                endAnonClassBody(token, false);
+                endExprNew(token, false);
+                return;
+            }
+            endAnonClassBody(token, true);
+        }
+        endExprNew(token, true);
+    }
+    
+    /**
+     * Parse a comma-separated, possibly empty list of arguments to a method/constructor.
+     * The closing ')' will be consumed by this method. 
+     * @param token   the '(' token
+     */
+    public void parseArgumentList(LocatableToken token)
+    {
+        beginArgumentList(token);
+        token = nextToken();
+        if (token.getType() != JavaTokenTypes.RPAREN) {
+            tokenStream.pushBack(token);
+            do  {
+                parseExpression();
+                token = nextToken();
+                endArgument();
+            } while (token.getType() == JavaTokenTypes.COMMA);
+            if (token.getType() != JavaTokenTypes.RPAREN) {
+                errorBefore("Expecting ',' or ')' (in argument list)", token);
+                tokenStream.pushBack(token);
+            }
+        }
+        endArgumentList(token);
+        return;
+    }
+    
+    /**
+     * Parse a list of formal parameters (possibly empty)
+     */
+    public void parseParameterList()
+    {
+        LocatableToken token = nextToken();
+        while (token.getType() != JavaTokenTypes.RPAREN
+                && token.getType() != JavaTokenTypes.RCURLY) {
+            tokenStream.pushBack(token);
+
+            parseModifiers();
+            parseTypeSpec(true);
+            LocatableToken idToken = nextToken(); // identifier
+            LocatableToken varargsToken = null;
+            if (idToken.getType() == JavaTokenTypes.TRIPLE_DOT) {
+                // var args
+                varargsToken = idToken;
+                idToken = nextToken();
+            }
+            if (idToken.getType() != JavaTokenTypes.IDENT) {
+                error("Expected parameter identifier (in method parameter)");
+                // TODO skip to next ',', ')' or '}' if there is one soon (LA(3)?)
+                tokenStream.pushBack(idToken);
+                return;
+            }
+            parseArrayDeclarators();
+            gotMethodParameter(idToken, varargsToken);
+            modifiersConsumed();
+            token = nextToken();
+            if (token.getType() != JavaTokenTypes.COMMA) {
+                break;
+            }
+            token = nextToken();
+        }
+        tokenStream.pushBack(token);
+    }
+        
+    private void pushBackAll(List<LocatableToken> tokens)
+    {
+        ListIterator<LocatableToken> i = tokens.listIterator(tokens.size());
+        while (i.hasPrevious()) {
+            tokenStream.pushBack(i.previous());
+        }
+    }
+
+    private class DepthRef
+    {
+        int depth;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/MethodCompletion.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/MethodCompletion.java
new file mode 100644
index 0000000000000000000000000000000000000000..9085012a9459a3d56952eb4ea605a66f1d0be17a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/MethodCompletion.java
@@ -0,0 +1,215 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.MethodReflective;
+import bluej.pkgmgr.JavadocResolver;
+
+/**
+ * Possible code completion for a method.
+ * 
+ * @author Davin McCall
+ */
+public class MethodCompletion extends AssistContent
+{
+    private MethodReflective method;
+    private JavadocResolver javadocResolver;
+    private Map<String,GenTypeParameter> typeArgs;
+    
+    /**
+     * Construct a new method completion
+     * @param method    The method to represent
+     * @param typeArgs   The type arguments applied to the declaring class. For a method
+     *                   call on a raw expression, will be null.
+     * @param javadocResolver  The javadoc resolver to use
+     */
+    public MethodCompletion(MethodReflective method,
+            Map<String,GenTypeParameter> typeArgs,
+            JavadocResolver javadocResolver)
+    {
+        this.method = method;
+        if (typeArgs != null) {
+            List<GenTypeDeclTpar> mtpars = method.getTparTypes();
+            if (! mtpars.isEmpty()) {
+                // The method has its own type parameters - these override the class parameters.
+                Map<String,GenTypeParameter> fullArgMap = new HashMap<String,GenTypeParameter>();
+                fullArgMap.putAll(typeArgs);
+                for (GenTypeDeclTpar mtpar : mtpars) {
+                    fullArgMap.put(mtpar.getTparName(), mtpar);
+                }
+                this.typeArgs = fullArgMap;
+            }
+            else {
+                this.typeArgs = typeArgs;
+            }
+        }
+        this.javadocResolver = javadocResolver;
+    }
+    
+    @Override
+    public String getDeclaringClass()
+    {
+        return method.getDeclaringType().getSimpleName();
+    }
+    
+    @Override
+    public String getDisplayMethodName()
+    {
+        return method.getName();
+    }
+
+    @Override
+    public String getDisplayMethodParams()
+    {
+        return getDisplayMethodParams(true);
+    }
+    
+    public String getDisplayMethodParams(boolean includeNames)
+    {
+        List<String> paramNames = includeNames ? method.getParamNames() : null;
+        Iterator<String> nameIterator = paramNames != null ? paramNames.iterator() : null;
+        
+        String displayName = "(";
+        List<JavaType> paramTypes = method.getParamTypes();
+        for (Iterator<JavaType> i = paramTypes.iterator(); i.hasNext(); ) {
+            JavaType paramType = convertToSolid(i.next());
+            displayName += paramType.toString(true);
+            if (nameIterator != null) {
+                displayName += " " + nameIterator.next();
+            }
+            if (i.hasNext()) {
+                displayName += ", ";
+            }
+        }
+        displayName += ")";
+        
+        return displayName;
+    }
+
+    @Override
+    public String getDisplayName()
+    {
+        return getDisplayMethodName() + getDisplayMethodParams(false);
+    }
+    
+    @Override
+    public String getCompletionText()
+    {
+        return method.getName() + "(";
+    }
+    
+    @Override
+    public String getCompletionTextSel()
+    {
+        List<JavaType> paramTypes = method.getParamTypes();
+        if (! paramTypes.isEmpty()) {
+            List<String> paramNames = method.getParamNames();
+            if (paramNames == null || paramNames.isEmpty()) {
+                return buildParam(1, paramTypes.get(0), null);
+            }
+            else {
+                return buildParam(1, paramTypes.get(0), paramNames.get(0));
+            }
+        }
+        return "";
+    }
+    
+    @Override
+    public String getCompletionTextPost()
+    {
+        String r = ")";
+        List<JavaType> paramTypes = method.getParamTypes();
+        if (paramTypes.size() > 1) {
+            String paramStr = "";
+            List<String> paramNames = method.getParamNames();
+            paramNames = (paramNames == null) ? Collections.<String>emptyList() : paramNames;
+            Iterator<JavaType> ti = paramTypes.iterator();
+            Iterator<String> ni = paramNames.iterator();
+            ti.next();
+            if (ni.hasNext()) ni.next();
+            int i = 2;
+            while (ti.hasNext()) {
+                String name = ni.hasNext() ? ni.next() : null;
+                paramStr += ", " + buildParam(i++, ti.next(), name);
+            }
+            r = paramStr + r;
+        }
+        
+        return r;
+    }
+    
+    @Override
+    public String getReturnType()
+    {
+        return convertToSolid(method.getReturnType()).toString(true);
+    }
+
+    @Override
+    public String getJavadoc()
+    {
+        String jd = method.getJavaDoc();
+        if (jd == null && javadocResolver != null) {
+            javadocResolver.getJavadoc(method);
+            jd = method.getJavaDoc();
+        }
+        return jd;
+    }
+
+    @Override
+    public boolean hasParameters()
+    {
+        return !method.getParamTypes().isEmpty();
+    }
+    
+    private JavaType convertToSolid(JavaType type)
+    {
+        if (! type.isPrimitive()) {
+            if (typeArgs != null) {
+                type = type.mapTparsToTypes(typeArgs).getUpperBound();
+            }
+            else {
+                // null indicates a raw type.
+                type = type.getErasedType();
+            }
+        }
+        return type;
+    }
+    
+    private static String buildParam(int pnum, JavaType paramType, String paramName)
+    {
+        if (paramName != null) {
+            return "_" + paramName + "_";
+        }
+        else {
+            return "_" + paramType.toString(true) + "_";
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/ParseFailure.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/ParseFailure.java
new file mode 100644
index 0000000000000000000000000000000000000000..52aefb78bced261ffe1b44024385aa77a755f0d9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/ParseFailure.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+/**
+ * An exception to throw when a parse failure occurs.
+ * 
+ * @author Davin McCall
+ */
+public class ParseFailure extends RuntimeException
+{
+    public ParseFailure()
+    {
+    }
+    
+    public ParseFailure(String message)
+    {
+        super(message);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/ParseUtils.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/ParseUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..0700ca9fe5d3f2e10a455fae957b8e62d057e6c5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/ParseUtils.java
@@ -0,0 +1,458 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import bluej.debugger.gentype.GenTypeArrayClass;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.JavaPrimitiveType;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.MethodReflective;
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.ImportedEntity;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.ParsedArrayReflective;
+import bluej.parser.entity.SolidTargEntity;
+import bluej.parser.entity.TypeArgumentEntity;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.entity.UnboundedWildcardEntity;
+import bluej.parser.entity.UnresolvedArray;
+import bluej.parser.entity.UnresolvedEntity;
+import bluej.parser.entity.WildcardExtendsEntity;
+import bluej.parser.entity.WildcardSuperEntity;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+import bluej.pkgmgr.JavadocResolver;
+import bluej.utility.JavaReflective;
+import bluej.utility.JavaUtils;
+
+/**
+ * Utilities for parsers.
+ * 
+ * @author Davin McCall
+ */
+public class ParseUtils
+{
+    private static class DepthRef
+    {
+        int depth = 0;
+    }
+    
+    /**
+     * Get the possible code completions, based on the provided suggestions and string prefix.
+     * If there are can be no valid completions in the give context, returns null.
+     * If there are valid completions but the given prefix doesn't match any of them,
+     * returns an empty array.
+     */
+    public static AssistContent[] getPossibleCompletions(CodeSuggestions suggests, String prefix,
+            JavadocResolver javadocResolver)
+    {
+        if (suggests != null) {
+            GenTypeClass exprType = suggests.getSuggestionType().asClass();
+            if (exprType == null) {
+                final JavaType arrayComponent = suggests.getSuggestionType().getArrayComponent();
+                if (arrayComponent != null && arrayComponent.isPrimitive()) {
+                    // Array of primitives:
+                    // For code completion purposes, consider this as an array of object with a tweaked name:
+                    exprType = new GenTypeArrayClass(new ParsedArrayReflective(new JavaReflective(Object.class),"Object")
+                    {
+                        public String getSimpleName()
+                        {
+                            return arrayComponent.toString() + "[]";
+                        }
+                        
+                    }, arrayComponent);
+                }
+                else {
+                    return null;
+                }
+            }
+            
+            GenTypeClass accessType = suggests.getAccessType();
+            Reflective accessReflective = (accessType != null) ? accessType.getReflective() : null;
+
+            // Use two sets, one to keep track of which types we have already processed,
+            // another for individual methods.
+            Set<String> contentSigs = new HashSet<String>();
+            Set<String> typesDone = new HashSet<String>();
+            List<AssistContent> completions = new ArrayList<AssistContent>();
+
+            LinkedList<GenTypeClass> typeQueue = new LinkedList<GenTypeClass>();
+            typeQueue.add(exprType);
+            GenTypeClass origExprType = exprType;
+            
+            while (! typeQueue.isEmpty()) {
+                exprType = typeQueue.removeFirst();
+                if (! typesDone.add(exprType.getReflective().getName())) {
+                    // we've already done this type...
+                    continue;
+                }
+                Map<String,Set<MethodReflective>> methods = exprType.getReflective().getDeclaredMethods();
+                Map<String,GenTypeParameter> typeArgs = exprType.getMap();
+
+                for (String name : methods.keySet()) {
+                    Set<MethodReflective> mset = methods.get(name);
+                    for (MethodReflective method : mset) {
+                        if (accessReflective != null &&
+                                ! JavaUtils.checkMemberAccess(method.getDeclaringType(),
+                                        origExprType,
+                                        suggests.getAccessType().getReflective(),
+                                        method.getModifiers(), suggests.isStatic())) {
+                            continue;
+                        }
+                        Map<String,GenTypeParameter> declMap =
+                            exprType.mapToSuper(method.getDeclaringType().getName()).getMap();
+                        MethodCompletion completion = new MethodCompletion(method,
+                                declMap, javadocResolver);
+                        String sig = completion.getDisplayName();
+                        if (contentSigs.add(sig)) {
+                            completions.add(new MethodCompletion(method, typeArgs, javadocResolver));
+                        }
+                    }
+                }
+
+                for (GenTypeClass stype : exprType.getReflective().getSuperTypes()) {
+                    if (typeArgs != null) {
+                        typeQueue.add(stype.mapTparsToTypes(typeArgs));
+                    }
+                    else {
+                        typeQueue.add(stype.getErasedType());
+                    }
+                }
+                
+                Reflective outer = exprType.getReflective().getOuterClass();
+                if (outer != null) {
+                    typeQueue.add(new GenTypeClass(outer));
+                }
+            }
+
+            // Sort the completions by name
+            Collections.sort(completions, new Comparator<AssistContent>() {
+                @Override
+              public Comparator<AssistContent> reversed() {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<AssistContent> thenComparing(
+                  Comparator<? super AssistContent> other) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public <U> Comparator<AssistContent> thenComparing(
+                  Function<? super AssistContent, ? extends U> keyExtractor,
+                  Comparator<? super U> keyComparator) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public <U extends Comparable<? super U>> Comparator<AssistContent> thenComparing(
+                  Function<? super AssistContent, ? extends U> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<AssistContent> thenComparingInt(
+                  ToIntFunction<? super AssistContent> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<AssistContent> thenComparingLong(
+                  ToLongFunction<? super AssistContent> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<AssistContent> thenComparingDouble(
+                  ToDoubleFunction<? super AssistContent> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+                public int compare(AssistContent o1, AssistContent o2)
+                {
+                    return o1.getDisplayName().compareTo(o2.getDisplayName());
+                }
+            });
+
+            return (AssistContent []) completions.toArray(new AssistContent[completions.size()]);
+        }
+
+        return null; // no completions
+    }
+    
+    /**
+     * Get an entity for an imported type specifier. This is different from a non-imported type
+     * because in that it must be qualified.
+     * 
+     * @param resolver  Entity resolver which will (eventually) resolve the entity
+     * @param tokens  The tokens making up the specification
+     */
+    public static JavaEntity getImportEntity(EntityResolver resolver,
+            Reflective querySource, List<LocatableToken> tokens)
+    {
+        if (tokens.isEmpty()) {
+            return null;
+        }
+        
+        Iterator<LocatableToken> i = tokens.iterator();
+        LocatableToken tok = i.next();
+        if (tok.getType() != JavaTokenTypes.IDENT) {
+            return null;
+        }
+        
+        List<String> names = new LinkedList<String>();
+        names.add(tok.getText());
+        
+        while (i.hasNext()) {
+            tok = i.next();
+            if (tok.getType() != JavaTokenTypes.DOT || ! i.hasNext()) {
+                return null;
+            }
+            tok = i.next();
+            if (tok.getType() != JavaTokenTypes.IDENT) {
+                return null;
+            }
+            names.add(tok.getText());
+        }
+        
+        return new ImportedEntity(resolver, names, querySource);
+    }
+    
+    /**
+     * Get an entity for a type specification (specified by a list of tokens). The
+     * returned entity might be unresolved.
+     * 
+     * @param resolver   Entity resolver which will (eventually) resolve the entity
+     * @param querySource  The source of the query - a fully qualified class name
+     * @param tokens  The tokens specifying the type
+     */
+    public static JavaEntity getTypeEntity(EntityResolver resolver,
+            Reflective querySource, List<LocatableToken> tokens)
+    {
+        DepthRef dr = new DepthRef();
+        return getTypeEntity(resolver, querySource, tokens.listIterator(), dr);
+    }
+    
+    /**
+     * Get an entity for a type specification. The returned entity may be unresolved.
+     * Returns null if the type specification appears to be invalid.
+     */
+    private static JavaEntity getTypeEntity(EntityResolver resolver, Reflective querySource,
+            ListIterator<LocatableToken> i, DepthRef depthRef)
+    {
+        LocatableToken token = i.next();
+        if (JavaParser.isPrimitiveType(token)) {
+            JavaType type = null;
+            switch (token.getType()) {
+            case JavaTokenTypes.LITERAL_int:
+                type = JavaPrimitiveType.getInt();
+                break;
+            case JavaTokenTypes.LITERAL_short:
+                type = JavaPrimitiveType.getShort();
+                break;
+            case JavaTokenTypes.LITERAL_long:
+                type = JavaPrimitiveType.getLong();
+                break;
+            case JavaTokenTypes.LITERAL_char:
+                type = JavaPrimitiveType.getChar();
+                break;
+            case JavaTokenTypes.LITERAL_byte:
+                type = JavaPrimitiveType.getByte();
+                break;
+            case JavaTokenTypes.LITERAL_boolean:
+                type = JavaPrimitiveType.getBoolean();
+                break;
+            case JavaTokenTypes.LITERAL_double:
+                type = JavaPrimitiveType.getDouble();
+                break;
+            case JavaTokenTypes.LITERAL_float:
+                type = JavaPrimitiveType.getFloat();
+                break;
+            case JavaTokenTypes.LITERAL_void:
+                type = JavaPrimitiveType.getVoid();
+            }
+            
+            while (i.hasNext()) {
+                token = i.next();
+                if (token.getType() == JavaTokenTypes.LBRACK) {
+                    type = type.getArray();
+                    i.next();  // RBRACK
+                }
+                else {
+                    return null;
+                }
+            }
+            
+            return new TypeEntity(type);
+        }
+        
+        String text = token.getText();
+        
+        JavaEntity poc = UnresolvedEntity.getEntity(resolver, text, querySource);
+        while (poc != null && i.hasNext()) {
+            token = i.next();
+            if (token.getType() == JavaTokenTypes.LT) {
+                // Type arguments
+                poc = processTypeArgs(resolver, querySource, poc, i, depthRef);
+                if (poc == null) {
+                    return null;
+                }
+                if (! i.hasNext()) {
+                    return poc;
+                }
+                token = i.next();
+            }
+            if (token.getType() != JavaTokenTypes.DOT) {
+                while (token.getType() == JavaTokenTypes.LBRACK) {
+                    poc = new UnresolvedArray(poc);
+                    if (i.hasNext()) {
+                        token = i.next(); // RBRACK
+                    }
+                    if (! i.hasNext()) {
+                        return poc;
+                    }
+                    token = i.next();
+                }
+                
+                i.previous(); // allow token to be re-read by caller
+                return poc;
+            }
+            token = i.next();            
+            if (token.getType() != JavaTokenTypes.IDENT) {
+                break;
+            }
+            poc = poc.getSubentity(token.getText(), querySource);
+        }
+        
+        return poc;
+    }
+
+    /**
+     * Process tokens as type arguments
+     * @param base  The base type, i.e. the type to which the arguments are applied
+     * @param i     A ListIterator to iterate through the tokens
+     * @param depthRef  The current argument depth; will be adjusted on return
+     * @return   A JavaEntity representing the type with type arguments applied (or null)
+     */
+    private static JavaEntity processTypeArgs(EntityResolver resolver, Reflective querySource, 
+            JavaEntity base, ListIterator<LocatableToken> i, DepthRef depthRef)
+    {
+        int startDepth = depthRef.depth;
+        List<TypeArgumentEntity> taList = new LinkedList<TypeArgumentEntity>();
+        depthRef.depth++;
+        
+        mainLoop:
+        while (i.hasNext() && depthRef.depth > startDepth) {
+            LocatableToken token = i.next();
+            if (token.getType() == JavaTokenTypes.QUESTION) {
+                if (! i.hasNext()) {
+                    return null;
+                }
+                token = i.next();
+                if (token.getType() == JavaTokenTypes.LITERAL_super) {
+                    JavaEntity taEnt = getTypeEntity(resolver, querySource, i, depthRef);
+                    if (taEnt == null) {
+                        return null;
+                    }
+                    taList.add(new WildcardSuperEntity(taEnt));
+                }
+                else if (token.getType() == JavaTokenTypes.LITERAL_extends) {
+                    JavaEntity taEnt = getTypeEntity(resolver, querySource, i, depthRef);
+                    if (taEnt == null) {
+                        return null;
+                    }
+                    taList.add(new WildcardExtendsEntity(taEnt));
+                }
+                else {
+                    taList.add(new UnboundedWildcardEntity(resolver));
+                    i.previous();
+                }
+            }
+            else {
+                i.previous();
+                JavaEntity taEnt = getTypeEntity(resolver, querySource, i, depthRef);
+                if (taEnt == null) {
+                    return null;
+                }
+                taList.add(new SolidTargEntity(taEnt));
+            }
+            
+            if (depthRef.depth <= startDepth) {
+                // We've hit the closing '>' already
+                break;
+            }
+            
+            if (! i.hasNext()) {
+                return null;
+            }
+            token = i.next();
+            int ttype = token.getType();
+            while (ttype == JavaTokenTypes.GT || ttype == JavaTokenTypes.SR || ttype == JavaTokenTypes.BSR) {
+                switch (ttype) {
+                case JavaTokenTypes.BSR:
+                    depthRef.depth--;
+                case JavaTokenTypes.SR:
+                    depthRef.depth--;
+                default:
+                    depthRef.depth--;
+                }
+                if (! i.hasNext()) {
+                    break mainLoop;
+                }
+                token = i.next();
+                ttype = token.getType();
+            }
+            
+            if (ttype != JavaTokenTypes.COMMA) {
+                i.previous();
+                break;
+            }
+        }
+        return base.setTypeArgs(taList);
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/SourceLocation.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/SourceLocation.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed5921bb4492f9606d06ee411511d4464a1a7196
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/SourceLocation.java
@@ -0,0 +1,66 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+/**
+ * A line/column location in a source file.
+ *
+ * Note that all line/column numbers start counting from 1.
+ *
+ * @author  Andrew Patterson
+ */
+public class SourceLocation
+{
+    private int line;
+    private int column;
+    
+    public SourceLocation(int line, int column)
+    {
+        if (line < 1 || column < 1)
+            throw new IllegalArgumentException("line/column numbers must be > 0");
+
+        this.line = line;
+        this.column = column;
+    }
+
+    /**
+     * Gets the line number of this location
+     */
+    public int getLine()
+    {
+        return line;
+    }
+
+    /**
+     * gets the column where this node reside
+     * @return <code>int</code>
+     */
+    public int getColumn()
+    {
+        return column;
+    }
+
+    public String toString()
+    {   
+        return "<" + line + "," + column + ">";
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/SourceSpan.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/SourceSpan.java
new file mode 100644
index 0000000000000000000000000000000000000000..bbac4d63b8e4bcd23f8ee445f8da3e5701a3e865
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/SourceSpan.java
@@ -0,0 +1,98 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+/**
+ * A span between two line/column locations.
+ *
+ * @author  Andrew Patterson
+ */
+public class SourceSpan
+{
+    private SourceLocation start;
+    private SourceLocation end;
+    
+    /**
+     * @param start  the line/column location where the span starts
+     * @param end	 the line/column location where the span ends
+     */
+    public SourceSpan(SourceLocation start, SourceLocation end)
+    {
+        this.start = start;
+        this.end = end;
+    }
+    
+    /**
+     * @param start    the line/column location where the span starts
+     * @param numChars the number of characters (assumes span is only on one line)
+     */
+    public SourceSpan(SourceLocation start, int numChars)
+    {
+        this.start = start;
+        this.end = new SourceLocation(start.getLine(), start.getColumn() + numChars);
+    }
+
+    /**
+     * Determine if a span crosses more that one line.
+     * 
+     * @return  true if the span is only on one line.
+     */
+    public boolean isOneLine()
+    {
+        return (start.getLine() == end.getLine() );
+    }
+    
+    public SourceLocation getStartLocation()
+    {
+        return start;
+    }
+
+    public int getStartColumn()
+    {
+        return start.getColumn();
+    }
+
+    public int getStartLine()
+    {
+        return start.getLine();
+    }
+
+    public SourceLocation getEndLocation()
+    {
+        return end;
+    }
+
+    public int getEndColumn()
+    {
+        return end.getColumn();
+    }
+
+    public int getEndLine()
+    {
+        return end.getLine();
+    }
+    
+    public String toString()
+    {
+        return start.toString() + "-" + end.toString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/TextAnalyzer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/TextAnalyzer.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d8f345e181259bb78560b2bff603a0dfae94c7a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/TextAnalyzer.java
@@ -0,0 +1,1613 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import bluej.debugger.gentype.BadInheritanceChainException;
+import bluej.debugger.gentype.GenTypeCapture;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.GenTypeSolid;
+import bluej.debugger.gentype.GenTypeTpar;
+import bluej.debugger.gentype.GenTypeWildcard;
+import bluej.debugger.gentype.IntersectionType;
+import bluej.debugger.gentype.JavaPrimitiveType;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.MethodReflective;
+import bluej.debugger.gentype.Reflective;
+import bluej.debugmgr.NamedValue;
+import bluej.debugmgr.ValueCollection;
+import bluej.debugmgr.texteval.DeclaredVar;
+import bluej.parser.entity.ConstantFloatValue;
+import bluej.parser.entity.ConstantIntValue;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.PackageEntity;
+import bluej.parser.entity.PackageOrClass;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.entity.ValueEntity;
+import bluej.utility.Debug;
+import bluej.utility.JavaNames;
+import bluej.utility.JavaReflective;
+import bluej.utility.JavaUtils;
+
+/**
+ * Parsing routines for the code pad.<p>
+ * 
+ * This is pretty tricky stuff, we try to following the Java Language Specification
+ * (JLS) where possible.
+ *  
+ * @author Davin McCall
+ */
+public class TextAnalyzer
+{
+    private EntityResolver parentResolver;
+    private String packageScope;  // evaluation package
+    private ValueCollection objectBench;
+
+    private List<DeclaredVar> declVars; // variables declared in the parsed statement block
+    private String amendedCommand;  // command string amended with initializations for
+                                    // all variables
+    
+    private ImportsCollection imports;
+    private String importCandidate; // any import candidates.
+    
+    /**
+     * TextParser constructor. Defines the class loader and package scope
+     * for evaluation.
+     */
+    public TextAnalyzer(EntityResolver parentResolver, String packageScope, ValueCollection ob)
+    {
+        this.parentResolver = parentResolver;
+        this.packageScope = packageScope;
+        this.objectBench = ob;
+        imports = new ImportsCollection();
+    }
+    
+    /**
+     * Set a new class loader, and clear the imports list.
+     */
+    public void newClassLoader(ClassLoader newLoader)
+    {
+        imports.clear();
+    }
+    
+    /**
+     * Parse a string entered into the code pad. Return is null if the string
+     * is a statement; otherwise the string is an expression and the returned
+     * string if the type of the expression (empty if the type cannot be determined).
+     * 
+     * <p>After calling this method, getDeclaredVars() and getAmendedCommand() can be
+     * called - see the documentation for those methods respectively.
+     * 
+     * <p>If the parsed string is then executed, the confirmCommand() method should
+     * subsequently be called.
+     */
+    public String parseCommand(String command)
+    {
+        importCandidate = "";
+        amendedCommand = command;
+        declVars = Collections.emptyList();
+        
+        EntityResolver resolver = getResolver(); 
+        
+        Reflective accessRef = new DummyReflective(JavaNames.combineNames(packageScope, "$SHELL"));
+        TypeEntity accessType = new TypeEntity(accessRef);
+        TextParser parser = new TextParser(resolver, command, accessType, true);
+        
+        try {
+
+            // check if it's an import statement
+            try {
+                parser.parseImportStatement();
+                if (parser.atEnd()) {
+                    amendedCommand = "";
+                    importCandidate = command;
+                    return null;
+                }
+            }
+            catch (ParseFailure e) {}
+
+            CodepadVarParser vparser = new CodepadVarParser(resolver, command);
+            try {
+                if (vparser.parseVariableDeclarations() != null) {
+                    declVars = vparser.getVariables();
+                    if (! declVars.isEmpty()) {
+                        for (DeclaredVar var : declVars) {
+                            if (! var.isInitialized() && ! var.isFinal()) {
+                                amendedCommand += "\n" + var.getName();
+                                String text;
+                                JavaType declVarType = var.getDeclaredType();
+                                if (declVarType.isPrimitive()) {
+                                    if (declVarType.isNumeric()) {
+                                        text = " = 0";
+                                    }
+                                    else {
+                                        text = " = false";
+                                    }
+                                }
+                                else {
+                                    // reference type
+                                    text = " = null";
+                                }
+                                amendedCommand += text + ";\n";
+                            }
+                        }
+                        return null; // not an expression
+                    }
+                }
+            }
+            catch (ParseFailure e) {}
+
+            // Check if it's an expression
+            parser = new TextParser(resolver, command, accessType, true);
+            try {
+                // Note the TextParser will throw an exception if a parse error occurs.
+                // We must catch it.
+                parser.parseExpression();
+                if (parser.atEnd()) {
+                    JavaEntity exprType = parser.getExpressionType();
+                    if (exprType == null) {
+                        return "";
+                    }
+                    else {
+                        JavaEntity rval =  exprType.resolveAsValue();
+                        if (rval != null) {
+                            if (rval.getType().typeIs(JavaPrimitiveType.JT_VOID)) {
+                                return null;
+                            }
+                            return rval.getType().toString();
+                        }
+                        return "";
+                    }
+                }
+            }
+            catch (ParseFailure e) {}
+        }
+        catch (Throwable t) {
+            // It's best at this stage if an exception (other than a parse failure) occurs that
+            // we still do a normal return from this method (so the codepad continues to function).
+            // However we'll log the problem.
+            Debug.reportError("Exception in parser", t);
+        }
+
+        return null;
+    }
+    
+    private EntityResolver getResolver()
+    {
+        EntityResolver resolver = new EntityResolver()
+        {
+            public TypeEntity resolveQualifiedClass(String name)
+            {
+                return parentResolver.resolveQualifiedClass(name);
+            }
+            
+            public PackageOrClass resolvePackageOrClass(String name, Reflective querySource)
+            {
+                String pkgScopePrefix = packageScope;
+                if (packageScope.length() > 0) {
+                    pkgScopePrefix += ".";
+                }
+
+                // Imported class?
+                TypeEntity entity = imports.getTypeImport(name);
+                if (entity != null)
+                {
+                    return entity;
+                }
+                
+                // Might be a class in the current package
+                TypeEntity rval = parentResolver.resolveQualifiedClass(pkgScopePrefix + name);
+                if (rval != null) {
+                    return rval;
+                }
+                
+                // Try in java.lang (see JLS 7.5.5)
+                rval = parentResolver.resolveQualifiedClass("java.lang." + name);
+                if (rval != null) {
+                    return rval;
+                }
+                
+                // Try in wildcard imports
+                entity = imports.getTypeImportWC(name);
+                if (entity != null) {
+                    return entity;
+                }
+                
+                // Have to assume it's a package
+                return new PackageEntity(name, this);
+            }
+            
+            public JavaEntity getValueEntity(String name, Reflective querySource)
+            {
+                NamedValue obVal = objectBench.getNamedValue(name);
+                if (obVal != null) {
+                    return new ValueEntity(obVal.getGenType());
+                }
+                List<JavaEntity> importStaticVals = imports.getStaticImports(name);
+                if (importStaticVals != null && !importStaticVals.isEmpty()) {
+                    return importStaticVals.get(0).getSubentity(name, querySource);
+                }
+                importStaticVals = imports.getStaticWildcardImports();
+                if (importStaticVals != null) {
+                    for (JavaEntity importStatic : importStaticVals) {
+                        importStatic = importStatic.resolveAsType();
+                        if (importStatic == null) {
+                            continue;
+                        }
+                        JavaEntity entity = importStatic.getSubentity(name, querySource);
+                        if (entity != null) {
+                            return entity;
+                        }
+                    }
+                }
+                
+                return resolvePackageOrClass(name, querySource);
+            }
+        };
+        return resolver;
+    }
+    
+    /**
+     * Called to confirm that the recently parsed command has successfully
+     * executed. This allows TextParser to update internal state to reflect
+     * changes caused by the execution of the command.
+     */
+    public void confirmCommand()
+    {
+        if (importCandidate.length() != 0) {
+            Reader r = new StringReader(importCandidate);
+            CodepadImportParser parser = new CodepadImportParser(getResolver(), r);
+            parser.parseImportStatement();
+            if (parser.isStaticImport()) {
+                if (parser.isWildcardImport()) {
+                    imports.addStaticWildcardImport(parser.getImportEntity()
+                            .resolveAsType());
+                }
+                else {
+                    imports.addStaticImport(parser.getMemberName(),
+                            parser.getImportEntity().resolveAsType());
+                }
+            }
+            else {
+                if (parser.isWildcardImport()) {
+                    imports.addWildcardImport(parser.getImportEntity().resolveAsPackageOrClass());
+                }
+                else {
+                    JavaEntity importEntity = parser.getImportEntity();
+                    TypeEntity classEnt = importEntity.resolveAsType();
+                    String name = classEnt.getType().toString(true);
+                    imports.addNormalImport(name, classEnt);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Get a list of the variables declared in the recently parsed statement
+     * block. The return is a List of TextParser.DeclaredVar
+     */
+    public List<DeclaredVar> getDeclaredVars()
+    {
+        return declVars;
+    }
+    
+    /**
+     * Get the amended command string, which has initializers inserted for variable
+     * declarations which were missing initializers.
+     */
+    public String getAmendedCommand()
+    {
+        return amendedCommand;
+    }
+    
+    /**
+     * Return the imports collection as a sequence of java import statements.
+     */
+    public String getImportStatements()
+    {
+        return imports.toString() + importCandidate;
+    }
+    
+    /**
+     * Java 1.4 & prior version of trinary "? :" operator. See JLS 2nd ed. 
+     * section 15.25.
+     * 
+     * @throws RecognitionException
+     * @throws SemanticException
+     */
+//    private JavaType questionOperator14(AST node) throws RecognitionException, SemanticException
+//    {
+//        AST trueAlt = node.getFirstChild().getNextSibling();
+//        AST falseAlt = trueAlt.getNextSibling();
+//        ExprValue trueAltEv = getExpressionType(trueAlt);
+//        ExprValue falseAltEv = getExpressionType(falseAlt);
+//        JavaType trueAltType = trueAltEv.getType();
+//        JavaType falseAltType = falseAltEv.getType();
+//        
+//        // if the operands have the same type, that is the result type
+//        if (trueAltType.equals(falseAltType))
+//            return trueAltType;
+//        
+//        if (trueAltType.isNumeric() && falseAltType.isNumeric()) {
+//            // if one type is short and the other is byte, result type is short
+//            if (trueAltType.typeIs(JavaType.JT_SHORT) && falseAltType.typeIs(JavaType.JT_BYTE))
+//                return JavaPrimitiveType.getShort();
+//            if (falseAltType.typeIs(JavaType.JT_SHORT) && trueAltType.typeIs(JavaType.JT_BYTE))
+//                return JavaPrimitiveType.getShort();
+//            
+//            // if one type is byte/short/char and the other is a constant of
+//            // type int whose value fits, the result type is byte/short/char
+//            if (falseAltType.typeIs(JavaType.JT_INT) && falseAltEv.knownValue()) {
+//                int fval = falseAltEv.intValue();
+//                if (isMinorInteger(trueAltType) && trueAltType.couldHold(fval))
+//                    return trueAltType;
+//            }
+//            if (trueAltType.typeIs(JavaType.JT_INT) && trueAltEv.knownValue()) {
+//                int fval = trueAltEv.intValue();
+//                if (isMinorInteger(falseAltType) && falseAltType.couldHold(fval))
+//                    return falseAltType;
+//            }
+//            
+//            // binary numeric promotion is applied
+//            return binaryNumericPromotion(trueAltType, falseAltType);
+//        }
+//        
+//        // otherwise it must be possible to convert one type to the other by
+//        // assignment conversion:
+//        if (trueAltType.isAssignableFrom(falseAltType))
+//            return trueAltType;
+//        if (falseAltType.isAssignableFrom(trueAltType))
+//            return falseAltType;
+//        
+//        throw new SemanticException();
+//    }
+    
+    /**
+     * Test if a given type is one of the "minor" integral types: byte, char
+     * or short.
+     */
+//    private static boolean isMinorInteger(JavaType a)
+//    {
+//        return a.typeIs(JavaType.JT_BYTE) || a.typeIs(JavaType.JT_CHAR) || a.typeIs(JavaType.JT_SHORT); 
+//    }
+    
+    /**
+     * Test whether the given value fits in the range representable by byte, short or char
+     */
+    private static boolean doesValueFitIntType(long value, JavaType type)
+    {
+        if (type.typeIs(JavaType.JT_BYTE)) {
+            return value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE;
+        }
+        else if (type.typeIs(JavaType.JT_CHAR)) {
+            return value <= Character.MAX_VALUE && value >= Character.MIN_VALUE;
+        }
+        else if (type.typeIs(JavaType.JT_SHORT)) {
+            return value <= Short.MAX_VALUE && value >= Short.MIN_VALUE;
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Java 1.5 version of the trinary "? :" operator.
+     * See JLS section 15.25. Note that JLS 3rd ed. differs extensively
+     * from JLS 2nd edition. The changes are not backwards compatible.
+     */
+    public static ValueEntity questionOperator15(ValueEntity condition, ValueEntity trueAlt, ValueEntity falseAlt)
+    {
+        JavaType trueAltType = trueAlt.getType();
+        JavaType falseAltType = falseAlt.getType();
+        JavaType conditionType = condition.getType();
+        
+        // The condition must be boolean:
+        if (conditionType == null || ! conditionType.typeIs(JavaPrimitiveType.JT_BOOLEAN)) {
+            return null;
+        }
+        
+        // if we don't know the type of both alternatives, we don't
+        // know the result type:
+        if (trueAltType == null || falseAltType == null) {
+            return null;
+        }
+        
+        // Neither argument can be a void type.
+        if (trueAltType.isVoid() || falseAltType.isVoid()) {
+            return null;
+        }
+        
+        // if the second & third arguments have the same type, then
+        // that is the result type:
+        if (trueAltType.equals(falseAltType)) {
+            if (condition.hasConstantBooleanValue() && ValueEntity.isConstant(trueAlt) && ValueEntity.isConstant(falseAlt)) {
+                return condition.getConstantBooleanValue() ? trueAlt : falseAlt;
+            }
+            return new ValueEntity(trueAltType);
+        }
+
+        // If one of the operands is the null type and the other is a reference type,
+        // the type of the conditional expression is that of the reference type:
+        if (trueAltType.isNull() && !falseAltType.isPrimitive()) {
+            // The result cannot be a compile-time constant as expression contains a null
+            return new ValueEntity(falseAltType);
+        }
+        
+        // Otherwise:
+        String trueAltStr = trueAltType.toString();
+        String falseAltStr = falseAltType.toString();
+        
+        boolean trueIsByte = trueAltStr.equals("byte") || trueAltStr.equals("java.lang.Byte");
+        boolean falseIsShort = falseAltStr.equals("short") || falseAltStr.equals("java.lang.Short");
+        boolean falseIsByte = falseAltStr.equals("byte") || falseAltStr.equals("java.lang.Byte");
+        boolean trueIsShort = trueAltStr.equals("short") || trueAltStr.equals("java.lang.Short");
+        
+        if (trueIsByte && falseIsShort || falseIsByte && trueIsShort) {
+            if (condition.hasConstantBooleanValue() && trueAlt.hasConstantIntValue() && falseAlt.hasConstantIntValue()) {
+                long intVal = condition.getConstantBooleanValue() ? trueAlt.getConstantIntValue()
+                        : falseAlt.getConstantIntValue();
+                return new ConstantIntValue(null, JavaPrimitiveType.getShort(), intVal);
+            }
+            return new ValueEntity(JavaPrimitiveType.getShort());
+        }
+
+        // If one of the types is byte/short/char (possibly boxed) and the other is of type int, and is a constant
+        // whose value fits in the first type, then the result is of the first type (unboxed).
+        
+        JavaType trueUnboxed = unBox(trueAltType);
+        boolean trueIsSmallInt = trueUnboxed.typeIs(JavaType.JT_BYTE) || trueUnboxed.typeIs(JavaType.JT_SHORT)
+                || trueUnboxed.typeIs(JavaType.JT_CHAR);
+        
+        if (trueIsSmallInt && falseAltType.typeIs(JavaType.JT_INT) && falseAlt.hasConstantIntValue()) {
+            long fval = falseAlt.getConstantIntValue();
+            if (doesValueFitIntType(fval, trueAltType)) {
+                if (trueAlt.hasConstantIntValue() && condition.hasConstantBooleanValue()) {
+                    long val = condition.getConstantBooleanValue() ? trueAlt.getConstantIntValue()
+                            : falseAlt.getConstantIntValue();
+                    return new ConstantIntValue(null, trueAltType, val);
+                }
+                return new ValueEntity(trueUnboxed);
+            }
+        }
+        
+        JavaType falseUnboxed = unBox(falseAltType);
+        boolean falseIsSmallInt = falseUnboxed.typeIs(JavaType.JT_BYTE) || falseUnboxed.typeIs(JavaType.JT_SHORT)
+                || falseUnboxed.typeIs(JavaType.JT_CHAR);
+
+        if (falseIsSmallInt && trueAltType.typeIs(JavaType.JT_INT) && trueAlt.hasConstantIntValue()) {
+            long fval = trueAlt.getConstantIntValue();
+            if (doesValueFitIntType(fval, falseAltType)) {
+                if (falseAlt.hasConstantIntValue() && condition.hasConstantBooleanValue()) {
+                    long val = condition.getConstantBooleanValue() ? trueAlt.getConstantIntValue()
+                            : falseAlt.getConstantIntValue();
+                    return new ConstantIntValue(null, falseUnboxed, val);
+                }
+                return new ValueEntity(falseUnboxed);
+            }
+        }
+        
+        // Binary numeric promotion?
+        
+        if (trueUnboxed.isNumeric() && falseUnboxed.isNumeric()) {
+            JavaType rtype = binaryNumericPromotion(trueUnboxed, falseUnboxed);
+            if (condition.hasConstantBooleanValue() && ValueEntity.isConstant(trueAlt) && ValueEntity.isConstant(falseAlt)) {
+                ValueEntity relevantAlt = condition.getConstantBooleanValue() ? trueAlt : falseAlt;
+                if (rtype.typeIs(JavaType.JT_DOUBLE) || rtype.typeIs(JavaType.JT_FLOAT)) {
+                    double val;
+                    if (relevantAlt.getType().typeIs(JavaType.JT_DOUBLE) || relevantAlt.getType().typeIs(JavaType.JT_FLOAT)) {
+                        val = relevantAlt.getConstantFloatValue();
+                    }
+                    else {
+                        // the relevant alternative is an integer promoted to a float
+                        val = relevantAlt.getConstantIntValue();
+                    }
+                    return new ConstantFloatValue(rtype, val);
+                }
+                long val = condition.getConstantBooleanValue() ? trueAlt.getConstantIntValue()
+                        : falseAlt.getConstantIntValue();
+                return new ConstantIntValue(null, rtype, val);
+            }
+            return new ValueEntity(rtype);
+        }
+        
+        // No - reference types.
+        
+        GenTypeSolid trueBoxed = boxType(trueAltType);
+        GenTypeSolid falseBoxed = boxType(falseAltType);
+        GenTypeSolid rtype = GenTypeSolid.lub(new GenTypeSolid[] {trueBoxed, falseBoxed});
+        return new ValueEntity(rtype.getCapture());
+    }
+    
+    /**
+     * Capture conversion, as in the JLS 5.1.10
+     */
+    private static JavaType captureConversion(JavaType o)
+    {
+        GenTypeClass c = o.asClass();
+        if (c != null)
+            return captureConversion(c, new HashMap<String,GenTypeSolid>());
+        else
+            return o;
+    }
+    
+    /**
+     * Capture conversion, storing converted type parameters in the supplied Map so
+     * that they are accessible to inner classes.
+     *  
+     * @param c   The type to perform the conversion on
+     * @param tparMap   The map used for storing type parameter conversions
+     * @return   The converted type.
+     */
+    private static GenTypeClass captureConversion(GenTypeClass c, Map<String,GenTypeSolid> tparMap)
+    {
+        // capture the outer type
+        GenTypeClass newOuter = null;
+        GenTypeClass oldOuter = c.getOuterType();
+        if (oldOuter != null)
+            newOuter = captureConversion(oldOuter, tparMap);
+        
+        // capture the arguments
+        List<? extends GenTypeParameter> oldArgs = c.getTypeParamList();
+        List<GenTypeSolid> newArgs = new ArrayList<GenTypeSolid>(oldArgs.size());
+        Iterator<? extends GenTypeParameter> i = oldArgs.iterator();
+        Iterator<GenTypeDeclTpar> boundsIterator = c.getReflective().getTypeParams().iterator();
+        while (i.hasNext()) {
+            GenTypeParameter targ = (GenTypeParameter) i.next();
+            GenTypeDeclTpar tpar = (GenTypeDeclTpar) boundsIterator.next();
+            GenTypeSolid newArg;
+            if (targ instanceof GenTypeWildcard) {
+                GenTypeWildcard wc = (GenTypeWildcard) targ;
+                GenTypeSolid [] ubounds = wc.getUpperBounds();
+                GenTypeSolid lbound = wc.getLowerBound();
+                GenTypeSolid [] tpbounds = tpar.upperBounds();
+                for (int j = 0; j < tpbounds.length; j++) {
+                    tpbounds[j] = (GenTypeSolid) tpbounds[j].mapTparsToTypes(tparMap);
+                }
+                if (lbound != null) {
+                    // ? super XX
+                    newArg = new GenTypeCapture(new GenTypeWildcard(tpbounds, new GenTypeSolid[] {lbound}));
+                }
+                else {
+                    // ? extends ...
+                    GenTypeSolid [] newBounds = new GenTypeSolid[ubounds.length + tpbounds.length];
+                    System.arraycopy(ubounds, 0, newBounds, 0, ubounds.length);
+                    System.arraycopy(tpbounds, 0, newBounds, ubounds.length, tpbounds.length);
+                    newArg = new GenTypeCapture(new GenTypeWildcard(ubounds, new GenTypeSolid[0]));
+                }
+            }
+            else {
+                // The argument is not a wildcard. Capture doesn't affect it.
+                newArg = (GenTypeSolid) targ;
+            }
+            newArgs.add(newArg);
+            tparMap.put(tpar.getTparName(), newArg);
+        }
+        return new GenTypeClass(c.getReflective(), newArgs, newOuter);
+    }
+    
+    /**
+     * binary numeric promotion, as defined by JLS section 5.6.2. Both
+     * operands must be (possibly boxed) numeric types.
+     */
+    public static JavaType binaryNumericPromotion(JavaType a, JavaType b)
+    {
+        JavaType ua = unBox(a);
+        JavaType ub = unBox(b);
+
+        if (ua.typeIs(JavaType.JT_DOUBLE) || ub.typeIs(JavaType.JT_DOUBLE))
+            return JavaPrimitiveType.getDouble();
+
+        if (ua.typeIs(JavaType.JT_FLOAT) || ub.typeIs(JavaType.JT_FLOAT))
+            return JavaPrimitiveType.getFloat();
+
+        if (ua.typeIs(JavaType.JT_LONG) || ub.typeIs(JavaType.JT_LONG))
+            return JavaPrimitiveType.getLong();
+
+        if (ua.isNumeric() && ub.isNumeric()) {
+            return JavaPrimitiveType.getInt();
+        }
+        else {
+            return null;
+        }
+    }
+    
+    /**
+     * Unary numeric promotion, as defined by JLS 3rd ed. section 5.6.1
+     * Return is null if argument type is not convertible to a numeric type.
+     */
+    public static JavaType unaryNumericPromotion(JavaType a)
+    {
+        JavaType ua = unBox(a);
+        
+        // long float and double are merely unboxed; everything else is unboxed and widened to int:
+        if (ua.typeIs(JavaType.JT_DOUBLE))
+            return JavaPrimitiveType.getDouble();
+
+        if (ua.typeIs(JavaType.JT_FLOAT))
+            return JavaPrimitiveType.getFloat();
+
+        if (ua.typeIs(JavaType.JT_LONG))
+            return JavaPrimitiveType.getLong();
+        
+        if (ua.isNumeric()) {
+            return JavaPrimitiveType.getInt();
+        }
+        else {
+            return null;
+        }
+    }
+    
+    /**
+     * Get the GenType of a character literal node.
+     * 
+     * @throws RecognitionException
+     */
+//    private ExprValue getCharLiteral(AST node) throws RecognitionException
+//    {
+//        // char literal is either 'x', or '\\uXXXX' notation, or '\t' etc.
+//        String x = node.getText();
+//        x = x.substring(1, x.length() - 1); // strip single quotes
+//        
+//        final JavaType charType = JavaPrimitiveType.getChar();
+//        if (! x.startsWith("\\")) {
+//            // This is the normal case
+//            if (x.length() != 1)
+//                throw new RecognitionException();
+//            else
+//                return new NumValue(charType, new Integer(x.charAt(0)));
+//        }
+//        else if (x.equals("\\b"))
+//            return new NumValue(charType, new Integer('\b'));
+//        else if (x.equals("\\t"))
+//            return new NumValue(charType, new Integer('\t'));
+//        else if (x.equals("\\n"))
+//            return new NumValue(charType, new Integer('\n'));
+//        else if (x.equals("\\f"))
+//            return new NumValue(charType, new Integer('\f'));
+//        else if (x.equals("\\r"))
+//            return new NumValue(charType, new Integer('\r'));
+//        else if (x.equals("\\\""))
+//            return new NumValue(charType, new Integer('"'));
+//        else if (x.equals("\\'"))
+//            return new NumValue(charType, new Integer('\''));
+//        else if (x.equals("\\\\"))
+//            return new NumValue(charType, new Integer('\\'));
+//        else if (x.startsWith("\\u")) {
+//            // unicode escape, as a 4-digit hexadecimal
+//            if (x.length() != 6)
+//                throw new RecognitionException();
+//            
+//            char val = 0;
+//            for (int i = 0; i < 4; i++) {
+//                char digit = x.charAt(i + 2);
+//                int digVal = Character.digit(digit, 16);
+//                if (digVal == -1)
+//                    throw new RecognitionException();
+//                val = (char)(val * 16 + digVal);
+//            }
+//            return new NumValue(charType, new Integer(val));
+//        }
+//        else {
+//            // octal escape, up to three digits
+//            int xlen = x.length();
+//            if (xlen < 2 || xlen > 4)
+//                throw new RecognitionException();
+//            
+//            char val = 0;
+//            for (int i = 0; i < xlen - 1; i++) {
+//                char digit = x.charAt(i+1);
+//                int digVal = Character.digit(digit, 8);
+//                if (digVal == -1) {
+//                        throw new RecognitionException();
+//                }
+//                val = (char)(val * 8 + digVal);
+//            }
+//            return new NumValue(charType, new Integer(val));
+//        }
+//    }
+    
+    /**
+     * Get the GenType corresponding to an integer literal node.
+     * @throws RecognitionException
+     */
+//    private ExprValue getIntLiteral(AST node, boolean negative) throws RecognitionException
+//    {
+//        String x = node.getText();
+//        if (negative)
+//            x = "-" + x;
+//        
+//        try {
+//            Integer val = Integer.decode(x);
+//            return new NumValue(JavaPrimitiveType.getInt(), val);
+//        }
+//        catch (NumberFormatException nfe) {
+//            throw new RecognitionException();
+//        }
+//    }
+    
+    /**
+     * Ge the GenType corresponding to a long literal node.
+     * @throws RecognitionException
+     */
+//    private ExprValue getLongLiteral(AST node, boolean negative) throws RecognitionException
+//    {
+//        String x = node.getText();
+//        if (negative)
+//            x = "-" + x;
+//        
+//        try {
+//            Long val = Long.decode(x);
+//            return new NumValue(JavaPrimitiveType.getLong(), val);
+//        }
+//        catch (NumberFormatException nfe) {
+//            throw new RecognitionException();
+//        }
+//    }
+    
+    /**
+     * Get the GenType corresponding to a float literal.
+     * @throws RecognitionException
+     */
+//    private ExprValue getFloatLiteral(AST node, boolean negative) throws RecognitionException
+//    {
+//        String x = node.getText();
+//        if (negative)
+//            x = "-" + x;
+//        
+//        try {
+//            Float val = Float.valueOf(x);
+//            return new NumValue(JavaPrimitiveType.getFloat(), val);
+//        }
+//        catch (NumberFormatException nfe) {
+//            throw new RecognitionException();
+//        }
+//    }
+    
+    /**
+     * Get the GenType corresponding to a double literal.
+     * @throws RecognitionException
+     */
+//    private ExprValue getDoubleLiteral(AST node, boolean negative) throws RecognitionException
+//    {
+//        String x = node.getText();
+//        if (negative)
+//            x = "-" + x;
+//        
+//        try {
+//            Double val = Double.valueOf(x);
+//            return new NumValue(JavaPrimitiveType.getDouble(), val);
+//        }
+//        catch (NumberFormatException nfe) {
+//            throw new RecognitionException();
+//        }
+//    }
+    
+    /**
+     * Check whether a particular method is callable with particular
+     * parameters. If so return information about how specific the call is.
+     * If the parameters cannot be applied to this method, return null.
+     * 
+     * @param targetType   The type of object/class to which the method is
+     *                     being applied
+     * @param targs     The explicitly specified type arguments used in the
+     *                  invocation of a generic method (list of GenTypeClass)
+     * @param m       The method to check
+     * @param args    The types of the arguments supplied to the method
+     * @return   A record with information about the method call
+     * @throws RecognitionException
+     */
+    private static MethodCallDesc isMethodApplicable(GenTypeClass targetType, List<GenTypeParameter> targs, MethodReflective m, JavaType [] args)
+    {
+        boolean methodIsVarargs = m.isVarArgs();
+        MethodCallDesc rdesc = null;
+        
+        // First try without varargs expansion. If that fails, try with expansion.
+        rdesc = isMethodApplicable(targetType, targs, m, args, false);
+        if (rdesc == null && methodIsVarargs) {
+            rdesc = isMethodApplicable(targetType, targs, m, args, true);
+        }
+        return rdesc;
+    }
+
+    /**
+     * Check whether a particular method is callable with particular
+     * parameters. If so return information about how specific the call is.
+     * If the parameters cannot be applied to this method, return null.<p>
+     * 
+     * Normally this is called by the other variant of this method, which
+     * does not take the varargs parameter.
+     * 
+     * @param targetType   The type of object/class to which the method is
+     *                     being applied
+     * @param targs     The explicitly specified type parameters used in the
+     *                  invocation of a generic method (list of GenTypeClass)
+     * @param m       The method to check
+     * @param args    The types of the arguments supplied to the method
+     * @param varargs Whether to expand vararg parameters
+     * @return   A record with information about the method call
+     * @throws RecognitionException
+     */
+    private static MethodCallDesc isMethodApplicable(GenTypeClass targetType,
+            List<GenTypeParameter> targs, MethodReflective m, JavaType [] args, boolean varargs)
+    {
+        boolean rawTarget = targetType.isRaw();
+        boolean boxingRequired = false;
+        
+        // Check that the number of parameters supplied is allowable. Expand varargs
+        // arguments if necessary.
+        List<JavaType> mparams = m.getParamTypes();
+        if (varargs) {
+            // first basic check. The number of supplied arguments must be at least one less than
+            // the number of formal parameters.
+            if (mparams.size() > args.length + 1)
+                return null;
+
+            GenTypeSolid lastArgType = mparams.get(mparams.size() - 1).asSolid();
+            JavaType vaType = lastArgType.getArrayComponent();
+            List<JavaType> expandedParams = new ArrayList<JavaType>(args.length);
+            expandedParams.addAll(mparams);
+            expandedParams.remove(expandedParams.size() - 1); // remove the vararg array
+            for (int i = mparams.size() - 1; i < args.length; i++) {
+                expandedParams.add(vaType);
+            }
+            mparams = expandedParams;
+        }
+        else {
+            // Not varargs: supplied arguments must match formal parameters
+            if (mparams.size() != args.length)
+                return null;
+        }
+        
+        // Get type parameters of the method
+        List<GenTypeDeclTpar> tparams = Collections.emptyList();
+        if ((! rawTarget) || m.isStatic()) {
+            tparams = m.getTparTypes();
+            tparams = (tparams != null) ? tparams : Collections.<GenTypeDeclTpar>emptyList(); 
+        }
+        
+        // Number of type parameters supplied must match number declared, unless either
+        // is zero. Section 15.12.2 of the JLS, "a non generic method may be applicable
+        // to an invocation which supplies type arguments" (in which case the type args
+        // are ignored).
+        if (! targs.isEmpty() && ! tparams.isEmpty() && targs.size() != tparams.size())
+            return null;
+        
+        // Set up a map we can use to put actual/inferred type arguments. Initialise it
+        // with the target type's arguments.
+        Map<String,GenTypeParameter> tparMap;
+        if (rawTarget) {
+            tparMap = new HashMap<String,GenTypeParameter>();
+        }
+        else {
+            tparMap = targetType.getMap();
+        }
+
+        // Perform type inference, if necessary
+        if (! tparams.isEmpty() && targs.isEmpty()) {
+            // Our initial map has the class type parameters, minus those which are
+            // shadowed by the method's type parameters (map to themselves).
+            for (Iterator<GenTypeDeclTpar> i = tparams.iterator(); i.hasNext(); ) {
+                GenTypeDeclTpar tpar = (GenTypeDeclTpar) i.next();
+                tparMap.put(tpar.getTparName(), tpar);
+            }
+            
+            Map<String,Set<GenTypeSolid>> tlbConstraints = new HashMap<String,Set<GenTypeSolid>>();
+            Map<String,GenTypeSolid> teqConstraints = new HashMap<String,GenTypeSolid>();
+            
+            // Time for some type inference
+            for (int i = 0; i < mparams.size(); i++) {
+                if (mparams.get(i).isPrimitive()) {
+                    continue;
+                }
+                
+                GenTypeSolid mparam = (GenTypeSolid) mparams.get(i);
+                mparam = mparam.mapTparsToTypes(tparMap).getCapture().asSolid();
+                processAtoFConstraint(args[i], mparam, tlbConstraints, teqConstraints);
+            }
+            
+            // what we have now is a map with tpar constraints.
+            // Some tpars may not have been constrained: these are inferred to be the
+            // intersection of their upper bounds.
+            targs = new ArrayList<GenTypeParameter>();
+            Iterator<GenTypeDeclTpar> i = tparams.iterator();
+            while (i.hasNext()) {
+                GenTypeDeclTpar fTpar = (GenTypeDeclTpar) i.next();
+                String tparName = fTpar.getTparName();
+                GenTypeSolid eqConstraint = (GenTypeSolid) teqConstraints.get(tparName);
+                // If there's no equality constraint, use the lower bound constraints
+                if (eqConstraint == null) {
+                    Set<GenTypeSolid> lbConstraintSet = tlbConstraints.get(tparName);
+                    if (lbConstraintSet != null) {
+                        GenTypeSolid [] lbounds = (GenTypeSolid []) lbConstraintSet.toArray(new GenTypeSolid[lbConstraintSet.size()]);
+                        eqConstraint = GenTypeSolid.lub(lbounds); 
+                    }
+                    else {
+                        // no equality or lower bound constraints: use the upper
+                        // bounds of the tpar
+                        eqConstraint = fTpar.getBound();
+                    }
+                }
+                eqConstraint = (GenTypeSolid) eqConstraint.mapTparsToTypes(tparMap);
+                targs.add((GenTypeClass) eqConstraint);
+                tparMap.put(tparName, eqConstraint);
+            }
+        }
+        else {
+            // Get a map of type parameter names to types from the target type
+            // complete the type parameter map with tpars of the method
+            Iterator<GenTypeDeclTpar> formalI = tparams.iterator();
+            Iterator<GenTypeParameter> actualI = targs.iterator();
+            while (formalI.hasNext()) {
+                GenTypeDeclTpar formalTpar = (GenTypeDeclTpar) formalI.next();
+                GenTypeSolid argTpar = (GenTypeSolid) actualI.next();
+                
+                // first we check that the argument type is a subtype of the
+                // declared type.
+                GenTypeSolid [] formalUbounds = formalTpar.upperBounds();
+                for (int i = 0; i < formalUbounds.length; i++) {
+                    formalUbounds[i] = (GenTypeSolid) formalUbounds[i].mapTparsToTypes(tparMap);
+                    if (formalUbounds[i].isAssignableFrom(argTpar))
+                        break;
+                    if (i == formalUbounds.length - 1)
+                        return null;
+                }
+                
+                tparMap.put(formalTpar.getTparName(), argTpar);
+            }
+        }
+        
+        // For each argument, must check the compatibility of the supplied
+        // parameter type with the argument type; and if neither the formal
+        // parameter or supplied argument are raw, then must check generic
+        // contract as well.
+        
+        for (int i = 0; i < args.length; i++) {
+            JavaType formalArg = mparams.get(i);
+            JavaType givenParam = args[i];
+            
+            // Substitute type arguments.
+            formalArg = formalArg.mapTparsToTypes(tparMap).getUpperBound();
+            
+            // check if the given parameter doesn't match the formal argument
+            if (! formalArg.isAssignableFrom(givenParam)) {
+                // a boxing conversion followed by a widening reference conversion
+                if (! formalArg.isAssignableFrom(boxType(givenParam))) {
+                    // an unboxing conversion followed by a widening primitive conversion
+                    if (! formalArg.isAssignableFrom(unBox(givenParam))) {
+                        return null;
+                    }
+                }
+                boxingRequired = true;
+            }
+        }
+        
+        JavaType rType = m.getReturnType().mapTparsToTypes(tparMap).getUpperBound();
+        return new MethodCallDesc(m, mparams, varargs, boxingRequired, rType);
+    }
+
+    
+    
+    /**
+     * Process a type inference constraint of the form "A is convertible to F".
+     * Note F must be a valid formal parameter: it can't be a wildcard with multiple
+     * bounds or an intersection type.
+     * 
+     * @param a  The argument type
+     * @param f  The formal parameter type
+     * @param tlbConstraints   lower bound constraints (a Map to Set of GenTypeSolid)
+     * @param teqConstraints   equality constraints (a Map to GenTypeSolid)
+     */
+    private static void processAtoFConstraint(JavaType a, GenTypeSolid f,
+            Map<String,Set<GenTypeSolid>> tlbConstraints,
+            Map<String,GenTypeSolid> teqConstraints)
+    {
+        a = boxType(a);
+        if (a.asSolid() == null) {
+            return; // no constraint
+        }
+        
+        if (f instanceof GenTypeTpar) {
+            // The constraint T :> A is implied
+            GenTypeTpar t = (GenTypeTpar) f;
+            Set<GenTypeSolid> constraintsSet = tlbConstraints.get(t.getTparName());
+            if (constraintsSet == null) {
+                constraintsSet = new HashSet<GenTypeSolid>();
+                tlbConstraints.put(t.getTparName(), constraintsSet);
+            }
+            
+            constraintsSet.add(a.asSolid());
+        }
+        
+        // If F is an array of the form U[], and a is an array of the form V[]...
+        else if (f.getArrayComponent() != null) {
+            if (a.getArrayComponent() != null) {
+                if (f.getArrayComponent() instanceof GenTypeSolid) {
+                    a = a.getArrayComponent();
+                    f = (GenTypeSolid) f.getArrayComponent();
+                    processAtoFConstraint(a, f, tlbConstraints, teqConstraints);
+                }
+            }
+        }
+        
+        // If F is of the form G<...> and A is convertible to the same form...
+        else {
+            GenTypeClass cf = f.asClass();
+            Map<String,GenTypeParameter> fMap = cf.getMap();
+            if (fMap != null && a.asSolid() != null) {
+                GenTypeClass [] asts = a.asSolid().getReferenceSupertypes();
+                for (int i = 0; i < asts.length; i++) {
+                    try {
+                        GenTypeClass aMapped = asts[i].mapToSuper(cf.classloaderName());
+                        // Superclass relationship is by capture conversion
+                        if (! asts[i].classloaderName().equals(cf.classloaderName()))
+                            aMapped = (GenTypeClass) captureConversion(aMapped);
+                        Map<String,GenTypeParameter> aMap = aMapped.getMap();
+                        if (aMap != null) {
+                            Iterator<String> j = fMap.keySet().iterator();
+                            while (j.hasNext()) {
+                                String tpName = j.next();
+                                GenTypeParameter fPar = fMap.get(tpName);
+                                GenTypeParameter aPar = aMap.get(tpName);
+                                processAtoFtpar(aPar, fPar, tlbConstraints, teqConstraints);
+                            }
+                        }
+                    }
+                    catch (BadInheritanceChainException bice) {}
+                }
+            }
+        }
+        return;
+    }
+    
+    /**
+     * Process type parameters from a type inference constraint A convertible-to F.
+     */
+    private static void processAtoFtpar(GenTypeParameter aPar, GenTypeParameter fPar,
+            Map<String,Set<GenTypeSolid>> tlbConstraints, Map<String,GenTypeSolid> teqConstraints)
+    {
+        if (fPar instanceof GenTypeSolid) {
+            if (aPar instanceof GenTypeSolid) {
+                // aPar = fPar
+                processAeqFConstraint((GenTypeSolid) aPar, (GenTypeSolid) fPar, tlbConstraints, teqConstraints);
+            }
+        } else {
+            GenTypeSolid flbound = fPar.getLowerBound();
+            if (flbound != null) {
+                // F-par is of form "? super ..."
+                GenTypeSolid albound = aPar.getLowerBound();
+                if (albound != null) {
+                    // there should only be one element in albounds
+                    // recurse with albounds[0] >> flbound[0]
+                    processFtoAConstraint(albound, flbound, tlbConstraints, teqConstraints);
+                }
+            } else {
+                // F-par is of form "? extends ..."
+                GenTypeSolid [] fubounds = fPar.getUpperBounds();
+                GenTypeSolid [] aubounds = aPar.getUpperBounds();
+                if (fubounds.length > 0 && aubounds.length > 0) {
+                    // recurse with aubounds << fubounds[0]
+                    processAtoFConstraint(IntersectionType.getIntersection(aubounds), fubounds[0], tlbConstraints, teqConstraints);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Process a type inference constraint of the form "A is equal to F".
+     */
+    private static void processAeqFConstraint(GenTypeSolid a, GenTypeSolid f,
+            Map<String,Set<GenTypeSolid>> tlbConstraints, Map<String,GenTypeSolid> teqConstraints)
+    {
+        if (f instanceof GenTypeTpar) {
+            // The constraint T == A is implied.
+            GenTypeTpar t = (GenTypeTpar) f;
+            teqConstraints.put(t.getTparName(), a);
+        }
+        
+        else if (f.getArrayComponent() instanceof GenTypeSolid) {
+            // "If F = U[] ... if A is an array type V[], or a type variable with an
+            // upper bound that is an array type V[]..."
+            GenTypeSolid [] asts;
+            if (a instanceof GenTypeDeclTpar)
+                asts = ((GenTypeDeclTpar) a).upperBounds();
+            else
+                asts = new GenTypeSolid[] {a};
+            
+            for (int i = 0; i < asts.length; i++) {
+                JavaType act = asts[i].getArrayComponent();
+                if (act instanceof GenTypeSolid) {
+                    processAeqFConstraint((GenTypeSolid) act, (GenTypeSolid) f.getArrayComponent(), tlbConstraints, teqConstraints);
+                }
+            }
+        }
+        
+        else {
+            GenTypeClass cf = f.asClass();
+            GenTypeClass af = a.asClass();
+            if (af != null && cf != null) {
+                if (cf.classloaderName().equals(af.classloaderName())) {
+                    Map<String,GenTypeParameter> fMap = cf.getMap();
+                    Map<String,GenTypeParameter> aMap = af.getMap();
+                    if (fMap != null && aMap != null) {
+                        Iterator<String> j = fMap.keySet().iterator();
+                        while (j.hasNext()) {
+                            String tpName = j.next();
+                            GenTypeParameter fPar = fMap.get(tpName);
+                            GenTypeParameter aPar = aMap.get(tpName);
+                            processAeqFtpar(aPar, fPar, tlbConstraints, teqConstraints);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Process type parameters from a type inference constraint A equal-to F.
+     */
+    private static void processAeqFtpar(GenTypeParameter aPar, GenTypeParameter fPar,
+            Map<String,Set<GenTypeSolid>> tlbConstraints, Map<String,GenTypeSolid> teqConstraints)
+    {
+        if (aPar instanceof GenTypeSolid && fPar instanceof GenTypeSolid) {
+            processAeqFConstraint((GenTypeSolid) aPar, (GenTypeSolid) fPar, tlbConstraints, teqConstraints);
+        }
+        else if (aPar instanceof GenTypeWildcard && fPar instanceof GenTypeWildcard) {
+            GenTypeSolid flBound = fPar.getLowerBound();
+            GenTypeSolid [] fuBounds = fPar.getUpperBounds();
+            // F = ? super U,  A = ? super V
+            if (flBound != null) {
+                GenTypeSolid alBound = aPar.getLowerBound();
+                if (alBound != null)
+                    processAeqFConstraint(alBound, flBound, tlbConstraints, teqConstraints);
+            }
+            // F = ? extends U, A = ? extends V
+            else if (fuBounds.length != 0) {
+                GenTypeSolid [] auBounds = aPar.getUpperBounds();
+                if (auBounds.length != 0)
+                    processAeqFConstraint(IntersectionType.getIntersection(auBounds), fuBounds[0], tlbConstraints, teqConstraints);
+            }
+        }
+    }
+
+    /**
+     * Process a type inference constraint of the form "F is convertible to A".
+     */
+    private static void processFtoAConstraint(GenTypeSolid a, GenTypeSolid f,
+            Map<String,Set<GenTypeSolid>> tlbConstraints, Map<String,GenTypeSolid> teqConstraints)
+    {
+        // This is pretty much nothing like what the JLS says it should be. As far as I can
+        // make out, the JLS is just plain wrong.
+        
+        // If F = T, then T <: A is implied: but we cannot make use of such a constraint.
+        // If F = U[] ...
+        if (f.getArrayComponent() instanceof GenTypeSolid) {
+            // "If F = U[] ... if A is an array type V[], or a type variable with an
+            // upper bound that is an array type V[]..."
+            GenTypeSolid [] asts;
+            if (a instanceof GenTypeDeclTpar)
+                asts = ((GenTypeDeclTpar) a).upperBounds();
+            else
+                asts = new GenTypeSolid[] {a};
+            
+            for (int i = 0; i < asts.length; i++) {
+                JavaType act = asts[i].getArrayComponent();
+                if (act instanceof GenTypeSolid) {
+                    processFtoAConstraint((GenTypeSolid) act, (GenTypeSolid) f.getArrayComponent(), tlbConstraints, teqConstraints);
+                }
+            }
+        }
+        
+        else if (f.asClass() != null) {
+            GenTypeClass cf = f.asClass();
+            if (! (a instanceof GenTypeTpar)) {
+                GenTypeClass [] asts = a.getReferenceSupertypes();
+                for (int i = 0; i < asts.length; i++) {
+                    try {
+                        GenTypeClass fMapped = cf.mapToSuper(asts[i].classloaderName());
+                        Map<String,GenTypeParameter> aMap = asts[i].getMap();
+                        Map<String,GenTypeParameter> fMap = fMapped.getMap();
+                        if (aMap != null && fMap != null) {
+                            Iterator<String> j = fMap.keySet().iterator();
+                            while (j.hasNext()) {
+                                String tpName = j.next();
+                                GenTypeParameter fPar = fMap.get(tpName);
+                                GenTypeParameter aPar = aMap.get(tpName);
+                                processFtoAtpar(aPar, fPar, tlbConstraints, teqConstraints);
+                            }
+                        }
+                    }
+                    catch (BadInheritanceChainException bice) {}
+                }
+            }
+        }
+    }
+
+    /**
+     * Process type parameters from a type inference constraint F convertible-to A.
+     */
+    private static void processFtoAtpar(GenTypeParameter aPar, GenTypeParameter fPar,
+            Map<String,Set<GenTypeSolid>> tlbConstraints, Map<String,GenTypeSolid> teqConstraints)
+    {
+        if (fPar instanceof GenTypeSolid) {
+            if (aPar instanceof GenTypeSolid) {
+                processAeqFConstraint((GenTypeSolid) aPar, (GenTypeSolid) fPar, tlbConstraints, teqConstraints);
+            }
+            else {
+                GenTypeSolid alBound = aPar.getLowerBound();
+                if (alBound != null) {
+                    // aPar is of the form "? super ..."
+                    processAtoFConstraint(alBound, (GenTypeSolid) fPar, tlbConstraints, teqConstraints);
+                }
+                else {
+                    GenTypeSolid [] auBounds = aPar.getUpperBounds();
+                    if (auBounds.length != 0) {
+                        processFtoAConstraint(auBounds[0], (GenTypeSolid) fPar, tlbConstraints, teqConstraints);
+                    }
+                }
+            }
+        }
+        
+        else {
+            // fPar must be a wildcard
+            GenTypeSolid flBound = fPar.getLowerBound();
+            if (flBound != null) {
+                if (aPar instanceof GenTypeWildcard) {
+                    // fPar is ? super ...
+                    GenTypeSolid alBound = aPar.getLowerBound();
+                    if (alBound != null) {
+                        processAtoFConstraint(alBound, flBound, tlbConstraints, teqConstraints);
+                    }
+                }
+                else {
+                    // fPar is ? extends ...
+                    GenTypeSolid [] fuBounds = fPar.getUpperBounds();
+                    GenTypeSolid [] auBounds = aPar.getUpperBounds();
+                    if (auBounds.length != 0 && fuBounds.length != 0) {
+                        processFtoAConstraint(auBounds[0], fuBounds[0], tlbConstraints, teqConstraints);
+                    }
+                }
+            }
+        }
+    }
+        
+    /**
+     * Get the candidate list of methods with the given name and argument types. The returned
+     * list will be the maximally specific methods (as defined by the JLS 15.12.2.5). The
+     * methods returned in the list might not be <i>appropriate</i> as according to JLS 15.12.3.
+     * 
+     * @param methodName    The name of the method
+     * @param targetTypes   The types to search for declarations of this method
+     * @param argumentTypes The types of the arguments supplied in the method invocation
+     * @param typeArgs      The type arguments, if any, supplied in the method invocation
+     * @return  an ArrayList of MethodCallDesc - the list of candidate methods
+     * @throws RecognitionException
+     */
+    public static ArrayList<MethodCallDesc> getSuitableMethods(String methodName,
+            GenTypeSolid targetType, JavaType [] argumentTypes, List<GenTypeParameter> typeArgs,
+            Reflective accessType)
+    {
+        ArrayList<MethodCallDesc> suitableMethods = new ArrayList<MethodCallDesc>();
+        
+        Stack<GenTypeSolid> targetTypes = new Stack<GenTypeSolid>();
+        targetTypes.push(targetType);
+        Set<GenTypeSolid> doneTypes = new HashSet<GenTypeSolid>();
+        
+        // JLS 4.5.2 specifies members of parameterized types
+        // JLS 4.4, the members of a type variable are the members of the intersection type of the
+        //          bounds
+        // Mostly straightforward.
+        
+        while (! targetTypes.isEmpty()) {
+            GenTypeSolid topType = targetTypes.pop();
+            GenTypeClass targetClass = topType.asClass();
+            if (targetClass == null) {
+                GenTypeSolid [] bounds = topType.getUpperBounds();
+                for (int i = 0; i < bounds.length; i++) {
+                    if (doneTypes.add(bounds[i])) {
+                        targetTypes.push(bounds[i]);
+                    }
+                }
+                continue;
+            }
+            
+            // Check members of supertypes
+            Reflective ref = targetClass.getReflective();
+            List<GenTypeClass> supers = ref.getSuperTypes();
+            Map<String,GenTypeParameter> tparMap = targetClass.getMap();
+
+            for (GenTypeClass superType : supers) {
+                GenTypeClass mapped = superType.mapTparsToTypes(tparMap);
+                if (doneTypes.add(mapped)) {
+                    targetTypes.push(mapped);
+                }
+            }
+            
+            Map<String,Set<MethodReflective>> methodMap = targetClass.getReflective()
+                    .getDeclaredMethods();
+            Set<MethodReflective> methods = methodMap.get(methodName);
+
+            if (methods == null) {
+                continue;
+            }
+            
+            // Find methods that are applicable, and
+            // accessible. See JLS 15.12.2.1.
+            for (MethodReflective method : methods) {
+
+                // Check accessibility
+                if (!JavaUtils.checkMemberAccess(method.getDeclaringType(), targetType, accessType,
+                        method.getModifiers(), false)) {
+                    continue;
+                }
+                
+                // check that the method is applicable (and under
+                // what constraints)
+                MethodCallDesc mcd = isMethodApplicable(targetClass, typeArgs, method, argumentTypes);
+
+                // Iterate through the current candidates, and:
+                // - replace one or more of them with this one
+                //   (this one is more precise)
+                //   OR
+                // - add this one (no more or less precise than
+                //   any other candidates)
+                //   OR
+                // - discard this one (less precise than another)
+
+                if (mcd != null) {
+                    boolean replaced = false;
+                    for (int j = 0; j < suitableMethods.size(); j++) {
+                        //suitableMethods.add(methods[i]);
+                        MethodCallDesc mc = (MethodCallDesc) suitableMethods.get(j);
+                        int compare = mcd.compareSpecificity(mc);
+                        if (compare == 1) {
+                            // this method is more specific
+                            suitableMethods.remove(j);
+                            j--;
+                        }
+                        else if (compare == -1) {
+                            // other method is more specific
+                            replaced = true;
+                            break;
+                        }
+                    }
+
+                    if (! replaced)
+                        suitableMethods.add(mcd);
+                }
+            }
+        }
+        return suitableMethods;
+    }
+    
+    /**
+     * Unbox a type, if it is a class type which represents a primitive type
+     * in object form (eg. java.lang.Integer).<p>
+     * 
+     * Other class types are returned unchanged.<p>
+     * 
+     * To determine whether unboxing occurred, compare the result with the
+     * object which was passed in. (The same object will be returned if no
+     * unboxing took place).
+     * 
+     * @param b  The type to unbox
+     * @return  The unboxed type
+     */
+    public static JavaType unBox(JavaType b)
+    {
+        GenTypeClass c = b.asClass();
+        if (c != null) {
+            String cName = c.classloaderName();
+            if (cName.equals("java.lang.Integer")) {
+                return JavaPrimitiveType.getInt();
+            }
+            else if (cName.equals("java.lang.Long")) {
+                return JavaPrimitiveType.getLong();
+            }
+            else if (cName.equals("java.lang.Short")) {
+                return JavaPrimitiveType.getShort();
+            }
+            else if (cName.equals("java.lang.Byte")) {
+                return JavaPrimitiveType.getByte();
+            }
+            else if (cName.equals("java.lang.Character")) {
+                return JavaPrimitiveType.getChar();
+            }
+            else if (cName.equals("java.lang.Float")) {
+                return JavaPrimitiveType.getFloat();
+            }
+            else if (cName.equals("java.lang.Double")) {
+                return JavaPrimitiveType.getDouble();
+            }
+            else if (cName.equals("java.lang.Boolean")) {
+                return JavaPrimitiveType.getBoolean();
+            }
+            else {
+                return b;
+            }
+        }
+        else {
+            return b;
+        }
+    }
+    
+    /**
+     * Box a type, if it is a primitive type such as "int".<p>
+     * 
+     * Other types are returned unchanged, however void/null types return null.<p>
+     * 
+     * @param b  The type to box
+     * @return  The boxed type
+     */
+    private static GenTypeSolid boxType(JavaType u)
+    {
+        if (u.isPrimitive()) {
+            if (u.typeIs(JavaType.JT_INT)) {
+                return new GenTypeClass(new JavaReflective(Integer.class));
+            }
+            else if (u.typeIs(JavaType.JT_LONG)) {
+                return new GenTypeClass(new JavaReflective(Long.class));
+            }
+            else if (u.typeIs(JavaType.JT_SHORT)) {
+                return new GenTypeClass(new JavaReflective(Short.class));
+            }
+            else if (u.typeIs(JavaType.JT_BYTE)) {
+                return new GenTypeClass(new JavaReflective(Byte.class));
+            }
+            else if (u.typeIs(JavaType.JT_CHAR)) {
+                return new GenTypeClass(new JavaReflective(Character.class));
+            }
+            else if (u.typeIs(JavaType.JT_FLOAT)) {
+                return new GenTypeClass(new JavaReflective(Float.class));
+            }
+            else if (u.typeIs(JavaType.JT_DOUBLE)) {
+                return new GenTypeClass(new JavaReflective(Double.class));
+            }
+            else if (u.typeIs(JavaType.JT_BOOLEAN)) {
+                return new GenTypeClass(new JavaReflective(Boolean.class));
+            }
+        }
+        
+        return u.asSolid();
+    }
+        
+    /**
+     * Conditionally box a type. The type is only boxed if the boolean flag
+     * passed in the second parameter is true.<p>
+     * 
+     * This is a helper method to improve readability.<p>
+     * 
+     * @see TextAnalyzer#boxType(JavaType)
+     * 
+     * @param u    The type to box
+     * @param box  The flag indicating whether boxing should occur
+     * @return
+     */
+//    private JavaType maybeBox(JavaType u, boolean box)
+//    {
+//        if (box)
+//            return boxType(u);
+//        else
+//            return u;
+//    }
+    
+    /**
+     * A simple structure to hold various information about a method call.
+     * 
+     * @author Davin McCall
+     */
+    public static class MethodCallDesc
+    {
+        public MethodReflective method;
+        public List<JavaType> argTypes; // list of GenType
+        public boolean vararg;   // is a vararg call
+        public boolean autoboxing; // requires autoboxing
+        public JavaType retType; // effective return type (before capture conversion)
+        
+        /**
+         * Constructor for MethodCallDesc.
+         * 
+         * @param m   The method being called
+         * @param argTypes   The effective types of the arguments, as an
+         *                   ordered list
+         * @param vararg      Whether the method is being called as a vararg
+         *                    method
+         * @param autoboxing  Whether autoboxing is required for parameters
+         * @param retType     The effective return type
+         */
+        public MethodCallDesc(MethodReflective m, List<JavaType> argTypes, boolean vararg, boolean autoboxing, JavaType retType)
+        {
+            this.method = m;
+            this.argTypes = argTypes;
+            this.vararg = vararg;
+            this.autoboxing = autoboxing;
+            this.retType = retType;
+        }
+        
+        /**
+         * Find out which (if any) method call is strictly more specific than the
+         * other. Both calls must be valid calls to the same method with the same
+         * number of parameters.
+         * 
+         * @param other  The method to compare with
+         * @return 1 if this method is more specific;
+         *         -1 if the other method is more specific;
+         *         0 if neither method is more specific than the other.
+         * 
+         * See JLS 15.12.2.5 (by "more specific", we mean what the JLS calls
+         * "strictly more specific", more or less. We also take arity into account.
+         * This method effectively combines and performs phases 1-3 as specified by
+         * JLS 15.12.2.2 - 15.12.2.4
+         */
+        public int compareSpecificity(MethodCallDesc other)
+        {
+            if (other.vararg && ! vararg) {
+                return 1; // we are more specific
+            }
+            if (! other.vararg && vararg) {
+                return -1; // we are less specific
+            }
+            
+            // I am reasonably sure this gives the same result as the algorithm
+            // described in the JLS section 15.12.2.5, and it has the advantage
+            // of being a great deal simpler.
+            Iterator<JavaType> i = argTypes.iterator();
+            Iterator<JavaType> j = other.argTypes.iterator();
+            int upCount = 0;
+            int downCount = 0;
+            
+            while (i.hasNext()) {
+                JavaType myArg = i.next();
+                JavaType otherArg = j.next();
+                
+                if (myArg.isAssignableFrom(otherArg)) {
+                    if (! otherArg.isAssignableFrom(myArg))
+                        upCount++;
+                }
+                else if (otherArg.isAssignableFrom(myArg)) {
+                    downCount++;
+                }
+            }
+            
+            if (upCount > 0 && downCount == 0) {
+                return -1; // other is more specific
+            }
+            else if (downCount > 0 && upCount == 0) {
+                return 1;  // other is less specific
+            }
+            
+            return 0;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/TextParser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/TextParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8a9603bd1ca0b96f545c2878f471286b5c8c6b9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/TextParser.java
@@ -0,0 +1,2248 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Stack;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.GenTypeSolid;
+import bluej.debugger.gentype.JavaPrimitiveType;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.TextAnalyzer.MethodCallDesc;
+import bluej.parser.entity.ConstantBoolValue;
+import bluej.parser.entity.ConstantFloatValue;
+import bluej.parser.entity.ConstantIntValue;
+import bluej.parser.entity.ConstantStringEntity;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.ErrorEntity;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.NullEntity;
+import bluej.parser.entity.PackageOrClass;
+import bluej.parser.entity.SolidTargEntity;
+import bluej.parser.entity.TypeArgumentEntity;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.entity.UnboundedWildcardEntity;
+import bluej.parser.entity.UnresolvedEntity;
+import bluej.parser.entity.ValueEntity;
+import bluej.parser.entity.WildcardExtendsEntity;
+import bluej.parser.entity.WildcardSuperEntity;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+import bluej.utility.JavaReflective;
+
+/**
+ * A parser for the codepad.
+ * 
+ * @author Davin McCall
+ */
+public class TextParser extends JavaParser
+{
+    private EntityResolver resolver;
+    private JavaEntity accessType;
+    private boolean staticAccess;
+    
+    protected Stack<JavaEntity> valueStack = new Stack<JavaEntity>();
+    private int arrayCount = 0;
+    
+    /** A class to represent operators, possibly associated with a token */
+    protected class Operator
+    {
+        int type;
+        LocatableToken token;
+        Operator(int type, LocatableToken token) { this.type = type; this.token = token; }
+        int getType() { return type; }
+        LocatableToken getToken() { return token; }
+    }
+    
+    protected Stack<Operator> operatorStack = new Stack<Operator>();
+    
+    /** A stack of type argument lists - one list for each method call on the operator stack */
+    protected Stack<List<LocatableToken>> typeArgStack = new Stack<List<LocatableToken>>();
+    
+    /*
+     * Make up some operators - only for cases where there is not a token
+     * type we could use, or for where the token is ambiguos:
+     */
+    
+    private static final int CAST_OPERATOR = JavaTokenTypes.INVALID + 1;
+    private static final int BAD_CAST_OPERATOR = CAST_OPERATOR + 1;
+    private static final int PAREN_OPERATOR = BAD_CAST_OPERATOR + 1;
+    private static final int MEMBER_CALL_OP = PAREN_OPERATOR + 1;
+    private static final int METHOD_CALL_OP = MEMBER_CALL_OP + 1;
+    private static final int CONSTRUCTOR_CALL_OP = METHOD_CALL_OP + 1;
+    
+    private static final int UNARY_PLUS_OP = CONSTRUCTOR_CALL_OP + 1;
+    private static final int UNARY_MINUS_OP = UNARY_PLUS_OP + 1;
+    
+    /*
+     * Parse states - mainly so we know what to do with a type specification
+     * when we seen one:
+     */
+    
+    private static final int STATE_NONE = 0;
+    private static final int STATE_NEW = 1;  // just saw "new"
+    private static final int STATE_NEW_ARGS = 2;  // expecting "new" arguments or array dimensions
+    private static final int STATE_INSTANCEOF = 3;  // just saw "instanceof", expecting type
+    
+    private int state = STATE_NONE;
+
+    /** Arguments for a method or constructor call are added to the list at the top of this stack */
+    private Stack<List<JavaEntity>> argumentStack = new Stack<List<JavaEntity>>();
+    
+    
+    /**
+     * Construct a text parser for parsing an expression.
+     * 
+     * @param resolver   Resolver to resolve symbols
+     * @param r           Reader to read the expression source
+     * @param accessType   The containing type
+     * @param staticAccess Whether the expression occurs in a static context
+     */
+    public TextParser(EntityResolver resolver, Reader r, JavaEntity accessType, boolean staticAccess)
+    {
+        super(r);
+        this.resolver = resolver;
+        this.accessType = accessType;
+        this.staticAccess = staticAccess;
+    }
+    
+    /**
+     * Construct a text parser for parsing an expression, where the expression is located
+     * at a particular line and column in the source.
+     * 
+     * @param resolver   Resolver to resolve symbols
+     * @param r           Reader to read the expression source
+     * @param accessType   The containing type
+     * @param staticAccess Whether the expression occurs in a static context
+     * @param line        The line in the source where the expression occurs
+     * @param col         The column in the source where the expression occurs
+     */
+    public TextParser(EntityResolver resolver, Reader r, JavaEntity accessType, boolean staticAccess,
+            int line, int col, int pos)
+    {
+        super(r, line, col, pos);
+        this.resolver = resolver;
+        this.accessType = accessType;
+        this.staticAccess = staticAccess;
+    }
+    
+    /**
+     * Construct a text parser for parsing an expression which is represented in a String.
+     * 
+     * @param resolver   Resolver to resolve symbols
+     * @param s           A string containing the expression
+     * @param accessType   The containing type
+     * @param staticAccess Whether the expression occurs in a static context
+     */
+    public TextParser(EntityResolver resolver, String s, JavaEntity accessType, boolean staticAccess)
+    {
+        this(resolver, new StringReader(s), accessType, staticAccess);
+    }
+    
+    /**
+     * Check whether the parsed expression ended at the end of the input.
+     *  
+     * @return  true iff the parsed expression ended at the end of the input (reader or string);
+     *          false otherwise.
+     */
+    public boolean atEnd()
+    {
+        return tokenStream.LA(1).getType() == JavaTokenTypes.EOF;
+    }
+    
+    /**
+     * Get the type of the parsed expression. If the type is unknown or an error occurred,
+     * returns {@code null}.
+     */
+    public JavaEntity getExpressionType()
+    {
+        processHigherPrecedence(getPrecedence(JavaTokenTypes.EOF) - 1);
+        if (valueStack.isEmpty()) {
+            return null;
+        }
+        return valueStack.pop();
+    }
+    
+    /**
+     * Pop an item from the value stack. If there are no values to pop, supply an error entity.
+     */
+    protected JavaEntity popValueStack()
+    {
+        if (! valueStack.isEmpty()) {
+            return valueStack.pop();
+        }
+        return new ErrorEntity();
+    }
+    
+    /**
+     * Get the precedence level for a given operator type.
+     */
+    private int getPrecedence(int tokenType)
+    {
+        switch (tokenType) {
+        case JavaTokenTypes.LCURLY:
+            return -10; // beginning of anon class body
+        case PAREN_OPERATOR:
+            return -2;
+        case JavaTokenTypes.LITERAL_new:
+            return -1;
+        case JavaTokenTypes.ASSIGN:
+        case JavaTokenTypes.BAND_ASSIGN:
+        case JavaTokenTypes.BOR_ASSIGN:
+        case JavaTokenTypes.PLUS_ASSIGN:
+        case JavaTokenTypes.MINUS_ASSIGN:
+        case JavaTokenTypes.STAR_ASSIGN:
+        case JavaTokenTypes.DIV_ASSIGN:
+        case JavaTokenTypes.SL_ASSIGN:
+        case JavaTokenTypes.SR_ASSIGN:
+        case JavaTokenTypes.BSR_ASSIGN:
+        case JavaTokenTypes.MOD_ASSIGN:
+        case JavaTokenTypes.BXOR_ASSIGN:
+            return 0;
+        case JavaTokenTypes.QUESTION:
+            return 1;
+        case JavaTokenTypes.LT:
+        case JavaTokenTypes.LE:
+        case JavaTokenTypes.GT:
+        case JavaTokenTypes.GE:
+        case JavaTokenTypes.LITERAL_instanceof:
+            return 8;
+        case JavaTokenTypes.EQUAL:
+        case JavaTokenTypes.NOT_EQUAL:
+            return 9;        
+        case JavaTokenTypes.SL:
+        case JavaTokenTypes.SR:
+        case JavaTokenTypes.BSR:
+            return 10;
+        case JavaTokenTypes.PLUS:
+        case JavaTokenTypes.MINUS:
+            return 11;
+        case JavaTokenTypes.STAR:
+        case JavaTokenTypes.DIV:
+            return 12;
+        case JavaTokenTypes.LNOT:
+        case JavaTokenTypes.BNOT:
+        case JavaTokenTypes.INC:
+        case JavaTokenTypes.DEC:
+        case UNARY_PLUS_OP:
+        case UNARY_MINUS_OP:
+        case CAST_OPERATOR:
+        case BAD_CAST_OPERATOR:
+            return 13;
+        case JavaTokenTypes.DOT:
+        case MEMBER_CALL_OP:
+        case METHOD_CALL_OP:
+        case CONSTRUCTOR_CALL_OP:
+            return 20;
+        default:
+        }
+        
+        return -1;
+    }
+    
+    /** 
+     * Process all on-stack operators with a higher precedence than that given
+     */
+    private void processHigherPrecedence(int precedence)
+    {
+        while (! operatorStack.isEmpty()) {
+            Operator top = operatorStack.peek();
+            if (getPrecedence(top.getType()) <= precedence) {
+                break;
+            }
+            operatorStack.pop();
+            processOperator(top);
+        }
+    }
+    
+    /**
+     * Process an operator, take the operands from the value stack and leave the result on the
+     * stack.
+     */
+    private void processOperator(Operator operator)
+    {
+        int tokenType = operator.getType();
+        
+        JavaEntity arg1;
+        JavaEntity arg2;
+        
+        switch (tokenType) {
+        case JavaTokenTypes.PLUS:
+        case JavaTokenTypes.MINUS:
+        case JavaTokenTypes.STAR:
+        case JavaTokenTypes.DIV:
+        case JavaTokenTypes.MOD:
+        case JavaTokenTypes.SL:
+        case JavaTokenTypes.SR:
+        case JavaTokenTypes.BSR:
+        case JavaTokenTypes.LT:
+        case JavaTokenTypes.LE:
+        case JavaTokenTypes.GT:
+        case JavaTokenTypes.GE:
+        case JavaTokenTypes.EQUAL:
+        case JavaTokenTypes.NOT_EQUAL:
+        case JavaTokenTypes.ASSIGN:
+        case JavaTokenTypes.BAND_ASSIGN:
+        case JavaTokenTypes.BOR_ASSIGN:
+        case JavaTokenTypes.PLUS_ASSIGN:
+        case JavaTokenTypes.MINUS_ASSIGN:
+        case JavaTokenTypes.STAR_ASSIGN:
+        case JavaTokenTypes.DIV_ASSIGN:
+        case JavaTokenTypes.SL_ASSIGN:
+        case JavaTokenTypes.SR_ASSIGN:
+        case JavaTokenTypes.BSR_ASSIGN:
+        case JavaTokenTypes.MOD_ASSIGN:
+        case JavaTokenTypes.BXOR_ASSIGN:
+        case JavaTokenTypes.BAND:
+        case JavaTokenTypes.BOR:
+        case JavaTokenTypes.BXOR:
+        case JavaTokenTypes.LOR:
+        case JavaTokenTypes.LAND:
+            arg2 = popValueStack();
+            arg1 = popValueStack();
+            doBinaryOp(arg1, arg2, operator);
+            break;
+        case JavaTokenTypes.LNOT:
+        case JavaTokenTypes.BNOT:
+        case JavaTokenTypes.INC:
+        case JavaTokenTypes.DEC:
+        case UNARY_MINUS_OP:
+        case UNARY_PLUS_OP:
+            arg1 = popValueStack();
+            checkArg(arg1, operator);
+            break;
+        case CAST_OPERATOR:
+            doCast();
+            break;
+        case BAD_CAST_OPERATOR:
+            popValueStack(); // remove the value being cast
+            valueStack.push(new ErrorEntity());
+            break;
+        case JavaTokenTypes.QUESTION:
+            processQuestionOperator();
+            break;
+        }
+    }
+    
+    private strictfp void doCast()
+    {
+        // Conversions allowed are specified in JLS 3rd ed. 5.5.
+        // But see: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7029688
+        
+        ValueEntity varg1 = popValueStack().resolveAsValue(); // value being cast
+        TypeEntity castType = popValueStack().resolveAsType();  // cast-to type
+        if (varg1 == null || castType == null) {
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        if (ValueEntity.isConstant(varg1)) {
+            JavaType jctype = castType.getType();
+            if (jctype.isIntegralType()) {
+                long ival;
+                if (varg1.hasConstantIntValue()) {
+                    ival = varg1.getConstantIntValue();
+                    if (jctype.typeIs(JavaType.JT_BYTE)) {
+                        ival = (byte) ival;
+                    }
+                    else if (jctype.typeIs(JavaType.JT_CHAR)) {
+                        ival = (char) ival;
+                    }
+                    else if (jctype.typeIs(JavaType.JT_INT)) {
+                        ival = (int) ival;
+                    }
+                    else if (jctype.typeIs(JavaType.JT_SHORT)) {
+                        ival = (short) ival;
+                    }
+                }
+                else if (varg1.hasConstantFloatValue()) {
+                    if (jctype.typeIs(JavaType.JT_BYTE)) {
+                        ival = (byte) varg1.getConstantFloatValue();
+                    }
+                    else if (jctype.typeIs(JavaType.JT_CHAR)) {
+                        ival = (char) varg1.getConstantFloatValue();
+                    }
+                    else if (jctype.typeIs(JavaType.JT_INT)) {
+                        ival = (int) varg1.getConstantFloatValue();
+                    }
+                    else if (jctype.typeIs(JavaType.JT_SHORT)) {
+                        ival = (short) varg1.getConstantFloatValue();
+                    }
+                    else {
+                        ival = (long) varg1.getConstantFloatValue();
+                    }
+                }
+                else {
+                    // string constant
+                    valueStack.push(new ErrorEntity());
+                    return;
+                }
+                
+                valueStack.push(new ConstantIntValue(null, jctype, ival));
+                return;
+            }
+            else if (jctype.typeIs(JavaType.JT_FLOAT) || jctype.typeIs(JavaType.JT_DOUBLE)) {
+                double dval;
+                if (varg1.hasConstantIntValue()) {
+                    dval = varg1.getConstantIntValue();
+                }
+                else if (varg1.hasConstantFloatValue()) {
+                    dval = varg1.getConstantFloatValue();
+                }
+                else {
+                    valueStack.push(new ErrorEntity());
+                    return;
+                }
+                
+                if (jctype.typeIs(JavaType.JT_FLOAT)) {
+                    dval = (float) dval;
+                }
+                
+                valueStack.push(new ConstantFloatValue(jctype, dval));
+                return;
+            }
+            else if (jctype.toString().equals("java.lang.String")) {
+                // Argument is constant: it must be a constant string.
+                if (varg1.isConstantString()) {
+                    valueStack.push(varg1);
+                }
+                else {
+                    valueStack.push(new ErrorEntity());
+                }
+                return;
+            }
+        }
+        
+        // Argument is not a constant, or cast is to a type that won't result in
+        // a constant.
+        
+        JavaType argType = varg1.getType();
+        JavaType jctype = castType.getType();
+        
+        if (argType.isPrimitive() && ! jctype.isPrimitive()) {
+            if (argType.typeIs(JavaType.JT_NULL)) {
+                valueStack.push(new ValueEntity(jctype));
+                return;
+            }
+            
+            // The only remaining allowable case is a boxing conversion.
+            
+            String jctypeStr = jctype.toString();
+            
+            if (argType.typeIs(JavaType.JT_BOOLEAN) && jctypeStr.equals("java.lang.Boolean")
+                    || argType.typeIs(JavaType.JT_CHAR) && jctypeStr.equals("java.lang.Character")
+                    || argType.typeIs(JavaType.JT_BYTE) && jctypeStr.equals("java.lang.Byte")
+                    || argType.typeIs(JavaType.JT_SHORT) && jctypeStr.equals("java.lang.Short")
+                    || argType.typeIs(JavaType.JT_INT) && jctypeStr.equals("java.lang.Integer")
+                    || argType.typeIs(JavaType.JT_LONG) && jctypeStr.equals("java.lang.Long")
+                    || argType.typeIs(JavaType.JT_FLOAT) && jctypeStr.equals("java.lang.Float")
+                    || argType.typeIs(JavaType.JT_DOUBLE) && jctypeStr.equals("java.lang.Double")) {
+                valueStack.push(new ValueEntity(jctype));
+            }
+            else {
+                valueStack.push(new ErrorEntity());
+            }
+            return;
+        }
+        
+        JavaType argUnboxed = TextAnalyzer.unBox(argType);
+        
+        if (argUnboxed.isNumeric() && jctype.isNumeric()) {
+            // Widening or narrowing primitive conversion - allowed.
+            // NOTE: The JLS doesn't actually allow the case where the argument type is a
+            //       boxed type, but the javac compiler *does*, as does the Eclipse compiler.
+            // NOTE: Also, the JLS doesn't allow a cast from byte to char, because (JLS 5.1.4)
+            //       that requires a widening conversion *followed by* a narrowing conversion,
+            //       which isn't one of the options allowed for a cast.
+            valueStack.push(new ValueEntity(jctype));
+            return;
+        }
+        
+        if (jctype.isPrimitive()) {
+            // Note the numeric cases are handled above.
+            if (jctype.typeIs(JavaType.JT_BOOLEAN) && argUnboxed.typeIs(JavaType.JT_BOOLEAN)) {
+                valueStack.push(new ValueEntity(jctype));
+            }
+            else {
+                valueStack.push(new ErrorEntity());
+            }
+            return;
+        }
+        
+        // TODO check operand can be cast to this type - widening or narrowing
+        //      reference conversion.
+        valueStack.push(new ValueEntity(jctype));
+    }
+    
+    @Override
+    protected void gotArrayElementAccess()
+    {
+        JavaEntity index = popValueStack();
+        processHigherPrecedence(getPrecedence(JavaTokenTypes.DOT) - 1); // Process DOT precedence and higher
+        JavaEntity array = popValueStack();
+        
+        index = index.resolveAsValue();
+        array = array.resolveAsValue();
+        if (index == null || array == null) {
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        JavaType componentType = array.getType().getArrayComponent();
+        if (componentType == null) {
+            valueStack.push(new ErrorEntity());
+        }
+        else {
+            valueStack.push(new ValueEntity(componentType));
+        }
+    }
+    
+    private void processNewOperator(Operator token)
+    {
+        if (! argumentStack.isEmpty()) {
+            argumentStack.pop(); // constructor arguments
+            // TODO check argument validity
+        }
+        else {
+            popValueStack();
+            valueStack.push(new ErrorEntity());
+        }
+    }
+    
+    /**
+     * Process the "member call operator".
+     */
+    private void processMemberCall(Operator op)
+    {
+        // See JLS 15.12
+        // step 1 - determine type to search
+        //  Seeing as this is a member call, that's already mostly done.
+        JavaEntity target = popValueStack();
+        JavaEntity vtarget = target.resolveAsValue();
+        GenTypeSolid targetType;
+        
+        if (vtarget != null) {
+            GenTypeSolid stype = vtarget.getType().asSolid();
+            if (stype == null) {
+                // call on a primitive
+                valueStack.push(new ErrorEntity());
+                return;
+            }
+            targetType = stype;
+        }
+        else {
+            // entity may be a type rather than a value
+            target = target.resolveAsType();
+            if (target == null) {
+                valueStack.push(new ErrorEntity());
+                return;
+            }
+            GenTypeSolid stype = target.getType().asSolid();
+            if (stype == null) {
+                // call on a primitive
+                valueStack.push(new ErrorEntity());
+                return;
+            }
+            targetType = stype;
+        }
+        
+        if (op.getToken().getType() == JavaTokenTypes.IDENT) {
+            processMethodCall(targetType, op.getToken().getText(), typeArgStack.pop());
+        }
+        else {
+            valueStack.push(new ErrorEntity());
+        }
+    }
+    
+    private void processMethodCall(Operator op)
+    {
+        if (op.getToken().getType() == JavaTokenTypes.IDENT) {
+            processMethodCall(accessType.getType().asClass(), op.getToken().getText(),
+                    Collections.<LocatableToken>emptyList());
+        }
+        else {
+            valueStack.push(new ErrorEntity());
+        }
+    }
+    
+    private void processMethodCall(GenTypeSolid targetType, String methodName, List<LocatableToken> typeArgTokens)
+    {
+        GenTypeClass accessClass = accessType.getType().asClass();
+        if (accessClass == null) {
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        // Gather the argument types.
+        List<JavaEntity> argList = argumentStack.pop();
+        JavaType [] argTypes = new JavaType[argList.size()];
+        for (int i = 0; i < argTypes.length; i++) {
+            JavaEntity cent = argList.get(i).resolveAsValue();
+            if (cent == null) {
+                valueStack.push(new ErrorEntity());
+                return;
+            }
+            argTypes[i] = cent.getType().getCapture();
+        }
+
+        // Determine type arguments to method invocation
+        List<GenTypeParameter> typeArgs;
+        if (! typeArgTokens.isEmpty()) {
+            DepthRef depthRef = new DepthRef();
+            ListIterator<LocatableToken> i = typeArgTokens.listIterator(1); // skip '<'
+            List<TypeArgumentEntity> typeArgEnts = readTypeArguments(i, depthRef);
+            if (typeArgEnts == null) {
+                valueStack.push(new ErrorEntity());
+                return;
+            }
+            
+            typeArgs = new ArrayList<GenTypeParameter>(typeArgEnts.size());
+            for (TypeArgumentEntity typeArgEnt : typeArgEnts) {
+                GenTypeParameter targType = typeArgEnt.getType();
+                if (targType == null || targType.isPrimitive() || targType.isWildcard()) {
+                    valueStack.push(new ErrorEntity());
+                    return;
+                }
+                typeArgs.add(targType);
+            }
+        }
+        else {
+            typeArgs = Collections.emptyList();
+        }
+
+        ArrayList<MethodCallDesc> suitable = TextAnalyzer.getSuitableMethods(methodName,
+                targetType, argTypes, typeArgs, accessClass.getReflective());
+        if (suitable.size() == 0) {
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        // JLS 3rd ed. 15.12.2.5. We already have a list of the maximally specific methods:
+        // - if one or more methods have non override-equivalent signatures, the call is ambiguous
+        // - otherwise, if there is exactly one non-abstract method, choose that one;
+        // - otherwise, arbitrarily choose one from the set with the most specific return type.
+
+        int nonAbstractCount = 0;
+        MethodCallDesc nonAbstractMethod = null;
+        MethodCallDesc mostSpecificMethod = null;
+
+        Iterator<MethodCallDesc> i = suitable.iterator();
+        MethodCallDesc first = i.next();
+        if (! first.method.isAbstract()) {
+            nonAbstractCount++;
+            nonAbstractMethod = first;
+        }
+        mostSpecificMethod = first;
+        
+        if (suitable.size() > 1) {
+            List<GenTypeDeclTpar> tpars = first.method.getTparTypes();
+            List<JavaType> paramTypes = first.method.getParamTypes();
+            while (i.hasNext()) {
+                MethodCallDesc next = i.next();
+                if (!checkOverrideEquivalence(tpars, paramTypes, next.method.getTparTypes(), next.method.getParamTypes())) {
+                    // Non override equivalent signatures: ambiguous call
+                    valueStack.push(new ErrorEntity());
+                    return;
+                }
+                if (! next.method.isAbstract()) {
+                    nonAbstractCount++;
+                    nonAbstractMethod = next;
+                }
+                
+                if (mostSpecificMethod.retType.isAssignableFrom(next.retType)) {
+                    mostSpecificMethod = next;
+                }
+            }
+        }
+        
+        MethodCallDesc chosenMethod = nonAbstractMethod;
+        if (nonAbstractCount != 1) {
+            chosenMethod = mostSpecificMethod;
+        }
+        
+        // TODO check applicability of chosen method as per JLS 3rd ed. 15.12.3
+
+        valueStack.push(new ValueEntity(chosenMethod.retType));
+    }
+    
+    private static boolean checkOverrideEquivalence(List<GenTypeDeclTpar> firstTpars, List<JavaType> firstParamTypes,
+            List<GenTypeDeclTpar> secondTpars, List<JavaType> secondParamTypes)
+    {
+        if (firstTpars.size() != 0 && secondTpars.size() != 0) {
+            // Type parameters must be matchable
+            if (firstTpars.size() != secondTpars.size()) {
+                return false;
+            }
+            
+            // Create a map from second method tpar name to first method tpar
+            Map<String,GenTypeParameter> tparMap = new HashMap<String,GenTypeParameter>();
+            Iterator<GenTypeDeclTpar> i = firstTpars.iterator();
+            Iterator<GenTypeDeclTpar> j = secondTpars.iterator();
+            while (i.hasNext()) {
+                GenTypeDeclTpar firstTpar = i.next();
+                GenTypeDeclTpar secondTpar = j.next();
+                tparMap.put(secondTpar.getTparName(), firstTpar);
+                if (!secondTpar.getUpperBound().mapTparsToTypes(tparMap).equals(firstTpar.getUpperBound())) {
+                    return false;
+                }
+            }
+            
+            // Check argument types
+            Iterator<JavaType> k = firstParamTypes.iterator();
+            Iterator<JavaType> l = secondParamTypes.iterator();
+            while (k.hasNext()) {
+                if (!l.next().mapTparsToTypes(tparMap).equals(k.next())) {
+                    return false;
+                }
+            }
+            
+            return true;
+        }
+        
+        if (firstTpars.isEmpty() && secondTpars.isEmpty()) {
+            // The parameter types might match exactly
+            boolean doMatch = true;
+            Iterator<JavaType> k = firstParamTypes.iterator();
+            Iterator<JavaType> l = secondParamTypes.iterator();
+            while (k.hasNext()) {
+                if (!l.next().equals(k.next())) {
+                    doMatch = false;
+                    break;
+                }
+            }
+            if (doMatch) {
+                return true;
+            }
+        }
+        
+        if (firstTpars.isEmpty()) {
+            // The first signature might be the erasure of the second
+            boolean doMatch = true;
+            Iterator<JavaType> k = firstParamTypes.iterator();
+            Iterator<JavaType> l = secondParamTypes.iterator();
+            while (k.hasNext()) {
+                if (!l.next().getErasedType().equals(k.next())) {
+                    doMatch = false;
+                    break;
+                }
+            }
+            if (doMatch) {
+                return true;
+            }
+        }
+        
+        if (secondTpars.isEmpty()) {
+            // The second signature might be the erasure of the first
+            boolean doMatch = true;
+            Iterator<JavaType> k = firstParamTypes.iterator();
+            Iterator<JavaType> l = secondParamTypes.iterator();
+            while (k.hasNext()) {
+                if (!l.next().equals(k.next().getErasedType())) {
+                    doMatch = false;
+                    break;
+                }
+            }
+            return doMatch;
+        }
+        
+        return false;
+    }
+
+    /**
+     * For a unary operator, check that the argument is valid,
+     * then process the operator.
+     */
+    private void checkArg(JavaEntity arg1, Operator op)
+    {
+        JavaEntity rarg1 = arg1.resolveAsValue();
+        if (rarg1 == null) {
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        doUnaryOp(rarg1, op);
+    }
+    
+    /**
+     * Do a unary plus operation (JLS 3rd ed. 15.15.3)
+     */
+    private void doUnaryPlus(ValueEntity arg)
+    {
+        JavaType argType = arg.getType();
+        if (arg.hasConstantIntValue()) {
+            long value = arg.getConstantIntValue();
+            JavaType rtype = TextAnalyzer.unaryNumericPromotion(argType);
+            valueStack.push(new ConstantIntValue(null, rtype, value));
+        }
+        else if (arg.hasConstantFloatValue()) {
+            double value = arg.getConstantFloatValue();
+            valueStack.push(new ConstantFloatValue(argType, value));
+        }
+        else {
+            JavaType rtype = TextAnalyzer.unaryNumericPromotion(argType);
+            if (rtype != null) {
+                valueStack.push(new ValueEntity(rtype));
+            }
+            else {
+                valueStack.push(new ErrorEntity());
+            }
+        }
+    }
+    
+    /**
+     * Do a unary minus operation (JLS 3rd ed. 15.15.4)
+     */
+    private void doUnaryMinus(ValueEntity arg)
+    {
+        JavaType argType = arg.getType();
+        if (arg.hasConstantIntValue()) {
+            long value = -arg.getConstantIntValue();
+            JavaType rtype = TextAnalyzer.unaryNumericPromotion(argType);
+            valueStack.push(new ConstantIntValue(null, rtype, value));
+        }
+        else if (arg.hasConstantFloatValue()) {
+            double value = -arg.getConstantFloatValue();
+            valueStack.push(new ConstantFloatValue(argType, value));
+        }
+        else {
+            JavaType rtype = TextAnalyzer.unaryNumericPromotion(argType);
+            if (rtype != null) {
+                valueStack.push(new ValueEntity(rtype));
+            }
+            else {
+                valueStack.push(new ErrorEntity());
+            }
+        }
+    }
+    
+    /**
+     * Process a unary operator.
+     */
+    private void doUnaryOp(JavaEntity arg, Operator op)
+    {
+        ValueEntity varg = arg.resolveAsValue();
+        if (varg == null) {
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        JavaType argType = varg.getType();
+
+        int ttype = op.getType();
+        switch (ttype) {
+        case JavaTokenTypes.LNOT:
+            if (varg.hasConstantBooleanValue()) {
+                boolean rval = ! varg.getConstantBooleanValue();
+                valueStack.push(new ConstantBoolValue(rval));
+            }
+            else if (argType.typeIs(JavaType.JT_BOOLEAN) || argType.toString().equals("java.lang.Boolean")) {
+                valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
+            }
+            else {
+                valueStack.push(new ErrorEntity());
+            }
+            break;
+        case JavaTokenTypes.BNOT:
+            if (varg.hasConstantIntValue()) {
+                long rval = ~ varg.getConstantIntValue();
+                JavaType rtype = TextAnalyzer.unaryNumericPromotion(argType);
+                valueStack.push(new ConstantIntValue(null, rtype, rval));
+            }
+            else {
+                JavaType argTypeUnboxed = TextAnalyzer.unBox(argType);
+                if (argTypeUnboxed.isIntegralType()) {
+                    valueStack.push(new ValueEntity(TextAnalyzer.unaryNumericPromotion(argTypeUnboxed)));
+                }
+                else {
+                    valueStack.push(new ErrorEntity());
+                }
+            }
+            break;
+        case JavaTokenTypes.INC:
+        case JavaTokenTypes.DEC:
+            // TODO: check that the argument is a variable (an "lvalue")
+            JavaType argTypeUnboxed = TextAnalyzer.unBox(argType);
+            if (argTypeUnboxed.isIntegralType()) {
+                // Note the value has the type of the variable, not the unboxed type
+                valueStack.push(new ValueEntity(argType));
+            }
+            else {
+                valueStack.push(new ErrorEntity());
+            }
+            break;
+        case UNARY_PLUS_OP:
+            doUnaryPlus(varg);
+            break;
+        case UNARY_MINUS_OP:
+            doUnaryMinus(varg);
+            break;
+        }
+    }
+    
+    /**
+     * Cast an integer value to the given integer type, and return the resulting value.
+     * The returned value will be within the range of values representable by the type. 
+     */
+    private long limitResult(JavaType type, long value)
+    {
+        if (type.typeIs(JavaType.JT_BYTE)) {
+            return (byte) value;
+        }
+        else if (type.typeIs(JavaType.JT_CHAR)) {
+            return (char) value;
+        }
+        else if (type.typeIs(JavaType.JT_SHORT)) {
+            return (short) value;
+        }
+        else if (type.typeIs(JavaType.JT_INT)) {
+            return (int) value;
+        }
+        return value;
+    }
+    
+    /**
+     * Promote an integer or float to a float, return the result
+     */
+    private float promoteToFloat(ValueEntity arg1)
+    {
+        if (arg1.hasConstantFloatValue()) {
+            return (float) arg1.getConstantFloatValue();
+        }
+        else {
+            return arg1.getConstantIntValue();
+        }
+    }
+    
+    /**
+     * Promote an integer, float or double to a double, return the result.
+     */
+    private double promoteToDouble(ValueEntity arg1)
+    {
+        if (arg1.hasConstantFloatValue()) {
+            return (float) arg1.getConstantFloatValue();
+        }
+        else {
+            return arg1.getConstantIntValue();
+        }
+    }
+    
+    /**
+     * Process the '+' operator
+     */
+    private void doOpPlus(Operator op, ValueEntity arg1, ValueEntity arg2)
+    {
+        JavaType a1type = arg1.getType();
+        JavaType a2type = arg2.getType();
+        
+        // either the first or second argument might be a String,
+        // in which case the result will be a String also.
+        GenTypeSolid a1solid = a1type.asSolid();
+        GenTypeSolid a2solid = a2type.asSolid();
+        GenTypeClass a1class = null;
+        GenTypeClass a2class = null;
+        
+        // The JLS 3rd edition conflicts with actual compiler behaviour.
+        // JLS says that String concatenation is only the case if the type of
+        // either argument is String. However, if the type is a type parameter
+        // with a bound type of String, the compiler still applies concatenation.
+        if (a1solid != null) {
+            GenTypeClass [] stypes = a1solid.getReferenceSupertypes();
+            if (stypes.length > 0) {
+                a1class = a1solid.getReferenceSupertypes()[0];
+            }
+        }
+        if (a2solid != null) {
+            GenTypeClass [] stypes = a2solid.getReferenceSupertypes();
+            if (stypes.length > 0) {
+                a2class = a2solid.getReferenceSupertypes()[0];
+            }
+        }
+        
+        if (a1class != null && a1class.toString().equals("java.lang.String")) {
+            // TODO concatenation of constant string with a constant should yield a constant string
+            valueStack.push(new ValueEntity(a1class));
+            return;
+        }
+        if (a2class != null && a2class.toString().equals("java.lang.String")) {
+            // TODO concatenation of constant string with a constant should yield a constant string
+            valueStack.push(new ValueEntity(a2class));
+            return;
+        }
+        
+        doBnpOp(op, arg1, arg2);
+    }
+    
+    /**
+     * Process an operator which performs binary numeric promotion and which allows
+     * the result to be a constant expression.
+     */
+    private strictfp void doBnpOp(Operator op, ValueEntity arg1, ValueEntity arg2)
+    {
+        JavaType a1type = arg1.getType();
+        JavaType a2type = arg2.getType();
+        JavaType resultType = TextAnalyzer.binaryNumericPromotion(a1type, a2type);
+        
+        if (resultType == null) {
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        // Handle the case where the arguments are constant. We must do three cases
+        // differently: integral types, "float" type (arguments promoted to "float")
+        // and "double" type (arguments promoted to "double").
+        if ((arg1.hasConstantIntValue() || arg1.hasConstantFloatValue())
+                && (arg2.hasConstantIntValue() || arg2.hasConstantFloatValue())) {
+            if (resultType.isIntegralType()) {
+                long a1 = arg1.getConstantIntValue();
+                long a2 = arg2.getConstantIntValue();
+                long rval;
+                switch (op.type) {
+                case JavaTokenTypes.PLUS:
+                    rval = a1 + a2; break;
+                case JavaTokenTypes.MINUS:
+                    rval = a1 - a2; break;
+                case JavaTokenTypes.STAR:
+                    rval = a1 * a2; break;
+                case JavaTokenTypes.DIV:
+                    if (a2 == 0) {
+                        valueStack.push(new ValueEntity(resultType));
+                        return;
+                    }
+                    rval = a1 / a2; break;
+                case JavaTokenTypes.MOD:
+                    if (a2 == 0) {
+                        valueStack.push(new ValueEntity(resultType));
+                        return;
+                    }
+                    rval = a1 % a2; break;
+                case JavaTokenTypes.BAND:
+                    rval = a1 & a2; break;
+                case JavaTokenTypes.BOR:
+                    rval = a1 | a2; break;
+                case JavaTokenTypes.BXOR:
+                    rval = a1 ^ a2; break;
+                default:
+                    rval = 0; break;
+                }
+                rval = limitResult(resultType, rval);
+                valueStack.push(new ConstantIntValue(null, resultType, rval));
+            }
+            else if (resultType.typeIs(JavaType.JT_FLOAT)) {
+                float a1, a2;
+                a1 = promoteToFloat(arg1);
+                a2 = promoteToFloat(arg2);
+                float rval;
+                switch (op.type) {
+                case JavaTokenTypes.PLUS:
+                    rval = a1 + a2; break;
+                case JavaTokenTypes.MINUS:
+                    rval = a1 - a2; break;
+                case JavaTokenTypes.STAR:
+                    rval = a1 * a2; break;
+                case JavaTokenTypes.DIV:
+                    rval = a1 / a2; break;
+                case JavaTokenTypes.MOD:
+                    rval = a1 % a2; break;
+                case JavaTokenTypes.BAND:
+                case JavaTokenTypes.BOR:
+                case JavaTokenTypes.BXOR:
+                default:
+                    valueStack.push(new ErrorEntity());
+                    return;
+                }
+                valueStack.push(new ConstantFloatValue(resultType, rval));
+            }
+            else {
+                // Result type is double; one argument might still be integer.
+                double a1 = promoteToDouble(arg1);
+                double a2 = promoteToDouble(arg2);
+                double rval;
+                switch (op.type) {
+                case JavaTokenTypes.PLUS:
+                    rval = a1 + a2; break;
+                case JavaTokenTypes.MINUS:
+                    rval = a1 - a2; break;
+                case JavaTokenTypes.STAR:
+                    rval = a1 * a2; break;
+                case JavaTokenTypes.DIV:
+                    rval = a1 / a2; break;
+                case JavaTokenTypes.MOD:
+                    rval = a1 % a2; break;
+                case JavaTokenTypes.BAND:
+                case JavaTokenTypes.BOR:
+                case JavaTokenTypes.BXOR:
+                default:
+                    valueStack.push(new ErrorEntity());
+                    return;
+                }
+                valueStack.push(new ConstantFloatValue(resultType, rval));
+            }
+            return;
+        }
+
+        valueStack.push(new ValueEntity(null, resultType));
+    }
+    
+    /**
+     * Process equality operators '==' and '!='
+     */
+    private void doEqualityOp(Operator op, ValueEntity arg1, ValueEntity arg2)
+    {
+        JavaType a1type = arg1.getType();
+        JavaType a2type = arg2.getType();
+        
+        if (ValueEntity.isConstant(arg1) && ValueEntity.isConstant(arg2)) {
+            if (a1type.isNumeric()) {
+                if (! a2type.isNumeric()) {
+                    valueStack.push(new ErrorEntity());
+                    return;
+                }
+
+                JavaType promotedType = TextAnalyzer.binaryNumericPromotion(a1type, a2type);
+                if (promotedType.isIntegralType()) {
+                    long a1 = arg1.getConstantIntValue();
+                    long a2 = arg2.getConstantIntValue();
+                    boolean rval= (a1 == a2) ^ (op.type != JavaTokenTypes.EQUAL);
+                    valueStack.push(new ConstantBoolValue(rval));
+                }
+                else if (promotedType.typeIs(JavaType.JT_FLOAT)) {
+                    float a1 = promoteToFloat(arg1);
+                    float a2 = promoteToFloat(arg2);
+                    boolean rval= (a1 == a2) ^ (op.type != JavaTokenTypes.EQUAL);
+                    valueStack.push(new ConstantBoolValue(rval));                    
+                }
+                else {
+                    // JT_DOUBLE
+                    double a1 = promoteToDouble(arg1);
+                    double a2 = promoteToDouble(arg2);
+                    boolean rval= (a1 == a2) ^ (op.type != JavaTokenTypes.EQUAL);
+                    valueStack.push(new ConstantBoolValue(rval));                    
+                }
+                return;
+            }
+            
+            // Constants but not numeric...
+            if (arg1.hasConstantBooleanValue() && arg2.hasConstantBooleanValue()) {
+                boolean a1 = arg1.getConstantBooleanValue();
+                boolean a2 = arg2.getConstantBooleanValue();
+                boolean rval = op.type == JavaTokenTypes.EQUAL ? a1 == a2 : a1 != a2;
+                valueStack.push(new ConstantBoolValue(rval));
+                return;
+            }
+            
+            if (arg1.isConstantString() && arg2.isConstantString()) {
+                String a1 = arg1.getConstantString();
+                String a2 = arg2.getConstantString();
+                boolean rval = (op.type != JavaTokenTypes.EQUAL) ^ a1.equals(a2);
+                valueStack.push(new ConstantBoolValue(rval));
+                return;
+            }
+            
+            valueStack.push(new ErrorEntity());
+        }
+        
+        if (a1type.isNumeric() || a2type.isNumeric()) {
+            // Note we only perform binary numeric promotion if one of the arguments
+            // is already (primitive) numeric, as per the JLS 3rd ed.
+            JavaType promotedType = TextAnalyzer.binaryNumericPromotion(a1type, a2type);
+            if (promotedType == null) {
+                valueStack.push(new ErrorEntity());
+            }
+            else {
+                valueStack.push(new ValueEntity("", JavaPrimitiveType.getBoolean()));
+            }
+        }
+        else if (a1type.isNull() && a2type.isNull()
+                || a1type.isNull() && a2type.asSolid() != null
+                || a1type.asSolid() != null && a2type.isNull()) {
+            // Null compared to itself, or to a reference type
+            valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
+        }
+        else if (a1type.asSolid() != null && a2type.asSolid() != null) {
+            // Reference comparison
+            // TODO identify comparisons which are invalid due to divergent
+            // inheritance hierarchies
+            valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
+        }
+        else {
+            valueStack.push(new ErrorEntity());
+        }
+    }
+    
+    /**
+     * Process a relationship operator - '&lt;', '&gt;', '&lt;=', '&gt;='
+     */
+    private void doRelationshipOp(Operator op, ValueEntity arg1, ValueEntity arg2)
+    {
+        JavaType a1type = arg1.getType();
+        JavaType a2type = arg2.getType();
+        
+        JavaType promotedType = TextAnalyzer.binaryNumericPromotion(a1type, a2type);
+        if (promotedType == null) {
+            valueStack.push(new ErrorEntity());
+        }
+        else {
+            if (ValueEntity.isConstant(arg1) && ValueEntity.isConstant(arg2)) {
+                if (promotedType.isIntegralType()) {
+                    long a1 = arg1.getConstantIntValue();
+                    long a2 = arg2.getConstantIntValue();
+                    boolean rval;
+                    
+                    switch (op.type) {
+                    case JavaTokenTypes.LT:
+                        rval = a1 < a2; break;
+                    case JavaTokenTypes.LE:
+                        rval = a1 <= a2; break;
+                    case JavaTokenTypes.GT:
+                        rval = a1 > a2; break;
+                    default:
+                    // case JavaTokenTypes.GE:
+                        rval = a1 >= a2;
+                    }
+                    
+                    valueStack.push(new ConstantBoolValue(rval));
+                }
+                else if (promotedType.typeIs(JavaType.JT_FLOAT)) {
+                    float a1 = promoteToFloat(arg1);
+                    float a2 = promoteToFloat(arg2);
+                    boolean rval;
+                    
+                    switch (op.type) {
+                    case JavaTokenTypes.LT:
+                        rval = a1 < a2; break;
+                    case JavaTokenTypes.LE:
+                        rval = a1 <= a2; break;
+                    case JavaTokenTypes.GT:
+                        rval = a1 > a2; break;
+                    default:
+                    // case JavaTokenTypes.GE:
+                        rval = a1 >= a2;
+                    }
+                    
+                    valueStack.push(new ConstantBoolValue(rval));
+                }
+                else { // JT_DOUBLE
+                    double a1 = promoteToDouble(arg1);
+                    double a2 = promoteToDouble(arg2);
+                    boolean rval;
+                    
+                    switch (op.type) {
+                    case JavaTokenTypes.LT:
+                        rval = a1 < a2; break;
+                    case JavaTokenTypes.LE:
+                        rval = a1 <= a2; break;
+                    case JavaTokenTypes.GT:
+                        rval = a1 > a2; break;
+                    default:
+                    // case JavaTokenTypes.GE:
+                        rval = a1 >= a2;
+                    }
+                    
+                    valueStack.push(new ConstantBoolValue(rval));
+                }
+                return;
+            }
+            
+            valueStack.push(new ValueEntity("", JavaPrimitiveType.getBoolean()));
+        }
+    }
+    
+    /**
+     * Do a bitwise operation - '&amp;', '|' or '^'
+     */
+    private void doBitwiseOp(Operator op, ValueEntity arg1, ValueEntity arg2)
+    {
+        JavaType a1type = arg1.getType();
+        if (a1type.typeIs(JavaType.JT_BOOLEAN)
+                || a1type.toString().equals("java.lang.Boolean")) {
+            JavaType a2type = arg2.getType();
+            if (a2type.typeIs(JavaType.JT_BOOLEAN)
+                    || a2type.toString().equals("java.lang.Boolean")) {
+                // Both arguments are (convertible to) boolean
+                if (arg1.hasConstantBooleanValue() && arg2.hasConstantBooleanValue()) {
+                    boolean a1 = arg1.getConstantBooleanValue();
+                    boolean a2 = arg2.getConstantBooleanValue();
+                    boolean rval;
+                    switch (op.type) {
+                    case JavaTokenTypes.BAND:
+                        rval = a1 & a2;
+                    case JavaTokenTypes.BOR:
+                        rval = a1 | a2;
+                    default:
+                        // JavaTokenTypes.BXOR:
+                        rval = a1 ^ a2;
+                    }
+                    valueStack.push(new ConstantBoolValue(rval));
+                }
+                else {
+                    valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
+                }
+                return;
+            }
+        }
+        
+        doBnpOp(op, arg1, arg2);
+    }
+    
+    /**
+     * Do a logical operation - '&amp;&amp;' or '||'
+     * @param op
+     * @param arg1
+     * @param arg2
+     */
+    private void doLogicalOp(Operator op, ValueEntity arg1, ValueEntity arg2)
+    {
+        JavaType a1type = arg1.getType();
+        if (a1type.typeIs(JavaType.JT_BOOLEAN)
+                || a1type.toString().equals("java.lang.Boolean")) {
+            JavaType a2type = arg2.getType();
+            if (a2type.typeIs(JavaType.JT_BOOLEAN)
+                    || a2type.toString().equals("java.lang.Boolean")) {
+                // Both arguments are (convertible to) boolean
+                if (arg1.hasConstantBooleanValue() && arg2.hasConstantBooleanValue()) {
+                    boolean a1 = arg1.getConstantBooleanValue();
+                    boolean a2 = arg2.getConstantBooleanValue();
+                    boolean rval;
+                    switch (op.type) {
+                    case JavaTokenTypes.LAND:
+                        rval = a1 && a2;
+                    default:
+                        // JavaTokenTypes.LOR:
+                        rval = a1 || a2;
+                    }
+                    valueStack.push(new ConstantBoolValue(rval));
+                }
+                else {
+                    valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
+                }
+                return;
+            }
+        }
+        
+        valueStack.push(new ErrorEntity());
+    }
+    
+    /**
+     * Process a binary operator. Arguments have been resolved as values.
+     * The result is pushed back onto the value stack.
+     */
+    private void doBinaryOp(JavaEntity uarg1, JavaEntity uarg2, Operator op)
+    {
+        // Check that arguments resolve to values
+        ValueEntity arg1 = uarg1.resolveAsValue();
+        ValueEntity arg2 = uarg2.resolveAsValue();
+        if (arg1 == null || arg2 == null) {
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        JavaType a1type = arg1.getType().getCapture();
+        
+        int ttype = op.getType();
+        switch (ttype) {
+        case JavaTokenTypes.PLUS:
+            doOpPlus(op, arg1, arg2);
+            return;
+        case JavaTokenTypes.MINUS:
+        case JavaTokenTypes.STAR:
+        case JavaTokenTypes.DIV:
+        case JavaTokenTypes.MOD:
+            doBnpOp(op, arg1, arg2);
+            break;
+        case JavaTokenTypes.BAND:
+        case JavaTokenTypes.BOR:
+        case JavaTokenTypes.BXOR:
+            doBitwiseOp(op, arg1, arg2);
+            break;
+        case JavaTokenTypes.LOR:
+        case JavaTokenTypes.LAND:
+            doLogicalOp(op, arg1, arg2);
+            break;
+        case JavaTokenTypes.SL:
+        case JavaTokenTypes.SR:
+        case JavaTokenTypes.BSR:
+            JavaType a1typeP = TextAnalyzer.unaryNumericPromotion(a1type);
+            JavaType a2typeP = TextAnalyzer.unaryNumericPromotion(a1type);
+            if (a1typeP == null || a2typeP == null || !a1typeP.isIntegralType()
+                    || ! a2typeP.isIntegralType()) {
+                valueStack.push(new ErrorEntity());
+            }
+            else {
+                // The result type is the type of the LHS
+                // See JLS 3rd ed 15.19
+                if (arg1.hasConstantIntValue() && arg2.hasConstantIntValue()) {
+                    long a1 = arg1.getConstantIntValue();
+                    long a2 = arg2.getConstantIntValue();
+                    long rval;
+                    if (ttype == JavaTokenTypes.SL) {
+                        rval = a1 << a2;
+                    }
+                    else if (ttype == JavaTokenTypes.SR) {
+                        rval = a1 >> a2;
+                    }
+                    else {
+                        // ttype == JavaTokenTypes.BSR
+                        rval = a1 >>> a2;
+                    }
+                    rval = limitResult(a1typeP, rval);
+                    valueStack.push(new ConstantIntValue(null, a1typeP, rval));
+                }
+                else {
+                    valueStack.push(new ValueEntity("", a1typeP));
+                }
+            }
+            break;
+        case JavaTokenTypes.LT:
+        case JavaTokenTypes.LE:
+        case JavaTokenTypes.GT:
+        case JavaTokenTypes.GE:
+            doRelationshipOp(op, arg1, arg2);
+            break;
+        case JavaTokenTypes.EQUAL:
+        case JavaTokenTypes.NOT_EQUAL:
+            doEqualityOp(op, arg1, arg2);
+            break;
+        case JavaTokenTypes.ASSIGN:
+        case JavaTokenTypes.BAND_ASSIGN:
+        case JavaTokenTypes.BOR_ASSIGN:
+        case JavaTokenTypes.PLUS_ASSIGN:
+        case JavaTokenTypes.MINUS_ASSIGN:
+        case JavaTokenTypes.STAR_ASSIGN:
+        case JavaTokenTypes.DIV_ASSIGN:
+        case JavaTokenTypes.SL_ASSIGN:
+        case JavaTokenTypes.SR_ASSIGN:
+        case JavaTokenTypes.BSR_ASSIGN:
+        case JavaTokenTypes.MOD_ASSIGN:
+        case JavaTokenTypes.BXOR_ASSIGN:
+            // TODO check valid assignment
+            valueStack.push(arg1);
+            break;
+        case JavaTokenTypes.DOT:
+            // This is handled elsewhere
+            valueStack.push(new ErrorEntity());
+        default:
+        }
+    }
+    
+    private void processQuestionOperator()
+    {
+        // JLS 15.25
+        JavaEntity rhs = popValueStack();
+        JavaEntity lhs = popValueStack();
+        JavaEntity condition = popValueStack();
+        
+        ValueEntity conditionv = condition.resolveAsValue();
+        if (conditionv == null) {
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        JavaType ctype = conditionv.getType();
+        if (!ctype.typeIs(JavaType.JT_BOOLEAN) && !ctype.toString().equals("java.lang.Boolean")) {
+            // Condition is not a boolean
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        ValueEntity rhsv = rhs.resolveAsValue();
+        ValueEntity lhsv = lhs.resolveAsValue();
+        if (rhsv == null || lhsv == null) {
+            valueStack.push(new ErrorEntity());
+            return;
+        }
+        
+        ValueEntity rent = TextAnalyzer.questionOperator15(conditionv, lhsv, rhsv);
+        valueStack.push(rent);
+    }
+    
+    @Override
+    protected void beginExpression(LocatableToken token)
+    {
+        operatorStack.push(new Operator(PAREN_OPERATOR, token));
+    }
+    
+    @Override
+    protected void endExpression(LocatableToken token, boolean isEmpty)
+    {
+        // An "empty" expression hasn't yet generated a value:
+        if (isEmpty) {
+            valueStack.push(new ErrorEntity());
+        }
+        
+        // This should leave the expression value on top of the value stack:
+        processHigherPrecedence(getPrecedence(PAREN_OPERATOR));
+        operatorStack.pop(); // pop expression beginning operator
+        
+        if (!operatorStack.isEmpty()) {
+            if (operatorStack.peek().type == JavaTokenTypes.LCURLY) {
+                // The value generated by this expression can be discarded:
+                popValueStack();
+            }
+        }
+    }
+    
+    private void gotStringLiteral(LocatableToken token)
+    {
+        String ctext = token.getText();
+        StringBuffer sb = new StringBuffer(ctext.length());
+        for (int pos = 1; pos < ctext.length(); pos++) {
+            char c = ctext.charAt(pos); // just after "'"
+            if (c == '\"') {
+                break; // end of string
+            }
+            if (c == '\\') {
+                c = ctext.charAt(2);
+                if (c == 'b') {
+                    c = '\b';
+                }
+                else if (c == 't') {
+                    c = '\t';
+                }
+                else if (c == 'n') {
+                    c = '\n';
+                }
+                else if (c == 'f') {
+                    c = '\f';
+                }
+                else if (c == 'r') {
+                    c = '\r';
+                }
+                else if (c == '\'') {
+                    c = '\'';
+                }
+                else if (c == '\"') {
+                    c = '\"';
+                }
+                else if (c == '\\') {
+                    c = '\\';
+                }
+                else if (c >= '0' && c <= '7') {
+                    // Octal escape
+                    int val = c - '0';
+                    while (++pos < ctext.length()) {
+                        char d = ctext.charAt(pos);
+                        if (d == '\'') break;
+                        if (d < '0' || d > '7') {
+                            valueStack.push(new ErrorEntity());
+                            return;
+                        }
+                        val = val * 8 + (d - '0');
+                        if (val > 0377) {
+                            valueStack.push(new ErrorEntity());
+                            return;
+                        }
+                    }
+                    c = (char) val;
+                }
+                else {
+                    valueStack.push(new ErrorEntity());
+                    return;
+                }
+            }
+            sb.append(c);
+        }
+        JavaType stringType = new GenTypeClass(new JavaReflective(String.class));
+        ValueEntity ent = new ConstantStringEntity(stringType, sb.toString());
+        valueStack.push(ent);
+    }
+    
+    @Override
+    protected void gotLiteral(LocatableToken token)
+    {
+        if (token.getType() == JavaTokenTypes.CHAR_LITERAL) {
+            String ctext = token.getText();
+            char c = ctext.charAt(1); // just after "'"
+            if (c == '\\') {
+                c = ctext.charAt(2);
+                if (c == 'b') {
+                    c = '\b';
+                }
+                else if (c == 't') {
+                    c = '\t';
+                }
+                else if (c == 'n') {
+                    c = '\n';
+                }
+                else if (c == 'f') {
+                    c = '\f';
+                }
+                else if (c == 'r') {
+                    c = '\r';
+                }
+                else if (c == '\'') {
+                    c = '\'';
+                }
+                else if (c == '\"') {
+                    c = '\"';
+                }
+                else if (c == '\\') {
+                    c = '\\';
+                }
+                else if (c >= '0' && c <= '7') {
+                    // Octal escape
+                    int val = c - '0';
+                    int pos = 3;
+                    while (pos < ctext.length()) {
+                        char d = ctext.charAt(pos++);
+                        if (d == '\'') break;
+                        if (d < '0' || d > '7') {
+                            valueStack.push(new ErrorEntity());
+                            return;
+                        }
+                        val = val * 8 + (d - '0');
+                        if (val > 0377) {
+                            valueStack.push(new ErrorEntity());
+                            return;
+                        }
+                    }
+                    c = (char) val;
+                }
+                else {
+                    valueStack.push(new ErrorEntity());
+                    return;
+                }
+            }
+            valueStack.push(new ConstantIntValue(null, JavaPrimitiveType.getChar(), c));
+        }
+        else if (token.getType() == JavaTokenTypes.NUM_INT) {
+            try {
+                valueStack.push(new ConstantIntValue(null, JavaPrimitiveType.getInt(), Integer.decode(token.getText())));
+            }
+            catch (NumberFormatException nfe) {
+                valueStack.push(new ErrorEntity());
+            }
+        }
+        else if (token.getType() == JavaTokenTypes.NUM_LONG) {
+            try {
+                String text = token.getText();
+                text = text.substring(0, text.length() - 1); // remove 'l' or 'L' suffix
+                valueStack.push(new ConstantIntValue(null, JavaPrimitiveType.getLong(), Long.decode(text)));
+            }
+            catch (NumberFormatException nfe) {
+                valueStack.push(new ErrorEntity());
+            }
+        }
+        else if (token.getType() == JavaTokenTypes.NUM_FLOAT) {
+            try {
+                valueStack.push(new ConstantFloatValue(JavaPrimitiveType.getFloat(), Float.parseFloat(token.getText())));
+            }
+            catch (NumberFormatException nfe) {
+                valueStack.push(new ErrorEntity());
+            }
+        }
+        else if (token.getType() == JavaTokenTypes.NUM_DOUBLE) {
+            try {
+                valueStack.push(new ConstantFloatValue(JavaPrimitiveType.getDouble(), Double.parseDouble(token.getText())));
+            }
+            catch (NumberFormatException nfe) {
+                valueStack.push(new ErrorEntity());
+            }
+        }
+        else if (token.getType() == JavaTokenTypes.LITERAL_null) {
+            valueStack.push(new NullEntity());
+        }
+        else if (token.getType() == JavaTokenTypes.STRING_LITERAL) {
+            gotStringLiteral(token);
+        }
+        else if (token.getType() == JavaTokenTypes.LITERAL_true
+                || token.getType() == JavaTokenTypes.LITERAL_false) {
+            valueStack.push(new ConstantBoolValue(token.getType() == JavaTokenTypes.LITERAL_true));
+        }
+        else if (token.getType() == JavaTokenTypes.LITERAL_this) {
+            if (staticAccess) {
+                valueStack.push(new ErrorEntity());
+            }
+            else {
+                JavaType type = accessType.getType();
+                if (type != null) {
+                    valueStack.push(new ValueEntity(type));
+                }
+                else {
+                    valueStack.push(new ErrorEntity());
+                }
+            }
+        }
+        else {
+            // TODO handle LITERAL_super
+            valueStack.push(new ErrorEntity());
+        }
+    }
+    
+    @Override
+    protected void gotIdentifier(LocatableToken token)
+    {
+        String ident = token.getText();
+        Reflective accessSource = getAccessSource();
+        valueStack.push(UnresolvedEntity.getEntity(resolver, ident, accessSource));
+        arrayCount = 0;
+    }
+    
+    /**
+     * Get the access type as a reflective.
+     */
+    private Reflective getAccessSource()
+    {
+        if (accessType != null) {
+            GenTypeClass accessClass = accessType.getType().asClass();
+            if (accessClass != null) {
+                return accessClass.getReflective();
+            }
+        }
+        return null;
+    }
+    
+    @Override
+    protected void gotMemberAccess(LocatableToken token)
+    {
+        String ident = token.getText();
+        JavaEntity top = valueStack.pop();
+        
+        // handle array "length" member
+        if (token.getText().equals("length")) {
+            JavaEntity topVal = top.resolveAsValue();
+            if (topVal != null) {
+                if (topVal.getType().getArrayComponent() != null) {
+                    // This is an array
+                    valueStack.push(new ValueEntity(JavaPrimitiveType.getInt()));
+                    return;
+                }
+            }
+        }
+        
+        JavaEntity newTop = top.getSubentity(ident, getAccessSource());
+        if (newTop != null) {
+            valueStack.push(newTop);
+        }
+        else {
+            valueStack.push(new ErrorEntity());
+        }
+    }
+    
+    @Override
+    protected void gotMemberCall(LocatableToken token, List<LocatableToken> typeArgs)
+    {
+        operatorStack.push(new Operator(MEMBER_CALL_OP, token));
+        typeArgStack.push(typeArgs);
+    }
+    
+    @Override
+    protected void gotMethodCall(LocatableToken token)
+    {
+        operatorStack.push(new Operator(METHOD_CALL_OP, token));
+    }
+    
+    @Override
+    protected void gotConstructorCall(LocatableToken token)
+    {
+        operatorStack.push(new Operator(METHOD_CALL_OP, token));
+    }
+    
+    @Override
+    protected void gotUnaryOperator(LocatableToken token)
+    {
+        int ttype = token.getType();
+        if (ttype == JavaTokenTypes.PLUS) {
+            ttype = UNARY_PLUS_OP;
+        }
+        else if (ttype == JavaTokenTypes.MINUS) {
+            ttype = UNARY_MINUS_OP;
+        }
+        processHigherPrecedence(getPrecedence(ttype)); // right associative
+        operatorStack.push(new Operator(ttype, token));
+    }
+    
+    @Override
+    protected void gotBinaryOperator(LocatableToken token)
+    {
+        processHigherPrecedence(getPrecedence(token.getType()) - 1);
+        operatorStack.push(new Operator(token.getType(), token));
+    }
+    
+    @Override
+    protected void gotInstanceOfOperator(LocatableToken token)
+    {
+        processHigherPrecedence(getPrecedence(token.getType()) - 1);
+        operatorStack.push(new Operator(token.getType(), token));
+        state = STATE_INSTANCEOF;
+    }
+    
+    @Override
+    protected void gotQuestionOperator(LocatableToken token)
+    {
+        processHigherPrecedence(getPrecedence(token.getType()) - 1);
+        operatorStack.push(new Operator(token.getType(), token));
+    }
+    
+    @Override
+    protected void gotTypeSpec(List<LocatableToken> tokens)
+    {
+        if (state == STATE_NEW) {
+            JavaEntity entity = resolveTypeSpec(tokens);
+            state = STATE_NEW_ARGS;
+            
+            if (entity != null) {
+                valueStack.push(new ValueEntity(entity.getType().getCapture()));
+            }
+            else {
+                valueStack.push(new ErrorEntity());
+            }
+        }
+        else if (state == STATE_INSTANCEOF) {
+            TypeEntity entity = resolveTypeSpec(tokens);
+            if (entity != null) {
+                // TODO: check validity of instanceof check
+                popValueStack();
+                valueStack.push(new ValueEntity(JavaPrimitiveType.getBoolean()));
+            }
+            else {
+                popValueStack();
+                valueStack.push(new ErrorEntity());
+            }
+        }
+    }
+    
+    @Override
+    protected void gotTypeCast(List<LocatableToken> tokens)
+    {
+        JavaEntity entity = resolveTypeSpec(tokens);
+        
+        if (entity != null) {
+            valueStack.push(entity);
+            operatorStack.push(new Operator(CAST_OPERATOR, null));
+        }
+        else {
+            operatorStack.push(new Operator(BAD_CAST_OPERATOR, null));
+        }
+    }
+    
+    @Override
+    protected void gotArrayDeclarator()
+    {
+        arrayCount++;
+    }
+    
+    @Override
+    protected void gotNewArrayDeclarator(boolean withDimension)
+    {
+        if (state != STATE_NONE) {
+            state = STATE_NONE; // Don't expect constructor arguments!
+            operatorStack.pop(); // remove new operator from stack
+        }
+        
+        if (withDimension) {
+            valueStack.pop(); // pull the dimension off the value stack
+        }
+        
+        JavaEntity top = valueStack.pop();
+        JavaEntity ttop = top.resolveAsValue();
+        if (ttop != null) {
+            valueStack.push(new ValueEntity(ttop.getType().getArray()));
+        }
+        else {
+            valueStack.push(new ErrorEntity());
+        }
+    }
+    
+    @Override
+    protected void gotPrimitiveTypeLiteral(LocatableToken token)
+    {
+        List<LocatableToken> ltokens = new ArrayList<LocatableToken>(1);
+        ltokens.add(token);
+        TypeEntity tent = resolveTypeSpec(ltokens);
+        valueStack.push(tent);
+        arrayCount = 0;
+    }
+    
+    @Override
+    protected void gotClassLiteral(LocatableToken token)
+    {
+        JavaEntity ent = popValueStack();
+        TypeEntity tent = ent.resolveAsType();
+        if (tent != null) {
+            JavaType ttype = tent.getType();
+            if (arrayCount > 0) {
+                while (arrayCount-- > 0) {
+                    ttype = ttype.getArray();
+                }
+                tent = new TypeEntity(ttype);
+            }
+            if (! ttype.isPrimitive()) {
+                TypeEntity jlcEnt = resolver.resolveQualifiedClass("java.lang.Class");
+                if (jlcEnt != null) {
+                    List<TypeArgumentEntity> targs = new ArrayList<TypeArgumentEntity>(1);
+                    targs.add(new SolidTargEntity(tent));
+                    jlcEnt = jlcEnt.setTypeArgs(targs);
+                    if (jlcEnt != null) {
+                        valueStack.push(new ValueEntity(jlcEnt.getType()));
+                        return;
+                    }
+                }
+            }
+            else {
+                String repClass = null;
+                if (ttype.typeIs(JavaType.JT_BOOLEAN)) {
+                    repClass = "java.lang.Boolean";
+                }
+                else if (ttype.typeIs(JavaType.JT_BYTE)) {
+                    repClass = "java.lang.Byte";
+                }
+                else if (ttype.typeIs(JavaType.JT_CHAR)) {
+                    repClass = "java.lang.Char";
+                }
+                else if (ttype.typeIs(JavaType.JT_DOUBLE)) {
+                    repClass = "java.lang.Double";
+                }
+                else if (ttype.typeIs(JavaType.JT_FLOAT)) {
+                    repClass = "java.lang.Float";
+                }
+                else if (ttype.typeIs(JavaType.JT_INT)) {
+                    repClass = "java.lang.Integer";
+                }
+                else if (ttype.typeIs(JavaType.JT_LONG)) {
+                    repClass = "java.lang.Long";
+                }
+                else if (ttype.typeIs(JavaType.JT_VOID)) {
+                    repClass = "java.lang.Void";
+                }
+                if (repClass != null) {
+                    TypeEntity jlcEnt = resolver.resolveQualifiedClass("java.lang.Class");
+                    TypeEntity repEnt = resolver.resolveQualifiedClass(repClass);
+                    if (jlcEnt != null && repEnt != null) {
+                        List<TypeArgumentEntity> targs = new ArrayList<TypeArgumentEntity>(1);
+                        targs.add(new SolidTargEntity(repEnt));
+                        jlcEnt = jlcEnt.setTypeArgs(targs);
+                        if (jlcEnt != null) {
+                            valueStack.push(new ValueEntity(jlcEnt.getType()));
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+
+        valueStack.push(new ErrorEntity());
+    }
+    
+    private class DepthRef
+    {
+        int depth = 0;
+    }
+    
+    /**
+     * Resolve a type specification. Returns null if the type couldn't be resolved.
+     */
+    private TypeEntity resolveTypeSpec(List<LocatableToken> tokens)
+    {
+        DepthRef dr = new DepthRef();
+        return resolveTypeSpec(tokens.listIterator(), dr);
+    }
+    
+    /**
+     * Resolve a type specification. Returns null if the type couldn't be resolved.
+     */
+    private TypeEntity resolveTypeSpec(ListIterator<LocatableToken> i, DepthRef depthRef)
+    {
+        LocatableToken token = i.next();
+        
+        if (isPrimitiveType(token)) {
+            if (token.getType() == JavaTokenTypes.LITERAL_void) {
+                return new TypeEntity(JavaPrimitiveType.getVoid());
+            }
+            
+            JavaType type = null;
+            switch (token.getType()) {
+            case JavaTokenTypes.LITERAL_int:
+                type = JavaPrimitiveType.getInt();
+                break;
+            case JavaTokenTypes.LITERAL_short:
+                type = JavaPrimitiveType.getShort();
+                break;
+            case JavaTokenTypes.LITERAL_char:
+                type = JavaPrimitiveType.getChar();
+                break;
+            case JavaTokenTypes.LITERAL_byte:
+                type = JavaPrimitiveType.getByte();
+                break;
+            case JavaTokenTypes.LITERAL_boolean:
+                type = JavaPrimitiveType.getBoolean();
+                break;
+            case JavaTokenTypes.LITERAL_long:
+                type = JavaPrimitiveType.getLong();
+                break;
+            case JavaTokenTypes.LITERAL_double:
+                type = JavaPrimitiveType.getDouble();
+                break;
+            case JavaTokenTypes.LITERAL_float:
+                type = JavaPrimitiveType.getFloat();
+            }
+            
+            while (i.hasNext()) {
+                token = i.next();
+                if (token.getType() == JavaTokenTypes.LBRACK) {
+                    type = type.getArray();
+                    i.next();  // RBRACK
+                }
+                else {
+                    return null;
+                }
+            }
+            
+            return new TypeEntity(type);
+        }
+
+        String text = token.getText();
+        PackageOrClass poc = resolver.resolvePackageOrClass(text, getAccessSource());
+        while (poc != null && i.hasNext()) {
+            token = i.next();
+            if (token.getType() == JavaTokenTypes.LT) {
+                // Type arguments
+                TypeEntity classEnt = poc.resolveAsType();
+                if (classEnt != null) {
+                    classEnt = processTypeArgs(classEnt, i, depthRef);
+                }
+                poc = classEnt;
+                if (poc == null) {
+                    return null;
+                }
+                if (! i.hasNext()) {
+                    return classEnt;
+                }
+                token = i.next();
+            }
+            if (token.getType() != JavaTokenTypes.DOT) {
+                poc = poc.resolveAsType();
+                if (poc == null) {
+                    return null;
+                }
+                
+                while (token.getType() == JavaTokenTypes.LBRACK) {
+                    poc = new TypeEntity(poc.getType().getCapture().getArray());
+                    if (i.hasNext()) {
+                        token = i.next(); // RBRACK
+                    }
+                    if (! i.hasNext()) {
+                        return poc.resolveAsType();
+                    }
+                    token = i.next();
+                }
+                
+                i.previous(); // allow token to be re-read by caller
+                return poc.resolveAsType();
+            }
+            token = i.next();            
+            if (token.getType() != JavaTokenTypes.IDENT) {
+                break;
+            }
+            poc = poc.getPackageOrClassMember(token.getText());
+        }
+                
+        if (poc != null) {
+            return poc.resolveAsType();
+        }
+        else {
+            return null;
+        }
+    }
+    
+    /**
+     * Process tokens as type arguments
+     * @param base  The base type, i.e. the type to which the arguments are applied
+     * @param i     A ListIterator to iterate through the tokens
+     * @param depthRef  The argument depth
+     * @return   A ClassEntity representing the type with type arguments applied (or null)
+     */
+    private TypeEntity processTypeArgs(TypeEntity base, ListIterator<LocatableToken> i, DepthRef depthRef)
+    {
+        List<TypeArgumentEntity> taList = readTypeArguments(i, depthRef);
+        if (taList == null) {
+            return null;
+        }
+        
+        // TODO check the type arguments are actually valid
+        return base.setTypeArgs(taList);
+    }
+    
+    /**
+     * Read a list of type arguments (the opening angle-bracket has already been read) from a list of tokens.
+     * Returns null if there is an error.
+     */
+    private List<TypeArgumentEntity> readTypeArguments(ListIterator<LocatableToken> i, DepthRef depthRef)
+    {
+        int startDepth = depthRef.depth;
+        List<TypeArgumentEntity> taList = new LinkedList<TypeArgumentEntity>();
+        depthRef.depth++; // initial '<' already skipped
+        
+        mainLoop:
+        while (i.hasNext() && depthRef.depth > startDepth) {
+            LocatableToken token = i.next();
+            if (token.getType() == JavaTokenTypes.QUESTION) {
+                if (! i.hasNext()) {
+                    return null;
+                }
+                token = i.next();
+                if (token.getType() == JavaTokenTypes.LITERAL_super) {
+                    TypeEntity taEnt = resolveTypeSpec(i, depthRef);
+                    if (taEnt == null) {
+                        return null;
+                    }
+                    taList.add(new WildcardSuperEntity(taEnt));
+                }
+                else if (token.getType() == JavaTokenTypes.LITERAL_extends) {
+                    TypeEntity taEnt = resolveTypeSpec(i, depthRef);
+                    if (taEnt == null) {
+                        return null;
+                    }
+                    taList.add(new WildcardExtendsEntity(taEnt));
+                }
+                else {
+                    taList.add(new UnboundedWildcardEntity(resolver));
+                    i.previous();
+                }
+            }
+            else {
+                i.previous();
+                TypeEntity taEnt = resolveTypeSpec(i, depthRef);
+                if (taEnt == null) {
+                    return null;
+                }
+                JavaType taType = taEnt.getType();
+                if (taType.isPrimitive()) {
+                    return null;
+                }
+                taList.add(new SolidTargEntity(new TypeEntity(taType)));
+            }
+
+            if (! i.hasNext()) {
+                return null;
+            }
+            token = i.next();
+            int ttype = token.getType();
+            while (ttype == JavaTokenTypes.GT || ttype == JavaTokenTypes.SR || ttype == JavaTokenTypes.BSR) {
+                switch (ttype) {
+                case JavaTokenTypes.BSR:
+                    depthRef.depth--;
+                case JavaTokenTypes.SR:
+                    depthRef.depth--;
+                default:
+                    depthRef.depth--;
+                }
+                if (! i.hasNext()) {
+                    break mainLoop;
+                }
+                token = i.next();
+                ttype = token.getType();
+            }
+
+            if (ttype != JavaTokenTypes.COMMA) {
+                i.previous();
+                break;
+            }
+        }
+        
+        return taList;
+    }
+    
+    @Override
+    protected void beginArgumentList(LocatableToken token)
+    {
+        state = STATE_NONE;
+        argumentStack.push(new ArrayList<JavaEntity>());
+    }
+    
+    @Override
+    protected void endArgument()
+    {
+        // Each argument is an expression delimited by beginExpression()/
+        // endExpression(), so it should leave just a single value on the
+        // stack.
+        if (! valueStack.isEmpty()) {
+            argumentStack.peek().add(valueStack.pop());
+        }
+    }
+    
+    @Override
+    protected void endArgumentList(LocatableToken token)
+    {
+        if (! operatorStack.isEmpty()) {
+            Operator top = operatorStack.pop();
+            if (top.getType() == JavaTokenTypes.LITERAL_new) {
+                processNewOperator(top);
+            }
+            else if (top.getType() == MEMBER_CALL_OP) {
+                processMemberCall(top);
+            }
+            else if (top.getType() == METHOD_CALL_OP) {
+                processMethodCall(top);
+            }
+            else {
+                // ??!!
+                argumentStack.pop();
+            }
+        }
+    }
+    
+    @Override
+    protected void gotExprNew(LocatableToken token)
+    {
+        state = STATE_NEW;
+        operatorStack.push(new Operator(token.getType(), token));
+    }
+    
+    @Override
+    protected void endExprNew(LocatableToken token, boolean included)
+    {
+        if (state != STATE_NONE) {
+            if (state == STATE_NEW_ARGS) {
+                // We got a type spec: remove it
+                popValueStack();
+            }
+            operatorStack.pop(); // Remove "new" operator from stack
+            valueStack.push(new ErrorEntity());
+            state = STATE_NONE;
+        }
+    }
+    
+    @Override
+    protected void beginAnonClassBody(LocatableToken token, boolean isEnumMember)
+    {
+        operatorStack.push(new Operator(token.getType(), token));
+    }
+    
+    @Override
+    protected void beginArrayInitList(LocatableToken token)
+    {
+        operatorStack.push(new Operator(token.getType(), token));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/TokenStream.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/TokenStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2a871ee4d7ff93342dfc9da34c55b358c30c0da
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/TokenStream.java
@@ -0,0 +1,14 @@
+package bluej.parser;
+
+import bluej.parser.lexer.LocatableToken;
+
+
+/**
+ * A token stream - a stream of tokens. This replaces the TokenStream from Antlr.
+ * 
+ * @author Davin McCall
+ */
+public interface TokenStream
+{
+    public LocatableToken nextToken();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/UnitTestAnalyzer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/UnitTestAnalyzer.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bd5254dcca09762bb7867093effde56247fad03
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/UnitTestAnalyzer.java
@@ -0,0 +1,114 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.io.Reader;
+import java.util.*;
+
+//import bluej.parser.ast.*;
+//import bluej.parser.ast.gen.*;
+
+/**
+ * @author Andrew
+ *
+ * To change the template for this generated type comment go to
+ * Window - Preferences - Java - Code Generation - Code and Comments
+ */
+public class UnitTestAnalyzer
+{
+    UnitTestParser utp;
+    
+    /**
+     * Analyse unit test source code.
+     */
+    public UnitTestAnalyzer(Reader r)
+    {
+        utp = new UnitTestParser(r);
+    }
+
+    /**
+     * Extract from the unit testing source the list of source spans
+     * for the fields declared in the unit test class.
+     * 
+     * ie
+     *
+     * class FooBar {
+     *    private int a = 10;
+     *    java.util.HashMap h,i,j = null;
+     *    public String aString;
+     * }
+     * gives us a list with SourceSpan objects encompassing
+     *   p in private to ;
+     *   j in java to ;
+     *   p in public to ;
+     *
+     * The list will be ordered in the order that the fields appear in the src.
+     */
+    public List<SourceSpan> getFieldSpans()
+    {
+        return utp.getFieldSpans();
+    }
+
+    /**
+     * Extract from the unit testing source
+     * the opening and closing bracket locations for the method 'methodName'.
+     * We select only methods that do not have any parameters (all unit test
+     * methods take no arguments).
+     * ie
+     *
+     * class FooBar {
+     *    public void setUp() {
+     *       // do something
+     *       i++;
+     *    }
+     * }
+     * gives us a SourceSpan object from the second "{" to the first "}"
+     */
+    public SourceSpan getMethodBlockSpan(String methodName)
+    {
+        return utp.getMethodBlockSpan(methodName);
+    }
+
+    /**
+     * Extract from the unit test source a source location where
+     * we should insert declarations of fields (that will become
+     * the classes fixtures).
+     * 
+     * @return
+     */
+    public SourceLocation getFixtureInsertLocation()
+    {
+        return utp.getFixtureInsertLocation();
+    }
+
+    /**
+     * Extract from the unit test source a source location where
+     * we can insert new methods.
+     * 
+     * @return
+     */
+    public SourceLocation getNewMethodInsertLocation()
+    {
+        return utp.getNewMethodInsertLocation();
+    }
+  
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/UnitTestParser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/UnitTestParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..79429da1069b489cad51c03a5fe85f97788eece6
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/UnitTestParser.java
@@ -0,0 +1,191 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser;
+
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+
+/**
+ * A parser which extracts certain information needed for BlueJ's unit test
+ * (junit) functionality.
+ * 
+ * @author Davin McCall
+ */
+public class UnitTestParser extends JavaParser
+{
+    private int classLevel = 0; // level of class nesting
+    private boolean inMethod = false; // are we in an interesting method
+    private String methodName;
+    private LocatableToken methodBegin;
+    private boolean isPublic = false;
+    private boolean haveClassInfo = false;
+    
+    private List<SourceSpan> fieldSpans = new LinkedList<SourceSpan>();
+    private SourceLocation methodInsertLocation;
+    private SourceLocation fixtureInsertLocation;
+    private Map<String,SourceSpan> methodSpans = new HashMap<String,SourceSpan>();
+    
+    private Stack<SourceLocation> fieldStarts = new Stack<SourceLocation>();
+    
+    public UnitTestParser(Reader r)
+    {
+        super(r);
+        try {
+            parseCU();
+        }
+        catch (Exception e) {
+        }
+    }
+    
+    public List<SourceSpan> getFieldSpans()
+    {
+        return fieldSpans;
+    }
+    
+    public SourceLocation getNewMethodInsertLocation()
+    {
+        return methodInsertLocation;
+    }
+    
+    public SourceLocation getFixtureInsertLocation()
+    {
+        return fixtureInsertLocation;
+    }
+    
+    public SourceSpan getMethodBlockSpan(String name)
+    {
+        return methodSpans.get(name);
+    }
+    
+    @Override
+    protected void error(String msg, int beginLine, int beginColumn, int endLine, int endColumn)
+    {
+        throw new RuntimeException("Parse error: " + msg);
+    }
+        
+    @Override
+    protected void gotModifier(LocatableToken token)
+    {
+        if (token.getType() == JavaTokenTypes.LITERAL_public) {
+            isPublic = true;
+        }
+    }
+    
+    @Override
+    protected void modifiersConsumed()
+    {
+        isPublic = false;
+    }
+    
+    @Override
+    protected void gotField(LocatableToken first, LocatableToken idToken)
+    {
+        if (classLevel == 1 && !haveClassInfo) {
+            fieldStarts.push(new SourceLocation(first.getLine(), first.getColumn()));
+        }
+    }
+    
+    @Override
+    protected void endFieldDeclarations(LocatableToken token, boolean included)
+    {
+        if (classLevel == 1 && !haveClassInfo) {
+            SourceLocation start = fieldStarts.pop();
+            SourceLocation end = new SourceLocation(token.getEndLine(), token.getEndColumn());
+            SourceSpan ss = new SourceSpan(start, end);
+            fieldSpans.add(ss);
+        }
+    }
+    
+    @Override
+    protected void gotTypeDef(LocatableToken firstToken, int tdType)
+    {
+        classLevel++;
+        if (haveClassInfo && isPublic) {
+            // A public class overrides a non-public class
+            haveClassInfo = false;
+            fieldSpans = new LinkedList<SourceSpan>();
+            methodSpans = new HashMap<String,SourceSpan>();
+        }
+    }
+    
+    @Override
+    protected void beginTypeBody(LocatableToken leftCurlyToken)
+    {
+        if (classLevel == 1) {
+            fixtureInsertLocation = new SourceLocation(leftCurlyToken.getLine(),
+                    leftCurlyToken.getColumn());
+        }
+    }
+    
+    @Override
+    protected void gotTypeDefEnd(LocatableToken token, boolean included)
+    {
+        classLevel--;
+        endElement(token, included);
+        if (classLevel == 0) {
+            haveClassInfo = true;
+            methodInsertLocation = new SourceLocation(token.getLine(), token.getColumn());
+        }
+    }
+    
+    @Override
+    protected void gotMethodDeclaration(LocatableToken token,
+            LocatableToken hiddenToken)
+    {
+        if (classLevel == 1 && ! haveClassInfo) {
+            inMethod = true;
+            methodName = token.getText();
+        }
+    }
+    
+    @Override
+    protected void gotMethodParameter(LocatableToken token, LocatableToken ellipsisToken)
+    {
+        inMethod = false; // we're not interested in methods with parameters
+    }
+    
+    @Override
+    protected void beginMethodBody(LocatableToken token)
+    {
+        if (inMethod) {
+            methodBegin = token;
+        }
+    }
+    
+    @Override
+    protected void endMethodBody(LocatableToken token, boolean included)
+    {
+        if (classLevel == 1 && !haveClassInfo && methodBegin != null) {
+            SourceLocation start = new SourceLocation(methodBegin.getLine(), methodBegin.getColumn());
+            SourceLocation end = new SourceLocation(token.getEndLine(), token.getEndColumn());
+            SourceSpan ss = new SourceSpan(start, end);
+            methodSpans.put(methodName, ss);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ClassLoaderResolver.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ClassLoaderResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..7dab21a01bf77f2c7629693d9c8a03ef17ea5c23
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ClassLoaderResolver.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * An entity resolver which resolves classes using a ClassLoader.
+ * 
+ * @author Davin McCall
+ */
+public class ClassLoaderResolver implements EntityResolver
+{
+    private ClassLoader classLoader;
+    
+    public ClassLoaderResolver(ClassLoader classLoader)
+    {
+        this.classLoader = classLoader;
+    }
+    
+    public TypeEntity resolveQualifiedClass(String name)
+    {
+        try {
+            // Try as a fully-qualified name 
+            Class<?> cl = classLoader.loadClass(name);
+            return new TypeEntity(cl);
+        }
+        catch (Exception e) {}
+        
+        return null;
+    }
+    
+    public PackageOrClass resolvePackageOrClass(String name, Reflective querySource)
+    {
+        // Have to assume it's a package
+        return new PackageEntity(name, this);
+    }
+    
+    public JavaEntity getValueEntity(String name, Reflective querySource)
+    {
+        return resolvePackageOrClass(name, querySource);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantBoolValue.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantBoolValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..9126e406d15affb01fa6107d1ee09c1a45c5d62e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantBoolValue.java
@@ -0,0 +1,52 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.JavaPrimitiveType;
+
+/**
+ * A value entity with a compile-time constant boolean value
+ * 
+ * @author Davin McCall
+ */
+public class ConstantBoolValue extends ValueEntity
+{
+    private boolean value;
+    
+    public ConstantBoolValue(boolean value)
+    {
+        super(JavaPrimitiveType.getBoolean());
+        this.value = value;
+    }
+    
+    @Override
+    public boolean hasConstantBooleanValue()
+    {
+        return true;
+    }
+    
+    @Override
+    public boolean getConstantBooleanValue()
+    {
+        return value;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantFloatValue.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantFloatValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..e31d6f5361be5792895185de83ca0307484da0e0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantFloatValue.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.JavaType;
+
+/**
+ * Represents a value entity with a known (constant) floating point value (single or double precision).
+ * 
+ * @author Davin McCall
+ */
+public class ConstantFloatValue extends ValueEntity
+{
+    private double value;
+    
+    /**
+     * Construct a floating-point constant value entity
+     * @param valueType  The type of the value (float or double)
+     * @param value      The known value
+     */
+    public ConstantFloatValue(JavaType valueType, double value)
+    {
+        super(valueType);
+        this.value = value;
+    }
+    
+    @Override
+    public boolean hasConstantFloatValue()
+    {
+        return true;
+    }
+    
+    @Override
+    public double getConstantFloatValue()
+    {
+        return value;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantIntValue.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantIntValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..a68612ac99c1f53e55e6b886ca5eb2f0392fe1f7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantIntValue.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.JavaType;
+
+/**
+ * Represents a value entity with a known (constant) integer value.
+ * 
+ * @author Davin McCall
+ */
+public class ConstantIntValue extends ValueEntity
+{
+    private long value;
+    
+    /**
+     * Construct a constant integer value entity.
+     * @param name   The entity name (may be null)
+     * @param type   The entity type (should be a primitive integer type)
+     * @param value  The value represented
+     */
+    public ConstantIntValue(String name, JavaType type, long value)
+    {
+        super(name, type);
+        this.value = value;
+    }
+    
+    @Override
+    public boolean hasConstantIntValue()
+    {
+        return true;
+    }
+    
+    @Override
+    public long getConstantIntValue()
+    {
+        return value;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantStringEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantStringEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..b401da74cc35de15bfef22baed9578cdd6d82db2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ConstantStringEntity.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.JavaType;
+
+/**
+ * An entity to represent a constant string value.
+ * 
+ * @author Davin McCall
+ */
+public class ConstantStringEntity extends ValueEntity
+{
+    private String value;
+    
+    /**
+     * Construct a constant string entity
+     * @param stringType  A representation of the "java.lang.String" type
+     * @param value       The string value
+     */
+    public ConstantStringEntity(JavaType stringType, String value)
+    {
+        super(stringType);
+        this.value = value.intern();
+    }
+    
+    @Override
+    public boolean isConstantString()
+    {
+        return true;
+    }
+    
+    @Override
+    public String getConstantString()
+    {
+        return value;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/EntityResolver.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/EntityResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c17e1c4b42987b95fcd3edf2b258969bca416c2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/EntityResolver.java
@@ -0,0 +1,63 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * An EntityResolver, broadly speaking, resolves identifiers into packages, classes,
+ * fields and variables. A resolver can be specific to a context; for instance a
+ * resolver inside a package normally sees classes in that package without requiring
+ * qualification. 
+ * 
+ * @author Davin McCall
+ */
+public interface EntityResolver
+{
+    /**
+     * Resolve a package or class. If a class with the given name exists in the resolver's scope,
+     * it is returned; otherwise a package is returned.
+     * 
+     * @param name  The package or class name. This must be an unqualified name.
+     * @param querySource  The source of the query (a fully qualified class name,
+     *            as would be returned by Class.getName()).
+     */
+    public PackageOrClass resolvePackageOrClass(String name, Reflective querySource);
+    
+    /**
+     * Resolve a class from its fully-qualified name. The supplied name should
+     * be the same as would be returned by Class.getName() for the required type.
+     */
+    public TypeEntity resolveQualifiedClass(String name);
+    
+    /**
+     * Resolve a value. If a local variable or field with the given name exists in the resolver's
+     * scope (or if there is a static import of that name), it is returned; otherwise the effect is as if resolvePackageOrClass was called.
+     * 
+     * <p>To resolve the final value entity, call resolveAsValue() on the returned entity.
+     * 
+     * @param name The name of the entity to access
+     * @param querySource The source of the query (a fully qualified class name,
+     *            as would be returned by Class.getName()).
+     */
+    public JavaEntity getValueEntity(String name, Reflective querySource);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ErrorEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ErrorEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..3963d3c655b80ae2647ee82eaa37fb0ec70bec89
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ErrorEntity.java
@@ -0,0 +1,60 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.List;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * An entity representing an erroneous expression in a Java program. This is sometimes
+ * more convenient than returning null.
+ * 
+ * @author Davin McCall
+ */
+public class ErrorEntity extends JavaEntity
+{
+    @Override
+    public String getName()
+    {
+        return "** error **";
+    }
+    
+    @Override
+    public JavaEntity getSubentity(String name, Reflective accessSource)
+    {
+        return this;
+    }
+    
+    @Override
+    public JavaType getType()
+    {
+        return null;
+    }
+    
+    @Override
+    public JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        return this;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ImportedEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ImportedEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..3fad43dfc1b3c5c5a9f3966359b853154176dc18
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ImportedEntity.java
@@ -0,0 +1,118 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * Represents an unresolved sequence of names from an import statement, which should
+ * when resolved refer to a class or (for wildcard imports) a package.
+ * 
+ * @author Davin McCall
+ */
+public class ImportedEntity extends JavaEntity
+{
+    private EntityResolver resolver;
+    private List<String> names;
+    private Reflective querySource;
+    
+    /**
+     * Create an ImportEntity with the given attributes.
+     */
+    public ImportedEntity(EntityResolver resolver, List<String> names,
+            Reflective querySource)
+    {
+        this.resolver = resolver;
+        this.names = names;
+        this.querySource = querySource;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return names.get(names.size() - 1);
+    }
+
+    @Override
+    public JavaEntity getSubentity(String name, Reflective accessSource)
+    {
+        List<String> newNames = new LinkedList<String>();
+        newNames.addAll(names);
+        newNames.add(name);
+        return new ImportedEntity(resolver, newNames, querySource);
+    }
+
+    @Override
+    public JavaType getType()
+    {
+        return null;
+    }
+    
+    @Override
+    public JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        return null;
+    }
+
+    @Override
+    public ValueEntity resolveAsValue()
+    {
+        return null;
+    }
+    
+    @Override
+    public TypeEntity resolveAsType()
+    {
+        PackageOrClass poc = resolveAsPackageOrClass();
+        if (poc != null) {
+            return poc.resolveAsType();
+        }
+        
+        return null;
+    }
+    
+    @Override
+    public PackageOrClass resolveAsPackageOrClass()
+    {
+        Iterator<String> i = names.iterator();
+        if (! i.hasNext()) {
+            return null;
+        }
+        
+        String fqName = i.next();
+        PackageOrClass poc = new PackageEntity(fqName, resolver);
+        
+        while (i.hasNext()) {
+            poc = poc.getPackageOrClassMember(i.next());
+            if (poc == null) {
+                return null;
+            }
+        }
+        
+        return poc;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/IntersectionTypeEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/IntersectionTypeEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..5303852db6af15f4a41f1a265c2d8448c7b33150
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/IntersectionTypeEntity.java
@@ -0,0 +1,114 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.Iterator;
+import java.util.List;
+
+import bluej.debugger.gentype.GenTypeSolid;
+import bluej.debugger.gentype.IntersectionType;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * An entity representing intersection types (such as the bounds for type parameters).
+ * 
+ * @author Davin McCall
+ */
+public class IntersectionTypeEntity extends JavaEntity
+{
+    private List<JavaEntity> types;
+    
+    /**
+     * Get an entity representing an intersection of the given types. If there are no types,
+     * this yields a "java.lang.Object" entity. If there is only one type, this returns that
+     * type.
+     */
+    public static JavaEntity getIntersectionEntity(List<JavaEntity> types, EntityResolver resolver)
+    {
+        if (types.size() == 0) {
+            return resolver.resolveQualifiedClass("java.lang.Object");
+        }
+        if (types.size() == 1) {
+            return types.get(0);
+        }
+        return new IntersectionTypeEntity(types);
+    }
+    
+    private IntersectionTypeEntity(List<JavaEntity> types)
+    {
+        this.types = types;
+    }
+    
+    @Override
+    public String getName()
+    {
+        Iterator<JavaEntity> i = types.iterator();
+        String name = i.next().getName();
+        for ( ; i.hasNext(); ) {
+            name += "&" + i.next().getName();
+        }
+        return name;
+    }
+    
+    @Override
+    public JavaEntity getSubentity(String name, Reflective accessSource)
+    {
+        return null;
+    }
+    
+    @Override
+    public JavaType getType()
+    {
+        GenTypeSolid [] components = new GenTypeSolid[types.size()];
+        int index = 0;
+        for (JavaEntity type : types) {
+            TypeEntity tent = type.resolveAsType();
+            if (tent == null) {
+                return null;
+            }
+            components[index] = tent.getType().asSolid();
+            if (components[index++] == null) {
+                // Not a "solid" type.
+                return null;
+            }
+        }
+        
+        return IntersectionType.getIntersection(components);
+    }
+    
+    @Override
+    public JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        return null;
+    }
+    
+    @Override
+    public TypeEntity resolveAsType()
+    {
+        JavaType type = getType();
+        if (type == null) {
+            return null;
+        }
+        return new TypeEntity(type);
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/JavaEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/JavaEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f3cee76197b4fef72609e57e43afea5647a82d7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/JavaEntity.java
@@ -0,0 +1,116 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.List;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * A general abstraction for handling entities which may have fields or
+ * members - including packages, classes, and values.
+ * 
+ * <p>Entities can be unresolved, meaning that they represent an expression such
+ * as "xyz.abc" where "xyz" could be a package, class or local member.
+ * 
+ * @author Davin McCall
+ */
+public abstract class JavaEntity
+{
+    /**
+     * If this entity is unresolved, resolve it now as a value.
+     */
+    public ValueEntity resolveAsValue()
+    {
+        return null;
+    }
+    
+    /**
+     * If this entity is unresolved, resolve it now as a type.
+     */
+    public TypeEntity resolveAsType()
+    {
+        return null;
+    }
+    
+    /**
+     * If this entity is unresolved, resolve it now as either a package or a
+     * qualified class.
+     */
+    public PackageOrClass resolveAsPackageOrClass()
+    {
+        return resolveAsType();
+    }
+    
+    /**
+     * Get the type of the entity. For a class entity, this is the class itself
+     * (may be generic). For a value this is the value type.
+     * 
+     * <p>You should always resolve the entity to either a value or type before
+     * calling this method.
+     * 
+     * <p>Returns null if no type is available or undetermined (i.e. if the entity
+     * has not properly been resolved).
+     */ 
+    public abstract JavaType getType();
+    
+    /**
+     * Check whether this entity represents "null". "null" has no type.
+     */
+    public boolean isNullEntity()
+    {
+        return false;
+    }
+    
+    /**
+     * Get a sub-entity (member, field, whatever) by name.
+     * @param name  The name of the subentity
+     * @param accessSource  The source of the access (for access control purposes)
+     * @return  The subentity  (or null if one does not exist)
+     */
+    public abstract JavaEntity getSubentity(String name, Reflective accessSource);
+    
+    /**
+     * Get the name of the entity. This returns the fully-qualified name of the
+     * entity.
+     */
+    public abstract String getName();
+    
+    /**
+     * Check whether this identity represents a single identifier. If it does,
+     * this method returns true and getName() returns the identifier.
+     */
+    public boolean isIdentifier()
+    {
+        return false;
+    }
+    
+    /**
+     * Set the type parameters of this entity. The return is a duplicate of this entity with
+     * the type parameters set as specified. If type parameters cannot be applied to this
+     * entity the return is null.
+     * 
+     * @param tparams   A list of type parameters
+     */
+    public abstract JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/NullEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/NullEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..19bf7ac3f74b008f2bb8cd6ab317014acff9b0dd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/NullEntity.java
@@ -0,0 +1,77 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.List;
+
+import bluej.debugger.gentype.JavaPrimitiveType;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * The "null" entity. This represents the "null" value (literal).
+ * 
+ * @author Davin McCall
+ */
+public class NullEntity extends ValueEntity
+{
+    public NullEntity()
+    {
+        super(JavaPrimitiveType.getNull());
+    }
+    
+    @Override
+    public String getName()
+    {
+        return null;
+    }
+
+    @Override
+    public JavaEntity getSubentity(String name, Reflective accessSource)
+    {
+        return null;
+    }
+
+    @Override
+    public JavaType getType()
+    {
+        return JavaPrimitiveType.getNull();
+    }
+    
+    @Override
+    public boolean isNullEntity()
+    {
+        return true;
+    }
+    
+    @Override
+    public JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        return null;
+    }
+
+    @Override
+    public ValueEntity resolveAsValue()
+    {
+        return this;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PackageEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PackageEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..002cefc401041fc248309c63f31fa316efef68a8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PackageEntity.java
@@ -0,0 +1,80 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.List;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * An entity representing a package. The entity is only presumed to be a package
+ * seeing as no class with the same name could be found.
+ * 
+ * @author Davin McCall
+ */
+public class PackageEntity extends PackageOrClass
+{
+    private String name;
+    private EntityResolver resolver;
+    
+    public PackageEntity(String name, EntityResolver resolver)
+    {
+        this.name = name;
+        this.resolver = resolver;
+    }
+    
+    @Override
+    public PackageOrClass getPackageOrClassMember(String name)
+    {
+        String nname = this.name + "." + name;
+        PackageOrClass rval = resolver.resolveQualifiedClass(nname);
+        if (rval != null) {
+            return rval;
+        }
+        return new PackageEntity(nname, resolver);
+    }
+
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public JavaEntity getSubentity(String name, Reflective accessSource)
+    {
+        return getPackageOrClassMember(name);
+    }
+
+    @Override
+    public JavaType getType()
+    {
+        return null;
+    }
+
+    @Override
+    public JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PackageOrClass.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PackageOrClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ba196db5e4e9712652372d785b2c744cdd25928
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PackageOrClass.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+/**
+ * An entity representing either a package or a class (but not a value).
+ * 
+ * @author Davin McCall
+ */
+public abstract class PackageOrClass extends JavaEntity
+{
+    /**
+     * Returns a subentity which is either a package or class entity.
+     * This is the same as getSubentity, but cannot yield a value.
+     */ 
+    public abstract PackageOrClass getPackageOrClassMember(String name);
+    
+    @Override
+    public PackageOrClass resolveAsPackageOrClass()
+    {
+        return this;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PackageResolver.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PackageResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6fe46cbd86f3c74527c3e5a43e4b5f8dd97e275
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PackageResolver.java
@@ -0,0 +1,76 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.Reflective;
+
+
+/**
+ * A resolver for a package scope level. Classes within the package are found
+ * first; otherwise resolution is delegated to the parent resolver.
+ * 
+ * @author Davin McCall
+ */
+public class PackageResolver implements EntityResolver
+{
+    private EntityResolver parentResolver;
+    private String pkg;
+    
+    public PackageResolver(EntityResolver parentResolver, String pkg)
+    {
+        this.parentResolver = parentResolver;
+        this.pkg = pkg;
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.parser.entity.EntityResolver#getValueEntity(java.lang.String, java.lang.String)
+     */
+    public JavaEntity getValueEntity(String name, Reflective querySource)
+    {
+        return resolvePackageOrClass(name, querySource);
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.parser.entity.EntityResolver#resolvePackageOrClass(java.lang.String, java.lang.String)
+     */
+    public PackageOrClass resolvePackageOrClass(String name, Reflective querySource)
+    {
+        String fqName = (pkg.length() == 0) ? name : pkg + "." + name;
+        TypeEntity tent = parentResolver.resolveQualifiedClass(fqName);
+        if (tent != null) {
+            // TODO check the returned class isn't private
+            return tent;
+        }
+        else {
+            return new PackageEntity(name, this);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.parser.entity.EntityResolver#resolveQualifiedClass(java.lang.String)
+     */
+    public TypeEntity resolveQualifiedClass(String name)
+    {
+        return parentResolver.resolveQualifiedClass(name);
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ParsedArrayReflective.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ParsedArrayReflective.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7defc4fbe6e9955f5bdcb09fa7367f86db123ee
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ParsedArrayReflective.java
@@ -0,0 +1,143 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010,2011  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.debugger.gentype.FieldReflective;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.JavaPrimitiveType;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.MethodReflective;
+import bluej.debugger.gentype.Reflective;
+import bluej.utility.JavaReflective;
+
+public class ParsedArrayReflective extends Reflective
+{
+    private Reflective component;
+    private String className;
+    
+    public ParsedArrayReflective(Reflective component, String componentName)
+    {
+        this.component = component;
+        className = "[" + componentName;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return "[L" + component.getName() + ";";
+    }
+    
+    public String getSimpleName()
+    {
+        return component.getName() + "[]";
+    }
+    
+    @Override
+    public Reflective getArrayOf()
+    {
+        return new ParsedArrayReflective(this, className);
+    }
+    
+    // See JLS section 10.7: arrays have a "public final int length" field
+    @Override
+    public Map<String,FieldReflective> getDeclaredFields()
+    {
+        return Collections.singletonMap("length", new FieldReflective("length", JavaPrimitiveType.getInt(), Modifier.PUBLIC | Modifier.FINAL)); 
+    }
+    
+    // See JLS section 10.7: arrays have a "public Object clone()" method
+    @Override
+    public Map<String, Set<MethodReflective>> getDeclaredMethods()
+    {
+        return Collections.singletonMap("clone", Collections.singleton(new MethodReflective("clone", new GenTypeClass(new JavaReflective(Object.class)), new ArrayList<GenTypeDeclTpar>(), new ArrayList<JavaType>(), this, false, Modifier.PUBLIC)));
+    }
+    
+    @Override
+    public List<Reflective> getInners()
+    {
+        return Collections.emptyList();
+    }
+    
+    @Override
+    public Reflective getRelativeClass(String name)
+    {
+        return component.getRelativeClass(name);
+    }
+    
+    @Override
+    public List<GenTypeClass> getSuperTypes()
+    {
+        List<GenTypeClass> componentSupers = component.getSuperTypes();
+        for (ListIterator<GenTypeClass> i = componentSupers.listIterator(); i.hasNext(); ) {
+            i.set(i.next().getArray());
+        }
+        componentSupers.add(new GenTypeClass(new JavaReflective(Object.class)));
+        return componentSupers;
+    }
+    
+    @Override
+    public List<Reflective> getSuperTypesR()
+    {
+        Reflective obj = new JavaReflective(Object.class);
+        return Collections.singletonList(obj);
+    }
+    
+    @Override
+    public List<GenTypeDeclTpar> getTypeParams()
+    {
+        return Collections.emptyList();
+    }
+    
+    @Override
+    public boolean isAssignableFrom(Reflective r)
+    {
+        // TODO implement this
+        return false;
+    }
+    
+    @Override
+    public boolean isInterface()
+    {
+        return false;
+    }
+    
+    @Override
+    public boolean isPublic()
+    {
+        return component.isPublic();
+    }
+    
+    @Override
+    public boolean isStatic()
+    {
+        return component.isStatic();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ParsedReflective.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ParsedReflective.java
new file mode 100644
index 0000000000000000000000000000000000000000..b041045e6923c33d56e07df6b03891442b1bb911
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ParsedReflective.java
@@ -0,0 +1,308 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.debugger.gentype.FieldReflective;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.MethodReflective;
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.JavaParser;
+import bluej.parser.nodes.FieldNode;
+import bluej.parser.nodes.MethodNode;
+import bluej.parser.nodes.ParsedTypeNode;
+import bluej.parser.nodes.TypeInnerNode;
+import bluej.utility.JavaUtils;
+
+/**
+ * A Reflective implementation for classes which are parsed, but not necessarily compiled.
+ * 
+ * @author Davin McCall
+ */
+public class ParsedReflective extends Reflective
+{
+    private ParsedTypeNode pnode;
+    
+    public ParsedReflective(ParsedTypeNode pnode)
+    {
+        this.pnode = pnode;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return pnode.getPrefix() + pnode.getName();
+    }
+
+    @Override
+    public Reflective getArrayOf()
+    {
+        return new ParsedArrayReflective(this, "L" + getName() + ";");
+    }
+
+    @Override
+    public Reflective getRelativeClass(String name)
+    {
+        TypeEntity tent = pnode.resolveQualifiedClass(name);
+        if (tent != null) {
+            GenTypeClass ctype = tent.getType().asClass();
+            if (ctype != null) {
+                return ctype.getReflective();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public List<GenTypeClass> getSuperTypes()
+    {
+        List<GenTypeClass> rval = new LinkedList<GenTypeClass>();
+        
+        for (JavaEntity etype : pnode.getExtendedTypes()) {
+            TypeEntity tent = etype.resolveAsType();
+            if (tent != null) {
+                GenTypeClass ct = tent.getType().asClass();
+                if (ct != null) {
+                    rval.add(ct);
+                }
+            }
+        }
+        
+        if (! isInterface()) {
+            if (rval.isEmpty()) {
+                // All classes extend Object implicitly
+                TypeEntity tent = pnode.resolveQualifiedClass("java.lang.Object");
+                if (tent != null) {
+                    GenTypeClass ct = tent.getType().asClass();
+                    if (ct != null) {
+                        rval.add(ct);
+                    }
+                }
+            }
+        }
+
+        for (JavaEntity etype : pnode.getImplementedTypes()) {
+            TypeEntity tent = etype.resolveAsType();
+            if (tent != null) {
+                GenTypeClass ct = tent.getType().asClass();
+                if (ct != null) {
+                    rval.add(ct);
+                }
+            }
+        }
+        
+        return rval;
+    }
+
+    @Override
+    public List<Reflective> getSuperTypesR()
+    {
+        List<Reflective> rlist = new ArrayList<Reflective>();
+        List<JavaEntity> extendedTypes = pnode.getExtendedTypes();
+        if (extendedTypes != null && ! extendedTypes.isEmpty()) {
+            for (JavaEntity etype : extendedTypes) {
+                TypeEntity etypeTEnt = etype.resolveAsType();
+                if (etypeTEnt != null) {
+                    GenTypeClass superGTC = etypeTEnt.getType().asClass();
+                    if (superGTC != null) {
+                        rlist.add(superGTC.getReflective());
+                    }
+                }
+            }
+        }
+        
+        if (rlist.isEmpty() && ! isInterface()) {
+            // Object is always a supertype
+            TypeEntity objEntity = pnode.resolveQualifiedClass("java.lang.Object");
+            if (objEntity != null) {
+                GenTypeClass superGTC = objEntity.getType().asClass();
+                if (superGTC != null) {
+                    rlist.add(superGTC.getReflective());
+                }
+            }
+        }
+        
+        extendedTypes = pnode.getImplementedTypes();
+        if (extendedTypes != null && ! extendedTypes.isEmpty()) {
+            for (JavaEntity etype : extendedTypes) {
+                TypeEntity etypeTEnt = etype.resolveAsType();
+                if (etypeTEnt != null) {
+                    GenTypeClass superGTC = etypeTEnt.getType().asClass();
+                    if (superGTC != null) {
+                        rlist.add(superGTC.getReflective());
+                    }
+                }
+            }
+        }
+        
+        return rlist;
+    }
+
+    @Override
+    public List<GenTypeDeclTpar> getTypeParams()
+    {
+        List<TparEntity> tparEntList = pnode.getTypeParams();
+        if (tparEntList == null) {
+            return Collections.emptyList();
+        }
+        
+        List<GenTypeDeclTpar> tparList = new ArrayList<GenTypeDeclTpar>(tparEntList.size());
+        for (TparEntity tpar : tparEntList) {
+            GenTypeDeclTpar tparType = tpar.getType();
+            if (tparType != null) {
+                tparList.add(tparType);
+            }
+        }
+        
+        return tparList;
+    }
+
+    @Override
+    public boolean isAssignableFrom(Reflective r)
+    {
+        Set<String> done = new HashSet<String>();
+        LinkedList<Reflective> todo = new LinkedList<Reflective>();
+        
+        while (r != null) {
+            String rname = r.getName();
+            if (rname.equals(getName())) {
+                return true;
+            }
+            if (done.add(r.getName())) {
+                todo.addAll(r.getSuperTypesR());
+            }
+            r = todo.poll();
+        }
+        
+        return false;
+    }
+
+    @Override
+    public boolean isInterface()
+    {
+        return pnode.getTypeKind() == JavaParser.TYPEDEF_INTERFACE;
+    }
+
+    @Override
+    public boolean isStatic()
+    {
+        return Modifier.isStatic(pnode.getModifiers());
+    }
+    
+    @Override
+    public boolean isPublic()
+    {
+        return Modifier.isPublic(pnode.getModifiers());
+    }
+    
+    @Override
+    public Map<String,FieldReflective> getDeclaredFields()
+    {
+        Map<String,FieldNode> fields = pnode.getInner().getFields();
+        Map<String,FieldReflective> rmap = new HashMap<String,FieldReflective>();
+        for (Iterator<String> i = fields.keySet().iterator(); i.hasNext(); ) {
+            String fieldName = i.next();
+            FieldNode fieldNode = fields.get(fieldName);
+            JavaEntity ftypeEnt = fieldNode.getFieldType().resolveAsType();
+            if (ftypeEnt != null) {
+                FieldReflective fref = new FieldReflective(fieldName, ftypeEnt.getType(),
+                        fieldNode.getModifiers());
+                rmap.put(fieldName, fref);
+            }
+        }
+        return rmap;
+    }
+    
+    @Override
+    public Map<String,Set<MethodReflective>> getDeclaredMethods()
+    {
+        TypeInnerNode pnodeInner = pnode.getInner();
+        if (pnodeInner == null) {
+            return Collections.emptyMap();
+        }
+        
+        Map<String,Set<MethodNode>> methods = pnodeInner.getMethods();
+        Map<String,Set<MethodReflective>> rmap = new HashMap<String,Set<MethodReflective>>();
+        
+        for (Iterator<String> i = methods.keySet().iterator(); i.hasNext(); ) {
+            String name = i.next();
+            Set<MethodNode> mset = methods.get(name);
+            Set<MethodReflective> rset = new HashSet<MethodReflective>();
+            
+            methodLoop:
+            for (Iterator<MethodNode> j = mset.iterator(); j.hasNext(); ) {
+                MethodNode method = j.next();
+                JavaEntity rtypeEnt = method.getReturnType();
+                if (rtypeEnt == null) continue; // constructor
+                rtypeEnt = rtypeEnt.resolveAsType();
+                if (rtypeEnt == null) continue;
+                JavaType rtype = rtypeEnt.getType().getCapture();
+                List<JavaType> paramTypes = new ArrayList<JavaType>();
+                List<JavaEntity> mparamTypes = method.getParamTypes();
+                for (JavaEntity mparam : mparamTypes) {
+                    TypeEntity mtent = mparam.resolveAsType();
+                    if (mtent == null) continue methodLoop;
+                    paramTypes.add(mtent.getType());
+                }
+                List<GenTypeDeclTpar> tparTypes = method.getTypeParams();
+                MethodReflective mref = new MethodReflective(name, rtype, tparTypes,
+                        paramTypes, this, method.isVarArgs(), method.getModifiers());
+                mref.setJavaDoc(JavaUtils.javadocToString(method.getJavadoc()));
+                mref.setParamNames(method.getParamNames());
+                rset.add(mref);
+            }
+            if (! rset.isEmpty()) {
+                rmap.put(name, rset);
+            }
+        }
+        return rmap;
+    }
+    
+    @Override
+    public List<Reflective> getInners()
+    {
+        // TODO fix
+        return Collections.emptyList();
+    }
+    
+    @Override
+    public Reflective getOuterClass()
+    {
+        ParsedTypeNode containing = pnode.getContainingClass();
+        if (containing != null) {
+            return new ParsedReflective(containing);
+        }
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PositionedResolver.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PositionedResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..a44893f2ce30021be209b21d90e22c7d5fc1f07e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/PositionedResolver.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.nodes.JavaParentNode;
+
+/**
+ * An entity resolver which resolves from a JavaParentNode at a particular position.
+ * Used to resolve correctly when the position is important, i.e. forward references are not allowed.
+ * 
+ * @author Davin McCall
+ */
+public class PositionedResolver implements EntityResolver
+{
+    private JavaParentNode parentNode;
+    private int fromPosition;
+    
+    /**
+     * Construct a new PositionedResolver, resolving against the given parent node at the given position.
+     */
+    public PositionedResolver(JavaParentNode parentNode, int fromPosition)
+    {
+        this.parentNode = parentNode;
+        this.fromPosition = fromPosition;
+    }
+    
+    @Override
+    public PackageOrClass resolvePackageOrClass(String name,
+            Reflective querySource)
+    {
+        return parentNode.resolvePackageOrClass(name, querySource, fromPosition);
+    }
+
+    @Override
+    public TypeEntity resolveQualifiedClass(String name)
+    {
+        return parentNode.resolveQualifiedClass(name);
+    }
+
+    @Override
+    public JavaEntity getValueEntity(String name, Reflective querySource)
+    {
+        return parentNode.getValueEntity(name, querySource, fromPosition);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/SolidTargEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/SolidTargEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..abd0b89b391ef5bf964668c973e2b7744748655a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/SolidTargEntity.java
@@ -0,0 +1,28 @@
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.GenTypeParameter;
+
+/**
+ * A TypeArgumentEntity representing a solid (i.e. non-wildcard) type argument.
+ * 
+ * @author Davin McCall
+ */
+public class SolidTargEntity extends TypeArgumentEntity
+{
+    private JavaEntity solid;
+    
+    public SolidTargEntity(JavaEntity solid)
+    {
+        this.solid = solid;
+    }
+    
+    @Override
+    public GenTypeParameter getType()
+    {
+        TypeEntity ce = solid.resolveAsType();
+        if (ce != null) {
+            return ce.getType();
+        }
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/TparEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/TparEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a8562b6b1b51cd28e798d2767c9ab0b4b22e1f7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/TparEntity.java
@@ -0,0 +1,108 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.List;
+
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.GenTypeSolid;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * A JavaEntity subclass for representing type parameters. In particular this avoids
+ * the problems associated with recursive definitions such as:
+ * 
+ * <blockquote>
+ *     <code>class Sort<T extends Comparable<T>> {  }</code></dt>
+ * </blockquote>
+ * 
+ * @author Davin McCall
+ */
+public class TparEntity extends JavaEntity
+{
+    private JavaEntity bounds;
+    private GenTypeDeclTpar tpar;
+    private String name;
+    
+    public TparEntity(String name, JavaEntity bounds)
+    {
+        super();
+        this.name = name;
+        this.tpar = new GenTypeDeclTpar(name);
+        this.bounds = bounds;
+    }
+
+    @Override
+    public GenTypeDeclTpar getType()
+    {
+        if (bounds != null) {
+            JavaEntity boundsCopy = bounds;
+            bounds = null; // prevent infinite recursion
+            
+            TypeEntity tent = boundsCopy.resolveAsType();
+            if (tent != null) {
+                GenTypeSolid boundType = tent.getType().asSolid();
+                if (boundType != null) {
+                    tpar.setBounds(boundType.getUpperBounds());
+                }
+                else {
+                    tpar = null;
+                }
+            }
+            else {
+                tpar = null;
+            }
+        }
+        return tpar;
+    }
+    
+    @Override
+    public TypeEntity resolveAsType()
+    {
+        JavaType myType = getType();
+        if (myType != null) {
+            return new TypeEntity(myType);
+        }
+        else {
+            return null;
+        }
+    }
+    
+    @Override
+    public JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        return null;
+    }
+    
+    @Override
+    public JavaEntity getSubentity(String name, Reflective accessSource)
+    {
+        return null;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/TypeArgumentEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/TypeArgumentEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e900ccaf5e99a6973a33211890101a452c25f30
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/TypeArgumentEntity.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.GenTypeParameter;
+
+/**
+ * A base type for representing type arguments as they occur in a source program.
+ * 
+ * <p>This type does not extend JavaEntity, as it is more specialised.
+ * 
+ * @author Davin McCall
+ */
+public abstract class TypeArgumentEntity
+{
+    /**
+     * Get the type parameter. This requires resolving the bound if not already done,
+     * and so may return null if the bound is not a valid type.
+     */
+    public abstract GenTypeParameter getType();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/TypeEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/TypeEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..1498865a70db7fdaf13c2dbe89f887d8e1c2539c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/TypeEntity.java
@@ -0,0 +1,185 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import bluej.debugger.gentype.FieldReflective;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+import bluej.utility.JavaReflective;
+import bluej.utility.JavaUtils;
+
+/**
+ * An entity which essentially wraps a JavaType.
+ * 
+ * @author Davin McCall
+ */
+public class TypeEntity extends PackageOrClass
+{
+    private JavaType thisType;
+    
+    public TypeEntity(JavaType type)
+    {
+        thisType = type;
+    }
+    
+    public TypeEntity(Reflective ref)
+    {
+        //thisRef = ref;
+        thisType = new GenTypeClass(ref);
+    }
+    
+    public TypeEntity(Class<?> c)
+    {
+        Reflective thisRef = new JavaReflective(c);
+        thisType = new GenTypeClass(thisRef);
+    }
+    
+    TypeEntity(Reflective r, GenTypeClass outer)
+    {
+        // thisRef = r;
+        thisType = new GenTypeClass(r, Collections.<GenTypeParameter>emptyList(), outer);
+    }
+
+    public JavaType getType()
+    {
+        return thisType;
+    }
+    
+    public GenTypeClass getClassType()
+    {
+        return thisType.getCapture().asClass();
+    }
+    
+    public JavaEntity getSubentity(String name, Reflective accessor)
+    {
+        GenTypeClass thisClass = thisType.getCapture().asClass();
+        if (thisClass == null) {
+            return null;
+        }
+        else if (thisClass.getArrayComponent() != null) {
+            // Arrays have no static fields/subtypes
+            return null;
+        }
+        
+        // subentity of a class could be a member type or field
+        // Is it a field?
+        
+        LinkedList<Reflective> stypes = new LinkedList<Reflective>();
+        Reflective ctypeRef = thisClass.getReflective();
+        stypes.add(ctypeRef);
+        
+        while (! stypes.isEmpty()) {
+            ctypeRef = stypes.poll();
+            Map<String,FieldReflective> m = ctypeRef.getDeclaredFields();
+            FieldReflective field = m.get(name);
+            if (field != null) {
+                boolean accessAllowed = JavaUtils.checkMemberAccess(ctypeRef,
+                        thisClass, accessor, field.getModifiers(), true);
+                if (accessAllowed) {
+                    thisClass = thisClass.mapToSuper(ctypeRef.getName());
+                    JavaType fieldType = field.getType().mapTparsToTypes(thisClass.getMap()).getUpperBound();
+                    return new ValueEntity(name, fieldType);
+                }
+            }
+            stypes.addAll(ctypeRef.getSuperTypesR());
+        }
+
+        // Is it a member type?
+        return getPackageOrClassMember(name);
+    }
+    
+    public TypeEntity getPackageOrClassMember(String name)
+    {
+        GenTypeClass thisClass = thisType.getCapture().asClass();
+        if (thisClass == null || thisClass.getArrayComponent() != null) {
+            return null;
+        }
+
+        LinkedList<Reflective> stypes = new LinkedList<Reflective>();
+        stypes.add(thisClass.getReflective());
+        
+        while (! stypes.isEmpty()) {
+            Reflective thisRef = stypes.poll();
+            Reflective member = thisRef.getRelativeClass(thisRef.getName() + '$' + name);
+            if (member != null) {
+                // TODO check access
+                //boolean accessAllowed = JavaUtils.checkMemberAccess(thisRef,
+                //        thisClass, accessor, member.getModifiers(), true);
+                GenTypeClass inner = new GenTypeClass(member,
+                    Collections.<GenTypeParameter>emptyList(), thisClass);
+                return new TypeEntity(inner);
+            }
+            stypes.addAll(thisRef.getSuperTypesR());
+        }
+        
+        Reflective thisRef = thisClass.getReflective();
+        if (thisRef != null) {
+            Reflective member = thisRef.getRelativeClass(thisRef.getName() + '$' + name);
+            if (member != null) {
+                GenTypeClass inner = new GenTypeClass(member,
+                    Collections.<GenTypeParameter>emptyList(), thisClass);
+                return new TypeEntity(inner);
+            }
+        }
+        
+        return null;
+    }
+    
+    public String getName()
+    {
+        return getType().toString();
+    }
+    
+    /*
+     * @see bluej.parser.entity.ClassEntity#setTypeParams(java.util.List)
+     */
+    public TypeEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        GenTypeClass classType = thisType.getCapture().asClass();
+        if (classType == null) {
+            return null;
+        }
+        GenTypeClass outer = classType.getOuterType();
+        List<GenTypeParameter> ttparams = new LinkedList<GenTypeParameter>();
+        for (TypeArgumentEntity eparam : tparams) {
+            GenTypeParameter tparamType = eparam.getType();
+            if (tparamType == null) {
+                return null;
+            }
+            ttparams.add(tparamType);
+        }
+        
+        return new TypeEntity(new GenTypeClass(classType.getReflective(), ttparams, outer));
+    }
+    
+    @Override
+    public TypeEntity resolveAsType()
+    {
+        return this;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnboundedWildcardEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnboundedWildcardEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5cd199ca83bba3bb6261d3fdb4777af288315ed
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnboundedWildcardEntity.java
@@ -0,0 +1,49 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.GenTypeUnbounded;
+
+/**
+ * A TypeArgumentEntity for representing unbounded wildcards ("?").
+ * 
+ * @author Davin McCall
+ */
+public class UnboundedWildcardEntity extends TypeArgumentEntity
+{
+    private GenTypeClass objClass;
+    
+    public UnboundedWildcardEntity(EntityResolver resolver)
+    {
+        TypeEntity objEntity = resolver.resolveQualifiedClass("java.lang.Object");
+        if (objEntity != null) {
+            objClass = objEntity.getClassType();
+        }
+    }
+    
+    @Override
+    public GenTypeParameter getType()
+    {
+        return new GenTypeUnbounded(objClass);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnresolvedArray.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnresolvedArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..0568ecef5a67552074822b14d851b313d9c4daf0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnresolvedArray.java
@@ -0,0 +1,77 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.List;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * An array entity, where the element type hasn't yet been resolved.
+ * 
+ * @author Davin McCall
+ */
+public class UnresolvedArray extends JavaEntity
+{
+    private JavaEntity baseType;
+    
+    public UnresolvedArray(JavaEntity baseType)
+    {
+        this.baseType = baseType;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return null;
+    }
+
+    @Override
+    public JavaEntity getSubentity(String name, Reflective accessSource)
+    {
+        return null;
+    }
+
+    @Override
+    public JavaType getType()
+    {
+        return null;
+    }
+
+    @Override
+    public JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        return null;
+    }
+    
+    @Override
+    public TypeEntity resolveAsType()
+    {
+        TypeEntity bt = baseType.resolveAsType();
+        if (bt != null) {
+            return new TypeEntity(bt.getType().getArray());
+        }
+        return null;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnresolvedEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnresolvedEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..54ed7c61e30a1f6f3b00afa23edcf3ff6ade95b3
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnresolvedEntity.java
@@ -0,0 +1,127 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.List;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * Represents a java entity whose nature (value or type) is not yet known,
+ * and provides a static method (getEntity) to obtain instances.
+ * 
+ * @author Davin McCall
+ */
+public class UnresolvedEntity extends JavaEntity
+{
+    private EntityResolver resolver;
+    private String name;
+    private List<TypeArgumentEntity> typeArguments;
+    private Reflective querySource;
+    
+    /**
+     * Get an entity whose type (value or class) is not yet known. The returned entity
+     * can later be resolved to either a value or type.
+     */
+    public static JavaEntity getEntity(EntityResolver resolver, String name, Reflective querySource)
+    {
+        return new UnresolvedEntity(resolver, name, querySource, null);
+    }
+    
+    protected UnresolvedEntity(EntityResolver resolver, String name, Reflective querySource,
+            List<TypeArgumentEntity> typeArgs)
+    {
+        this.resolver = resolver;
+        this.name = name;
+        this.querySource = querySource;
+        this.typeArguments = typeArgs;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public JavaEntity getSubentity(String name, Reflective accessSource)
+    {
+        return new UnresolvedSubEntity(this, name, accessSource);
+    }
+
+    @Override
+    public JavaType getType()
+    {
+        return null;
+    }
+    
+    @Override
+    public JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        return new UnresolvedEntity(resolver, name, querySource, tparams);
+    }
+
+    @Override
+    public ValueEntity resolveAsValue()
+    {
+        if (typeArguments != null) {
+            return null;
+        }
+        
+        JavaEntity entity = resolver.getValueEntity(name, querySource);
+        if (entity != null) {
+            return entity.resolveAsValue();
+        }
+        return null;
+    }
+    
+    @Override
+    public TypeEntity resolveAsType()
+    {
+        PackageOrClass entity = resolver.resolvePackageOrClass(name, querySource);
+        if (entity != null) {
+            TypeEntity tentity = entity.resolveAsType();
+            if (tentity != null) {
+                if (typeArguments != null) {
+                    return tentity.setTypeArgs(typeArguments);
+                }
+                return tentity;
+            }
+        }
+        return null;
+    }
+    
+    @Override
+    public PackageOrClass resolveAsPackageOrClass()
+    {
+        PackageOrClass ent = resolver.resolvePackageOrClass(name, querySource);
+        if (typeArguments != null) {
+            TypeEntity tent = ent.resolveAsType();
+            if (tent != null) {
+                return tent.setTypeArgs(typeArguments);
+            }
+            return null;
+        }
+        return ent;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnresolvedSubEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnresolvedSubEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..7599870c996a4bb579b2a7cd06feaed484a6ad34
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/UnresolvedSubEntity.java
@@ -0,0 +1,153 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.List;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * An unresolved subentity (an entity of form xxx.yyy, where yyy is the subentity name).
+ * 
+ * @author Davin McCall
+ */
+public class UnresolvedSubEntity extends JavaEntity
+{
+    private JavaEntity parent;
+    private String name;
+    private Reflective accessSource;
+    private List<TypeArgumentEntity> typeArgs;
+    
+    /**
+     * Construct a new unresolved sub entity.
+     * @param parent   The parent entity
+     * @param name     The subentity name
+     * @param accessSource  The access source (used for access control)
+     */
+    public UnresolvedSubEntity(JavaEntity parent, String name, Reflective accessSource)
+    {
+        this.parent = parent;
+        this.name = name;
+        this.accessSource = accessSource;
+    }
+    
+    @Override
+    public JavaType getType()
+    {
+        return null;
+    }
+
+    @Override
+    public JavaEntity getSubentity(String name, Reflective accessSource)
+    {
+        return new UnresolvedSubEntity(this, name, accessSource);
+    }
+
+    @Override
+    public String getName()
+    {
+        return parent.getName() + "." + name;
+    }
+
+    @Override
+    public JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        UnresolvedSubEntity newEnt = new UnresolvedSubEntity(parent, name, accessSource);
+        newEnt.typeArgs = tparams;
+        return newEnt;
+    }
+    
+    @Override
+    public ValueEntity resolveAsValue()
+    {
+        if (typeArgs != null) {
+            // A value can't have type arguments.
+            return null;
+        }
+        
+        JavaEntity pent = parent.resolveAsValue();
+        if (pent == null) {
+            pent = parent.resolveAsType();
+        }
+        
+        if (pent == null) {
+            return null;
+        }
+        
+        JavaEntity subEnt = pent.getSubentity(name, accessSource);
+        if (subEnt == null) {
+            return null;
+        }
+        
+        return subEnt.resolveAsValue();
+    }
+    
+    @Override
+    public TypeEntity resolveAsType()
+    {
+        PackageOrClass pent = parent.resolveAsPackageOrClass();
+        if (pent == null) {
+            return null;
+        }
+        
+        JavaEntity subEnt = pent.getPackageOrClassMember(name);
+        if (subEnt == null) {
+            return null;
+        }
+        
+        TypeEntity tentity = subEnt.resolveAsType();
+        if (tentity != null && typeArgs != null) {
+            tentity = tentity.setTypeArgs(typeArgs);
+        }
+        
+        return tentity;
+    }
+    
+    @Override
+    public PackageOrClass resolveAsPackageOrClass()
+    {
+        if (typeArgs != null) {
+            return resolveAsType();
+        }
+        
+        PackageOrClass pent = parent.resolveAsPackageOrClass();
+        if (pent == null) {
+            return null;
+        }
+        
+        JavaEntity subEnt = pent.getPackageOrClassMember(name);
+        if (subEnt == null) {
+            return null;
+        }
+        
+        PackageOrClass pocEnt = subEnt.resolveAsPackageOrClass();
+        if (pocEnt != null && typeArgs != null) {
+            TypeEntity tent = pocEnt.resolveAsType();
+            if (tent != null) {
+                return tent.setTypeArgs(typeArgs);
+            }
+            return null;
+        }
+        return pocEnt;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ValueEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ValueEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..7bce366e35a11649ba59b1eb37af49dc8ba7da61
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/ValueEntity.java
@@ -0,0 +1,210 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import bluej.debugger.gentype.FieldReflective;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.GenTypeSolid;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+import bluej.utility.JavaUtils;
+
+/**
+ * Represents a value entity - an unspecified value with a known type.
+ * 
+ * <p>A value entity might also represent a compile-time constant value as defined by the
+ * Java Language Specification section 15.28. To satisfy the requirements of the JLS when
+ * determining an expression type is necessary then to know the actual value, so there are
+ * methods provided for checking whether a value is known and what it is.
+ * 
+ * <p>Note that integer values are all representable as a "long" so there is only a single
+ * method to retrieve the known integer value; likewise "double" can also represent all
+ * "float" values.
+ * 
+ * @author Davin McCall
+ */
+public class ValueEntity extends JavaEntity
+{
+    private String name;
+    private JavaType type;
+    
+    /**
+     * Construct a value entity representing a value of the given type.
+     */
+    public ValueEntity(JavaType type)
+    {
+        this.type = type;
+    }
+    
+    /**
+     * Construct a value entity representing a value of the given type coming from
+     * the given name (meaning not well defined...)
+     */
+    public ValueEntity(String name, JavaType type)
+    {
+        this.name = name;
+        this.type = type;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public JavaEntity getSubentity(String name, Reflective accessor)
+    {
+        GenTypeSolid [] ubounds = type.getUpperBounds();
+        if (ubounds == null || ubounds.length == 0) {
+            return null;
+        }
+        
+        GenTypeClass ctype = ubounds[0].asClass();
+        
+        if (ctype != null) {
+            Reflective ctypeRef = ctype.getReflective();
+            LinkedList<Reflective> stypes = new LinkedList<Reflective>();
+            stypes.add(ctypeRef);
+            
+            FieldReflective field = null;
+            
+            while (! stypes.isEmpty()) {
+                ctypeRef = stypes.poll();
+                Map<String,FieldReflective> fields = ctypeRef.getDeclaredFields();
+                field = fields.get(name);
+                if (field != null) {
+                    break;
+                }
+                stypes.addAll(ctypeRef.getSuperTypesR());
+            }
+            
+            if (field != null) {
+                ctype = ctype.mapToSuper(ctypeRef.getName());
+                if (JavaUtils.checkMemberAccess(ctype.getReflective(), type.asSolid(), accessor,
+                        field.getModifiers(), false)) {
+                    JavaType fieldType = field.getType();
+                    Map<String,GenTypeParameter> tparMap = ctype.getMap();
+                    fieldType = fieldType.mapTparsToTypes(tparMap).getCapture();
+                    return new ValueEntity(this.name + "." + name, fieldType);
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public JavaType getType()
+    {
+        return type;
+    }
+
+    @Override
+    public ValueEntity resolveAsValue()
+    {
+        return this;
+    }
+    
+    @Override
+    public JavaEntity setTypeArgs(List<TypeArgumentEntity> tparams)
+    {
+        return null;
+    }
+    
+    /**
+     * Check whether this value entity represents a constant integer (byte,int,long,etc) value
+     */
+    public boolean hasConstantIntValue()
+    {
+        return false;
+    }
+    
+    /**
+     * Get the constant integer value represented by this value entity
+     */
+    public long getConstantIntValue()
+    {
+        throw new RuntimeException("Attempt to get constant value for entity without constant value");
+    }
+    
+    /**
+     * Check whether this value entity represents a constant "float" value
+     */
+    public boolean hasConstantFloatValue()
+    {
+        return false;
+    }
+    
+    /**
+     * Get the constant floating-point value represented by this value entity
+     */
+    public double getConstantFloatValue()
+    {
+        throw new RuntimeException("Attempt to get constant value for entity without constant value");
+    }
+    
+    /**
+     * Check whether this value entity represents a constant boolean value
+     */
+    public boolean hasConstantBooleanValue()
+    {
+        return false;
+    }
+    
+    /**
+     * Get the constant boolean value this value entity represents
+     */
+    public boolean getConstantBooleanValue()
+    {
+        throw new RuntimeException("Attempt to get constant value for entity without constant value");
+    }
+    
+    /**
+     * Check whether this value entity represents a String constant
+     */
+    public boolean isConstantString()
+    {
+        return false;
+    }
+    
+    /**
+     * Get the constant string value that this entity represents
+     */
+    public String getConstantString()
+    {
+        throw new RuntimeException("Attempt to get constant string value for an entity without such a value");
+    }
+    
+    /**
+     * Check whether a value entity represents any kind of constant (knonw at compile-time as per the JLS) value.
+     */
+    public static boolean isConstant(ValueEntity ent)
+    {
+        return ent.hasConstantBooleanValue() || ent.hasConstantIntValue()
+                || ent.hasConstantFloatValue() || ent.isConstantString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/WildcardExtendsEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/WildcardExtendsEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..236951d985b26958842af73866011e2fdc9a8f41
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/WildcardExtendsEntity.java
@@ -0,0 +1,54 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeExtends;
+import bluej.debugger.gentype.GenTypeParameter;
+
+/**
+ * Represents a "? extends ..." wildcard entity, where the bound has not yet been resolved.
+ * 
+ * @author Davin McCall
+ */
+public class WildcardExtendsEntity extends TypeArgumentEntity
+{
+    private JavaEntity extendsBound;
+    
+    public WildcardExtendsEntity(JavaEntity extendsBound)
+    {
+        this.extendsBound = extendsBound;
+    }
+    
+    @Override
+    public GenTypeParameter getType()
+    {
+        TypeEntity ebType = extendsBound.resolveAsType();
+        if (ebType != null) {
+            GenTypeClass cbType = ebType.getClassType();
+            if (cbType != null) {
+                return new GenTypeExtends(cbType);
+            }
+        }
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/WildcardSuperEntity.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/WildcardSuperEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..9499ebb04cb3d50daacf0da2b0b4fea9ea3d62ea
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/entity/WildcardSuperEntity.java
@@ -0,0 +1,54 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.entity;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.GenTypeSuper;
+
+/**
+ * Represents a "? super ..." wildcard entity, where the bound has not yet been resolved.
+ * 
+ * @author Davin McCall
+ */
+public class WildcardSuperEntity extends TypeArgumentEntity
+{
+    private JavaEntity superBound;
+    
+    public WildcardSuperEntity(JavaEntity superBound)
+    {
+        this.superBound = superBound;
+    }
+
+    @Override
+    public GenTypeParameter getType()
+    {
+        TypeEntity ebType = superBound.resolveAsType();
+        if (ebType != null) {
+            GenTypeClass cbType = ebType.getClassType();
+            if (cbType != null) {
+                return new GenTypeSuper(cbType);
+            }
+        }
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/JavaLexer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/JavaLexer.java
new file mode 100644
index 0000000000000000000000000000000000000000..8adc12b5414fffa6ca260b9f4b2aa1c4520cf50c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/JavaLexer.java
@@ -0,0 +1,817 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.lexer;
+
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Map;
+
+import bluej.parser.EscapedUnicodeReader;
+import bluej.parser.TokenStream;
+
+
+/**
+ * A Java lexer. Breaks up a source stream into tokens.
+ * 
+ * @author Marion Zalk
+ */
+public final class JavaLexer implements TokenStream
+{
+    private StringBuffer textBuffer; // text of current token
+    private EscapedUnicodeReader reader;
+    private int rChar; 
+    private int beginColumn, beginLine, beginPosition;
+    private int endColumn, endLine, endPosition;
+    private boolean generateWhitespaceTokens = false;
+    
+    private static Map<String,Integer> keywords = new HashMap<String,Integer>();
+    
+    static {
+        keywords.put("abstract", JavaTokenTypes.ABSTRACT);
+        keywords.put("assert", JavaTokenTypes.LITERAL_assert);
+        keywords.put("boolean", JavaTokenTypes.LITERAL_boolean);
+        keywords.put("break", JavaTokenTypes.LITERAL_break);
+        keywords.put("byte", JavaTokenTypes.LITERAL_byte);
+        keywords.put("case", JavaTokenTypes.LITERAL_case);
+        keywords.put("catch", JavaTokenTypes.LITERAL_catch);
+        keywords.put("char", JavaTokenTypes.LITERAL_char);
+        keywords.put("class", JavaTokenTypes.LITERAL_class);
+        keywords.put("continue", JavaTokenTypes.LITERAL_continue);
+        keywords.put("default", JavaTokenTypes.LITERAL_default);
+        keywords.put("do", JavaTokenTypes.LITERAL_do);
+        keywords.put("double", JavaTokenTypes.LITERAL_double);
+        keywords.put("else", JavaTokenTypes.LITERAL_else);
+        keywords.put("enum", JavaTokenTypes.LITERAL_enum);
+        keywords.put("extends", JavaTokenTypes.LITERAL_extends);
+        keywords.put("false", JavaTokenTypes.LITERAL_false);
+        keywords.put("final", JavaTokenTypes.FINAL);
+        keywords.put("finally", JavaTokenTypes.LITERAL_finally);
+        keywords.put("float", JavaTokenTypes.LITERAL_float);
+        keywords.put("for", JavaTokenTypes.LITERAL_for);
+        keywords.put("goto", JavaTokenTypes.GOTO);
+        keywords.put("if", JavaTokenTypes.LITERAL_if);
+        keywords.put("implements", JavaTokenTypes.LITERAL_implements);
+        keywords.put("import", JavaTokenTypes.LITERAL_import);
+        keywords.put("instanceof", JavaTokenTypes.LITERAL_instanceof);
+        keywords.put("int", JavaTokenTypes.LITERAL_int);
+        keywords.put("interface", JavaTokenTypes.LITERAL_interface);
+        keywords.put("long", JavaTokenTypes.LITERAL_long);
+        keywords.put("native", JavaTokenTypes.LITERAL_native);
+        keywords.put("new", JavaTokenTypes.LITERAL_new);
+        keywords.put("null", JavaTokenTypes.LITERAL_null);
+        keywords.put("package", JavaTokenTypes.LITERAL_package);
+        keywords.put("private", JavaTokenTypes.LITERAL_private);
+        keywords.put("protected", JavaTokenTypes.LITERAL_protected);
+        keywords.put("public", JavaTokenTypes.LITERAL_public);
+        keywords.put("return", JavaTokenTypes.LITERAL_return);
+        keywords.put("short", JavaTokenTypes.LITERAL_short);
+        keywords.put("static", JavaTokenTypes.LITERAL_static);
+        keywords.put("strictfp", JavaTokenTypes.STRICTFP);
+        keywords.put("super", JavaTokenTypes.LITERAL_super);
+        keywords.put("switch", JavaTokenTypes.LITERAL_switch);
+        keywords.put("synchronized", JavaTokenTypes.LITERAL_synchronized);
+        keywords.put("this", JavaTokenTypes.LITERAL_this);
+        keywords.put("throw", JavaTokenTypes.LITERAL_throw);
+        keywords.put("throws", JavaTokenTypes.LITERAL_throws);
+        keywords.put("transient", JavaTokenTypes.LITERAL_transient);
+        keywords.put("true", JavaTokenTypes.LITERAL_true);
+        keywords.put("try", JavaTokenTypes.LITERAL_try);
+        keywords.put("volatile", JavaTokenTypes.LITERAL_volatile);
+        keywords.put("while", JavaTokenTypes.LITERAL_while);
+        keywords.put("void", JavaTokenTypes.LITERAL_void);
+    }
+
+    /**
+     * Construct a lexer which readers from the given Reader.
+     */
+    public JavaLexer(Reader in)
+    {
+        this(in, 1, 1, 0);
+    }
+
+    /**
+     * Construct a lexer which readers from the given Reader, assuming that the
+     * reader is already positioned at the given line and column within the source
+     * document.
+     */
+    public JavaLexer(Reader in, int line, int col, int position)
+    {
+        reader = new EscapedUnicodeReader(in);
+        reader.setLineColPos(line, col, position);
+        endColumn = beginColumn = col;
+        endLine = beginLine = line;
+        endPosition = beginPosition = position;
+        try {
+            rChar = reader.read();
+        }
+        catch (IOException ioe) {
+            rChar = -1;
+        }
+    }
+    
+    /**
+     * Retrieve the next token.
+     */
+    public LocatableToken nextToken()
+    {  
+        textBuffer=new StringBuffer();
+        
+        if (generateWhitespaceTokens && Character.isWhitespace((char)rChar))
+        {
+            StringBuilder whitespaceBuffer = new StringBuilder();
+            while (Character.isWhitespace((char)rChar))
+            {
+                whitespaceBuffer.append((char)rChar);                
+                readNextChar();
+            }
+            return makeToken(JavaTokenTypes.WHITESPACE, whitespaceBuffer.toString());
+        }
+        else
+        {        
+            while (Character.isWhitespace((char)rChar)) {
+                beginLine = reader.getLine();
+                beginColumn = reader.getColumn();
+                beginPosition = reader.getPosition();
+                readNextChar();
+            }
+        }
+
+        if (rChar == -1) {
+            // EOF
+            return makeToken(JavaTokenTypes.EOF, null); 
+        }
+        
+        char nextChar = (char) rChar;
+        if (Character.isJavaIdentifierStart(nextChar)) {
+            return createWordToken(nextChar); 
+        }
+        if (Character.isDigit(nextChar)) {
+            return makeToken(readDigitToken(nextChar, false), textBuffer.toString());
+        }
+        return makeToken(getSymbolType(nextChar), textBuffer.toString());
+    }
+    
+    /**
+     * Make a token of the given type, with the given text. The token
+     * begins where the previous token ended, and ends at the current
+     * position (as found in endLine and endColumn).
+     */
+    private LocatableToken makeToken(int type, String txt)
+    {           
+        LocatableToken tok = new LocatableToken(type, txt);
+        tok.setPosition(beginLine, beginColumn, endLine, endColumn, beginPosition, endPosition - beginPosition);
+        beginColumn = endColumn;
+        beginLine = endLine;
+        beginPosition = endPosition;
+        return tok;
+    }
+
+    private LocatableToken createWordToken(char nextChar)
+    {
+        populateTextBuffer(nextChar);
+        return makeToken(getWordType(), textBuffer.toString());
+    }
+
+    private void populateTextBuffer(char ch)
+    {
+        char thisChar=ch;
+        do {  
+            textBuffer.append(thisChar);
+            int rval = readNextChar();
+            if (rval==-1){
+                //eof
+                return;
+            }
+            thisChar=(char)rval;
+        } while (Character.isJavaIdentifierPart(thisChar));
+    }
+
+    private boolean getTokenText(char endChar)
+    {
+        char thisChar=endChar;
+        int rval=0;     
+        boolean complete = false;
+        boolean escape = false;
+        while (!complete){  
+            rval=readNextChar();
+            //eof
+            if (rval==-1){
+                return false;
+            }
+            thisChar = (char)rval; 
+            if (thisChar=='\n'){
+                return false;
+            }
+
+            textBuffer.append(thisChar);
+            if (! escape) {
+                if (thisChar == '\\') {
+                    escape = true;
+                }
+                //endChar is the flag for the end of reading
+                if (thisChar == endChar)  {
+                    readNextChar();
+                    return true;
+                }
+            }
+            else {
+                escape = false;
+            }
+        }
+        return complete;
+    }
+
+    private boolean isHexDigit(char ch)
+    {
+        if (Character.isDigit(ch)) {
+            return true;
+        }
+        
+        if (ch >= 'a' && ch <= 'f') {
+            return true;
+        }
+        
+        if (ch >= 'A' && ch <= 'F') {
+            return true;
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Read a numerical literal token.
+     * 
+     * @param ch   The first character of the token (must be a decimal digit)
+     * @param dot  Whether there was a leading dot
+     */
+    private int readDigitToken(char ch, boolean dot)
+    {
+        int rval = ch;     
+        textBuffer.append(ch);
+        int type = dot ? JavaTokenTypes.NUM_DOUBLE : JavaTokenTypes.NUM_INT;
+
+        boolean fpValid = true; // whether a subsequent dot would be valid.
+                // (will be set false for a non-decimal literal).
+        
+        if (ch == '0') {
+            rval = readNextChar();
+            if (rval == 'x' || rval == 'X') {
+                // hexadecimal
+                textBuffer.append((char) rval);
+                rval = readNextChar();
+                if (!isHexDigit((char)rval)) {
+                    return JavaTokenTypes.INVALID;
+                }
+                
+                do {
+                    textBuffer.append((char) rval);
+                    rval = readNextChar();
+                } while (isHexDigit((char) rval) || rval == '_');
+                fpValid = false;
+            }
+            else if (rval == 'b' || rval == 'B') {
+                // Java 7 binary literal
+                textBuffer.append((char) rval);
+                rval = readNextChar();
+                if (rval != '0' && rval != '1') {
+                    return JavaTokenTypes.INVALID;
+                }
+                
+                do {
+                    textBuffer.append((char) rval);
+                    rval = readNextChar();
+                } while (rval == '0' || rval == '1' || rval == '_');
+                fpValid = false;
+            }
+            else if (Character.isDigit((char) rval)) {
+                do {
+                    // octal?
+                    textBuffer.append((char) rval);
+                    rval = readNextChar();
+                } while (Character.isDigit((char) rval) || rval == '_');
+                fpValid = false;
+            }
+            ch = (char) rval;
+        }
+        else {
+            rval = readNextChar();
+            while (Character.isDigit((char) rval) || rval == '_') {
+                textBuffer.append((char) rval);
+                rval = readNextChar();
+            }
+        }
+        
+        if (rval == '.' && fpValid) {
+            // A decimal.
+            textBuffer.append((char) rval);
+            rval = readNextChar();
+            while (Character.isDigit((char) rval) || rval == '_') {
+                textBuffer.append((char) rval);
+                rval = readNextChar();
+            }
+            if (rval == 'e' || rval == 'E') {
+                // exponent
+                textBuffer.append((char) rval);
+                rval = readNextChar();
+                while (Character.isDigit((char) rval) || rval == '_') {
+                    textBuffer.append((char) rval);
+                    rval = readNextChar();
+                }
+            }
+            
+            // Check for type suffixes
+            if (rval == 'f' || rval == 'F') {
+                textBuffer.append((char) rval);
+                rval = readNextChar();
+                return JavaTokenTypes.NUM_FLOAT;
+            }
+            if (rval == 'd' || rval == 'D') {
+                textBuffer.append((char) rval);
+                rval = readNextChar();
+            }
+            return JavaTokenTypes.NUM_DOUBLE;
+        }
+        
+        if ((rval == 'e' || rval == 'E') && fpValid) {
+            // exponent
+            textBuffer.append((char) rval);
+            rval = readNextChar();
+            while (Character.isDigit((char) rval) || rval == '_') {
+                textBuffer.append((char) rval);
+                rval = readNextChar();
+            }
+            type = JavaTokenTypes.NUM_DOUBLE;
+        }
+        else if (rval == 'l' || rval == 'L') {
+            textBuffer.append((char) rval);
+            rval = readNextChar();
+            return JavaTokenTypes.NUM_LONG;
+        }
+        
+        if (fpValid) {
+            if (rval == 'f' || rval == 'F') {
+                textBuffer.append((char) rval);
+                rval = readNextChar();
+                return JavaTokenTypes.NUM_FLOAT;
+            }
+            if (rval == 'd' || rval == 'D') {
+                textBuffer.append((char) rval);
+                rval = readNextChar();
+                return JavaTokenTypes.NUM_DOUBLE;
+            }
+        }
+        
+        return type;
+    }
+
+    private int getMLCommentType(char ch)
+    {
+        do{
+            textBuffer.append(ch);
+            int rval = readNextChar();
+            if (rval == -1) {
+                //eof
+                return JavaTokenTypes.INVALID;
+            }
+
+            ch=(char)rval;
+            while (ch=='*') {
+                textBuffer.append((char)rval);
+                rval = readNextChar();
+                if (rval == -1) {
+                    return JavaTokenTypes.INVALID;
+                }
+                if (rval == '/') {
+                    textBuffer.append((char)rval);
+                    readNextChar();
+                    return JavaTokenTypes.ML_COMMENT;
+                }
+                ch=(char)rval; 
+            }             
+        } while (true);
+    }
+    
+    private int getSLCommentType(char ch)
+    {
+        int rval=0;     
+
+        do{  
+            textBuffer.append(ch);
+            rval=readNextChar();
+            //eof
+            if (rval==-1 || rval == '\n') {
+                return JavaTokenTypes.SL_COMMENT;
+            }
+        } while (true);
+    }
+
+    private int getSymbolType(char ch)
+    {
+        int type= JavaTokenTypes.INVALID;
+        textBuffer.append(ch); 
+        if ('"' == ch)
+            return getStringLiteral();
+        if ('\'' == ch)
+            return getCharLiteral();
+        if ('?' == ch) {
+            readNextChar();
+            return JavaTokenTypes.QUESTION;
+        }
+        if (',' == ch) {
+            readNextChar();
+            return JavaTokenTypes.COMMA;
+        }
+        if (';' == ch) {
+            readNextChar();
+            return JavaTokenTypes.SEMI;
+        }
+        if (':' == ch) {
+            readNextChar();
+            return JavaTokenTypes.COLON;
+        }
+        if ('^' == ch)
+            return getBXORType();
+        if ('~' == ch) {
+            readNextChar();
+            return JavaTokenTypes.BNOT;
+        }
+        if ('(' == ch) {
+            readNextChar();
+            return JavaTokenTypes.LPAREN;
+        }
+        if (')' == ch) {
+            readNextChar();
+            return JavaTokenTypes.RPAREN;
+        }
+        if ('[' == ch) {
+            readNextChar();
+            return JavaTokenTypes.LBRACK;
+        }
+        if (']' == ch) {
+            readNextChar();
+            return JavaTokenTypes.RBRACK;
+        }
+        if ('{' == ch) {
+            readNextChar();
+            return JavaTokenTypes.LCURLY;
+        }
+        if ('}' == ch) {
+            readNextChar();
+            return JavaTokenTypes.RCURLY;
+        }
+        if ('@' == ch) {
+            readNextChar();
+            return JavaTokenTypes.AT;
+        }
+        if ('&' == ch)
+            return getAndType();
+        if ('|' == ch)
+            return getOrType();
+        if ('!' == ch)
+            return getExclamationType();
+        if ('+' == ch)
+            return getPlusType();            
+        if ('-' == ch)
+            return getMinusType();
+        if ('=' == ch)
+            return getEqualType();
+        if ('%' == ch)
+            return getModType();
+        if ('/' == ch)
+            return getForwardSlashType();
+        if ('.' == ch)
+            return getDotToken();
+        if ('*' == ch)
+            return getStarType();
+        if ('>' == ch)
+            return getGTType();
+        if ('<' == ch)
+            return getLTType();
+
+        readNextChar();
+        return type;
+    }
+
+    private int getBXORType()
+    {
+        char validChars[]=new char[1];
+        validChars[0]='='; 
+        int rval=readNextChar();
+        if (rval != '=') {
+            return JavaTokenTypes.BXOR;
+        }
+        char thisChar=(char)rval; 
+        textBuffer.append(thisChar); 
+        readNextChar();
+        return JavaTokenTypes.BXOR_ASSIGN;
+    }
+
+    private int getAndType()
+    {
+        char validChars[]=new char[2];
+        validChars[0]='=';
+        validChars[1]='&';        
+        int rval=readNextChar();
+        char thisChar = (char)rval; 
+        if (thisChar=='='){
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.BAND_ASSIGN; 
+        }
+        if (thisChar=='&'){
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.LAND; 
+        }
+        return JavaTokenTypes.BAND;
+    }
+
+    private int getStringLiteral()
+    {
+        boolean success=getTokenText('"');
+        if (success) {
+            return JavaTokenTypes.STRING_LITERAL;
+        }
+        return JavaTokenTypes.INVALID;     
+    }
+
+    private int getCharLiteral()
+    {
+        boolean success=getTokenText('\'');
+        if (success) {
+            return JavaTokenTypes.CHAR_LITERAL;
+        }
+        return JavaTokenTypes.INVALID;      
+    }
+
+    private int getOrType()
+    {
+        //|, |=, ||
+        int rval=readNextChar();
+        char thisChar=(char)rval; 
+        if (thisChar=='=') {
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.BOR_ASSIGN; 
+        }
+        if (thisChar=='|') {
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.LOR; 
+        }
+
+        return JavaTokenTypes.BOR;
+    }
+
+    private int getPlusType()
+    {
+        //+, +=, ++
+        int rval=readNextChar();
+        char thisChar=(char)rval; 
+        if (thisChar=='='){
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.PLUS_ASSIGN; 
+        }
+        if (thisChar=='+'){
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.INC; 
+        }
+
+        return JavaTokenTypes.PLUS;
+    }
+
+    private int getMinusType()
+    {
+        //-, -=, --
+        int rval=readNextChar();
+        char thisChar=(char)rval; 
+        if (thisChar=='='){
+            textBuffer.append(thisChar);
+            readNextChar();
+            return JavaTokenTypes.MINUS_ASSIGN; 
+        }
+        if (thisChar=='-'){
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.DEC; 
+        }
+
+        return JavaTokenTypes.MINUS;
+    }
+
+    private int getEqualType()
+    {
+        //=, ==
+        int rval = readNextChar();
+        char thisChar=(char)rval; 
+        if (thisChar=='='){
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.EQUAL; 
+        }
+
+        return JavaTokenTypes.ASSIGN;
+    }
+
+    private int getStarType()
+    {
+        //*, *=, 
+        int rval = readNextChar();
+        char thisChar=(char)rval; 
+        if (thisChar == '=') {
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.STAR_ASSIGN; 
+        }
+
+        return JavaTokenTypes.STAR;
+    }
+
+    private int getModType()
+    {
+        //%, %=
+        int rval=readNextChar();
+        char thisChar=(char)rval; 
+        if (thisChar=='='){
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.MOD_ASSIGN; 
+        }
+
+        return JavaTokenTypes.MOD;
+    }
+
+    private int getForwardSlashType()
+    {
+        // /,  /*, /= 
+        int rval=readNextChar();
+        char thisChar=(char)rval; 
+        if (thisChar=='=') {
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.DIV_ASSIGN; 
+        }
+        if (thisChar=='/') {
+            return getSLCommentType(thisChar);
+        }
+        if (thisChar=='*') {
+            return getMLCommentType(thisChar);
+        }
+
+        return JavaTokenTypes.DIV;
+    }
+
+    private int getGTType()
+    {
+        int rval=readNextChar();
+        char thisChar=(char)rval;
+        //>=
+        if (thisChar=='='){
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.GE; 
+        }
+        if (thisChar=='>'){
+            //>>
+            //>>>; >>>=; >>=
+            textBuffer.append(thisChar); 
+            rval=readNextChar();
+            thisChar = (char)rval;
+            if (thisChar=='>') {
+                textBuffer.append(thisChar); 
+                rval=readNextChar();
+                thisChar = (char)rval;
+                if (thisChar=='='){
+                    textBuffer.append(thisChar); 
+                    readNextChar();
+                    return JavaTokenTypes.BSR_ASSIGN; 
+                }
+                return JavaTokenTypes.BSR;
+            }
+            if (thisChar=='='){
+                textBuffer.append(thisChar); 
+                readNextChar();
+                return JavaTokenTypes.SR_ASSIGN; 
+            }
+            return JavaTokenTypes.SR;
+        }
+
+        return JavaTokenTypes.GT;
+    }
+
+    private int getLTType()
+    {
+        int rval=readNextChar();
+        char thisChar = (char)rval; 
+        if (thisChar=='='){
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.LE; 
+        }
+        if (thisChar=='<'){
+            textBuffer.append(thisChar); 
+            rval=readNextChar();
+            thisChar = (char)rval;
+            if (thisChar=='='){
+                textBuffer.append(thisChar); 
+                readNextChar();
+                return JavaTokenTypes.SL_ASSIGN;
+            }
+            return JavaTokenTypes.SL;
+        }
+
+        return JavaTokenTypes.LT;
+    }
+
+    private int getExclamationType()
+    {
+        int rval=readNextChar();
+        char thisChar = (char)rval; 
+        if (thisChar=='='){
+            textBuffer.append(thisChar); 
+            readNextChar();
+            return JavaTokenTypes.NOT_EQUAL; 
+        }
+
+        return JavaTokenTypes.LNOT;
+    }
+
+    private int getDotToken()
+    {
+        //. or .56f .12 
+        int rval = readNextChar();
+        char ch = (char)rval;
+        if (Character.isDigit(ch)){
+            return readDigitToken(ch, true);
+        }
+        //...
+        else if (ch=='.'){
+            textBuffer.append(ch); 
+            rval= readNextChar();
+            if (rval==-1){
+                return JavaTokenTypes.INVALID;
+            }
+            ch = (char)rval;
+            if (ch=='.'){
+                textBuffer.append(ch); 
+                readNextChar();
+                return JavaTokenTypes.TRIPLE_DOT;
+            }
+            else return JavaTokenTypes.INVALID;
+
+        }
+        return JavaTokenTypes.DOT;
+    }
+
+    private int readNextChar()
+    {
+        endColumn = reader.getColumn();
+        endLine = reader.getLine();
+        endPosition = reader.getPosition();
+        try{
+            rChar = reader.read();
+        } catch(IOException e) {
+            rChar = -1;
+        }
+
+        return rChar;
+    }
+
+    private int getWordType()
+    {
+        String text=textBuffer.toString();
+        Integer i = keywords.get(text);
+        if (i == null) {
+            return JavaTokenTypes.IDENT;
+        }
+        return i;
+    }
+
+    public void setGenerateWhitespaceTokens(boolean generateWhitespaceTokens)
+    {
+        this.generateWhitespaceTokens = generateWhitespaceTokens;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/JavaTokenFilter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/JavaTokenFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f4245fdae2fde840f1f49ecbc5882eba2117475
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/JavaTokenFilter.java
@@ -0,0 +1,145 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.lexer;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import bluej.parser.JavaParser;
+import bluej.parser.TokenStream;
+
+
+/**
+ * This is a token stream processor. It removes whitespace and comment tokens from the
+ * stream, attaching comments as hidden tokens to the next suitable token.
+ * 
+ * @author Davin McCall
+ */
+public final class JavaTokenFilter implements TokenStream
+{
+    private TokenStream sourceStream;
+    private LocatableToken lastComment;
+    private LocatableToken cachedToken;
+    private List<LocatableToken> buffer = new LinkedList<LocatableToken>();
+    private JavaParser parser;
+    
+    public JavaTokenFilter(TokenStream source)
+    {
+        sourceStream = source;
+        lastComment = null;
+    }
+    
+    public JavaTokenFilter(TokenStream source, JavaParser parser)
+    {
+        this(source);
+        this.parser = parser;
+    }
+        
+    public LocatableToken nextToken()
+    {
+        if (! buffer.isEmpty()) {
+            // Make sure we have a cached token; necessary to ensure that token lengths
+            // are set correctly.
+            if (cachedToken == null) {
+                cachedToken = nextToken2();
+            }
+            return buffer.remove(buffer.size() - 1);
+        }
+    	
+    	// We cache one lookahead token so that we can be sure the returned token
+        // has its end column set correctly. (The end column for a token can only be set
+        // when the following token is received).
+        LocatableToken rval;
+        if (cachedToken == null) {
+            rval = nextToken2();
+        }
+        else {
+            rval = cachedToken;
+        }
+        
+        cachedToken = nextToken2();
+        return (LocatableToken) rval;
+    }
+    
+    /**
+     * Push a token on to the stream. The token will be returned by the next call
+     * to nextToken().
+     */
+    public void pushBack(LocatableToken token)
+    {
+    	buffer.add(token);
+    }
+    
+    /**
+     * Look ahead a certain number of tokens (without actually consuming them).
+     * @param distance  The distance to look ahead (1 or greater).
+     */
+    public LocatableToken LA(int distance)
+    {
+    	if (cachedToken != null) {
+    	   buffer.add(0, (LocatableToken) cachedToken);
+    	   cachedToken = null;
+    	}
+    	
+    	int numToAdd = distance - buffer.size();
+    	while (numToAdd > 0) {
+    	   buffer.add(0, nextToken2());
+    	   numToAdd--;
+    	}
+    
+    	return buffer.get(buffer.size() - distance);
+    }
+    
+    private LocatableToken nextToken2()
+    {    	
+    	LocatableToken t = null;
+        
+        // Repeatedly read tokens until we find a non-comment, non-whitespace token.
+        while (true) {
+            t = (LocatableToken) sourceStream.nextToken();
+            
+            int ttype = t.getType();
+            if (ttype == JavaTokenTypes.ML_COMMENT) {
+                // If we come across a comment, save it.
+                lastComment = t;
+                if (parser != null) {
+                    parser.gotComment(t);
+                }
+            }
+            else if (ttype == JavaTokenTypes.SL_COMMENT) {
+                if (parser != null) {
+                    parser.gotComment(t);
+                }
+            }
+            else {
+                // When we have an interesting token, attach the previous comment.
+                if (lastComment != null) {
+                    t.setHiddenBefore(lastComment);
+                    lastComment = null;
+                }
+                break;
+            }
+        }
+        
+        return t;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/JavaTokenTypes.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/JavaTokenTypes.java
new file mode 100644
index 0000000000000000000000000000000000000000..0fa500999ca549369c7c3141062b26448eb05d23
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/JavaTokenTypes.java
@@ -0,0 +1,142 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009, 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.lexer;
+
+/**
+ * This interface just acts as a container for various Java token types.
+ */
+public interface JavaTokenTypes
+{
+    int EOF = 1;
+    int FINAL = 39;
+    int ABSTRACT = 40;
+    int STRICTFP = 41;
+    int ML_COMMENT = 61;
+    int LITERAL_package = 62;
+    int SEMI = 63;
+    int LITERAL_import = 64;
+    int LITERAL_static = 65;
+    int LBRACK = 66;
+    int RBRACK = 67;
+    int DOT = 68;
+    int IDENT = 69;
+    int QUESTION = 70;
+    int LITERAL_extends = 71;
+    int LITERAL_super = 72;
+    int LT = 73;
+    int COMMA = 74;
+    int GT = 75;
+    int SR = 76;
+    int BSR = 77;
+    int LITERAL_void = 78;
+    int LITERAL_boolean = 79;
+    int LITERAL_byte = 80;
+    int LITERAL_char = 81;
+    int LITERAL_short = 82;
+    int LITERAL_int = 83;
+    int LITERAL_float = 84;
+    int LITERAL_long = 85;
+    int LITERAL_double = 86;
+    int STAR = 87;
+    int LITERAL_private = 88;
+    int LITERAL_public = 89;
+    int LITERAL_protected = 90;
+    int LITERAL_transient = 91;
+    int LITERAL_native = 92;
+    int LITERAL_synchronized = 93;
+    int LITERAL_volatile = 94;
+    int AT = 95;
+    int LPAREN = 96;
+    int RPAREN = 97;
+    int ASSIGN = 98;
+    int LCURLY = 99;
+    int RCURLY = 100;
+    int LITERAL_class = 101;
+    int LITERAL_interface = 102;
+    int LITERAL_enum = 103;
+    int BAND = 104;
+    int LITERAL_default = 105;
+    int LITERAL_implements = 106;
+    int LITERAL_this = 107;
+    int LITERAL_throws = 108;
+    int TRIPLE_DOT = 109;
+    int COLON = 110;
+    int LITERAL_if = 111;
+    int LITERAL_else = 112;
+    int LITERAL_while = 113;
+    int LITERAL_do = 114;
+    int LITERAL_break = 115;
+    int LITERAL_continue = 116;
+    int LITERAL_return = 117;
+    int LITERAL_switch = 118;
+    int LITERAL_throw = 119;
+    int LITERAL_assert = 120;
+    int LITERAL_for = 121;
+    int LITERAL_case = 122;
+    int LITERAL_try = 123;
+    int LITERAL_finally = 124;
+    int LITERAL_catch = 125;
+    int PLUS_ASSIGN = 126;
+    int MINUS_ASSIGN = 127;
+    int STAR_ASSIGN = 128;
+    int DIV_ASSIGN = 129;
+    int MOD_ASSIGN = 130;
+    int SR_ASSIGN = 131;
+    int BSR_ASSIGN = 132;
+    int SL_ASSIGN = 133;
+    int BAND_ASSIGN = 134;
+    int BXOR_ASSIGN = 135;
+    int BOR_ASSIGN = 136;
+    int LOR = 137;
+    int LAND = 138;
+    int BOR = 139;
+    int BXOR = 140;
+    int NOT_EQUAL = 141;
+    int EQUAL = 142;
+    int LE = 143;
+    int GE = 144;
+    int LITERAL_instanceof = 145;
+    int SL = 146;
+    int PLUS = 147;
+    int MINUS = 148;
+    int DIV = 149;
+    int MOD = 150;
+    int INC = 151;
+    int DEC = 152;
+    int BNOT = 153;
+    int LNOT = 154;
+    int LITERAL_true = 155;
+    int LITERAL_false = 156;
+    int LITERAL_null = 157;
+    int LITERAL_new = 158;
+    int NUM_INT = 159;
+    int CHAR_LITERAL = 160;
+    int STRING_LITERAL = 161;
+    int NUM_FLOAT = 162;
+    int NUM_LONG = 163;
+    int NUM_DOUBLE = 164;
+    int SL_COMMENT = 166;
+    int WHITESPACE = 167; // Only generated by lexer when instructed to
+    int GOTO = 171;
+    int INVALID = 172;
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/LocatableToken.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/LocatableToken.java
new file mode 100644
index 0000000000000000000000000000000000000000..735c9acf0542f10fa989b136e03fc4e6279c9d75
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/lexer/LocatableToken.java
@@ -0,0 +1,119 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.lexer;
+
+public class LocatableToken
+{
+    private int beginLine, beginColumn;
+    private int endLine, endColumn;
+    private LocatableToken hiddenBefore;
+    private int type;
+    private int position, length; // position and length in original source
+    private String text;
+    
+    public LocatableToken(int t, String txt)
+    {
+        type = t;
+        text = txt;
+    }
+
+    public void setEndLineAndCol(int l, int c)
+    {
+        endLine = l;
+        endColumn = c;
+    }
+    
+    public int getEndColumn()
+    {
+        return endColumn;
+    }
+    
+    public int getEndLine()
+    {
+        return endLine;
+    }
+    
+    public int getLine()
+    {
+        return beginLine;
+    }
+
+    public void setPosition(int beginLine, int beginColumn, int endLine, int endColumn, int position, int length)
+    {
+        this.beginLine = beginLine;
+        this.beginColumn = beginColumn;
+        this.endLine = endLine;
+        this.endColumn = endColumn;
+        this.position = position;
+        this.length = length;
+    }
+    
+    public int getColumn()
+    {
+        return beginColumn;
+    }
+    
+    public int getType()
+    {
+        return type;
+    }
+    
+    /**
+     * Gets the text of the token, with any unicode escapes from the original
+     * taken care of.
+     * 
+     * For example, the original code may have String with the capital S escaped,
+     * like "\u0053tring".  In this case, getText() would return "String".
+     */
+    public String getText()
+    {
+        return text;
+    }
+    
+    /**
+     * Returns the length of the token in the original source.  Note that
+     * this is not necessarily the same as getText().length(), because the original
+     * token may have contained unicode escapes.  In this case, getText() will
+     * return the processed version, without escapes, but getLength() will
+     * still return the length of the original token in the document, including
+     * all the escapes.
+     */
+    public int getLength()
+    {
+        return length;
+    }
+    
+    public int getPosition()
+    {
+        return position;
+    }
+    
+    public void setHiddenBefore(LocatableToken t)
+    {
+        hiddenBefore = t;
+    }
+    
+    public LocatableToken getHiddenBefore()
+    {
+        return hiddenBefore;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/CommentNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/CommentNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6afc6924e9793f52b5960294fa2c865482fdc4e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/CommentNode.java
@@ -0,0 +1,198 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.io.Reader;
+
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+
+import bluej.editor.moe.MoeSyntaxDocument;
+import bluej.editor.moe.Token;
+import bluej.parser.CodeSuggestions;
+import bluej.parser.DocumentReader;
+import bluej.parser.lexer.JavaLexer;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+
+/**
+ * A node type for representing comments in the code.
+ * 
+ * @author Davin McCall
+ */
+public class CommentNode extends ParsedNode
+{
+    byte type;
+    private static byte SL_NORMAL = 0;
+    private static byte SL_SPECIAL = 1;
+    private static byte ML_NORMAL = 2;
+    private static byte ML_JAVADOC = 3;
+    private static byte ML_SPECIAL = 4;
+    
+    private static byte [] colours = {
+        Token.COMMENT1,
+        Token.COMMENT3,
+        Token.COMMENT1,
+        Token.COMMENT2,
+        Token.COMMENT3
+    };
+    
+    public CommentNode(ParsedNode parentNode, LocatableToken token)
+    {
+        super(parentNode);
+        type = getCommentType(token);
+    }
+    
+    /**
+     * Determine the comment type from the token.
+     */
+    private static byte getCommentType(LocatableToken token)
+    {
+        String text = token.getText();
+        if (token.getType() == JavaTokenTypes.ML_COMMENT) {
+            if (text.startsWith("/*#")) {
+                return ML_SPECIAL;
+            }
+            if (text.startsWith("/**#")) {
+                return ML_SPECIAL;
+            }
+            if (text.startsWith("/**")) {
+                return ML_JAVADOC;
+            }
+            return ML_NORMAL;
+        }
+        
+        // Single line
+        if (text.startsWith("//#")) {
+            return SL_SPECIAL;
+        }
+        
+        return SL_NORMAL;
+    }
+    
+    public boolean isJavadocComment()
+    {
+        return type == ML_JAVADOC;
+    }
+    
+    
+    @Override
+    public int getNodeType()
+    {
+        return NODETYPE_COMMENT;
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.parser.nodes.ParsedNode#getMarkTokensFor(int, int, int, javax.swing.text.Document)
+     */
+    public Token getMarkTokensFor(int pos, int length, int nodePos,
+            Document document)
+    {
+        Token tok = new Token(length, colours[type]);
+        tok.next = new Token(0, Token.END);
+        return tok;
+    }
+
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return true;
+    }
+    
+    @Override
+    public int textInserted(MoeSyntaxDocument document, int nodePos, int insPos, int length,
+            NodeStructureListener listener)
+    {
+        // grow ourself:
+        int newSize = getSize() + length;
+        resize(newSize);
+        document.scheduleReparse(insPos, length);
+        return ALL_OK;
+    }
+
+    @Override
+    public int textRemoved(MoeSyntaxDocument document, int nodePos, int delPos, int length,
+            NodeStructureListener listener)
+    {
+        // shrink ourself:
+        int newSize = getSize() - length;
+        resize(newSize);
+        document.scheduleReparse(delPos, 0);
+        return ALL_OK;
+    }
+
+    @Override
+    protected int reparseNode(Document document, int nodePos, int offset, int maxParse,
+            NodeStructureListener listener)
+    {
+        // Make a reader and parser
+        int pline = document.getDefaultRootElement().getElementIndex(nodePos) + 1;
+        int pcol = nodePos - document.getDefaultRootElement().getElement(pline - 1).getStartOffset() + 1;
+        Reader r = new DocumentReader(document, nodePos, nodePos + getSize());
+        JavaLexer lexer = new JavaLexer(r, pline, pcol, nodePos);
+
+        LocatableToken commentToken = lexer.nextToken();
+        if (commentToken.getType() != JavaTokenTypes.SL_COMMENT &&
+                commentToken.getType() != JavaTokenTypes.ML_COMMENT) {
+            return REMOVE_NODE;
+        }
+        
+        byte newType = getCommentType(commentToken);
+        if (type <= SL_SPECIAL && newType > SL_SPECIAL) {
+            // changed from single to multi-line
+            return REMOVE_NODE;
+        }
+        else if (type > SL_SPECIAL && newType <= SL_SPECIAL) {
+            // changed from multi-line to single line
+            if (getOffsetFromParent() == 0 && getParentNode().isCommentAttached()) {
+                return REMOVE_NODE;
+            }
+        }
+        
+        type = newType;
+        
+        int newEnd = lineColToPos(document, commentToken.getEndLine(),
+                commentToken.getEndColumn());
+        int newSize = newEnd - nodePos;
+        ((MoeSyntaxDocument)document).markSectionParsed(nodePos, newSize);
+        if (getSize() != newSize) {
+            setSize(newSize);
+            return NODE_SHRUNK;
+        }
+        
+        return ALL_OK;
+    }
+    
+    
+    private static int lineColToPos(Document document, int line, int col)
+    {
+        Element map = document.getDefaultRootElement();
+        Element lineEl = map.getElement(line - 1);
+        return lineEl.getStartOffset() + col - 1;
+    }
+    
+    @Override
+    public CodeSuggestions getExpressionType(int pos, Document document)
+    {
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ContainerNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ContainerNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..95f4f0c25f930bf95f94976b9a1aef07a9a1dfd5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ContainerNode.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+/**
+ * A basic container node implementation. A container node contains some sort of inner
+ * scope.
+ * 
+ * @author Davin McCall
+ */
+public class ContainerNode extends JavaParentNode
+{
+    private int nodeType;
+    
+    public ContainerNode(JavaParentNode parent, int nodeType)
+    {
+        super(parent);
+        this.nodeType = nodeType;
+    }
+    
+    @Override
+    public int getNodeType()
+    {
+        return nodeType;
+    }
+    
+    @Override
+    public boolean isContainer()
+    {
+        return true;
+    }
+    
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/DeclarationNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/DeclarationNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3f28ce3ec08cb62dc5e0c3475ed175427fe3df0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/DeclarationNode.java
@@ -0,0 +1,40 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+/**
+ * Filler node for declarations where we don't yet know what is being declared (method,
+ * constructor, field/variable, type)
+ */
+public class DeclarationNode extends JavaParentNode
+{
+    public DeclarationNode(JavaParentNode parent)
+    {
+        super(parent);
+    }
+    
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ExpressionNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ExpressionNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..ea626bba6b5ffc728b0c1dda77704e96fca955cd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ExpressionNode.java
@@ -0,0 +1,96 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.io.Reader;
+
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeSolid;
+import bluej.parser.CodeSuggestions;
+import bluej.parser.CompletionParser;
+import bluej.parser.DocumentReader;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * A node representing a parsed expression.
+ * 
+ * @author Davin McCall
+ */
+public class ExpressionNode extends JavaParentNode
+{
+    public ExpressionNode(JavaParentNode parent)
+    {
+        super(parent);
+    }
+    
+    @Override
+    public int getNodeType()
+    {
+        return NODETYPE_EXPRESSION;
+    }
+    
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return false;
+    }
+    
+    @Override
+    protected CodeSuggestions getExpressionType(int pos, int nodePos, JavaEntity defaultType, Document document)
+    {
+        valueEntityCache.clear();
+        pocEntityCache.clear();
+        
+        NodeAndPosition<ParsedNode> nap = findNodeAt(pos, nodePos);
+        if (nap != null && nap.getNode().getNodeType() == ParsedNode.NODETYPE_TYPEDEF) {
+            return nap.getNode().getExpressionType(pos, nap.getPosition(), defaultType, document);
+        }
+        return suggestAsExpression(pos, nodePos, this, defaultType, document);
+    }
+    
+    public static CodeSuggestions suggestAsExpression(int pos, int nodePos, EntityResolver resolver,
+            JavaEntity defaultType, Document document)
+    {
+        Reader r = new DocumentReader(document, nodePos, pos);
+        Element map = document.getDefaultRootElement();
+        int line = map.getElementIndex(nodePos) + 1;
+        int col = nodePos - map.getElement(line - 1).getStartOffset() + 1;
+        
+        CompletionParser parser = new CompletionParser(resolver, r, defaultType, line, col, nodePos);
+        parser.parseExpression();
+        
+        GenTypeSolid stype = parser.getSuggestionType();
+        GenTypeClass atype = (defaultType != null) ? defaultType.getType().asClass() : null;
+        if (stype != null) {
+            return new CodeSuggestions(stype, atype, parser.getSuggestionToken(), parser.isSuggestionStatic());
+        }
+        else {
+            return null;
+        }
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/FieldNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/FieldNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..6030a6943f00d006cf4360603bec9db77ec76c8f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/FieldNode.java
@@ -0,0 +1,134 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import javax.swing.text.Document;
+
+import bluej.parser.CodeSuggestions;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.UnresolvedArray;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * A node representing a parsed field or variable declaration.
+ * 
+ * @author Davin McCall
+ */
+public class FieldNode extends JavaParentNode
+{
+    private String name;
+    private JavaEntity fieldType;
+    private FieldNode firstNode;
+    private int modifiers;
+    /** Number of extra array declarators */
+    private int arrayDecls;
+    
+    /**
+     * Construct a field node representing the first declared field in a field
+     * declaration. The fieldType may be null if it appears invalid.
+     */
+    public FieldNode(JavaParentNode parent, String name, JavaEntity fieldType, int arrayDecls,
+            int modifiers)
+    {
+        super(parent);
+        this.name = name;
+        this.fieldType = fieldType;
+        this.arrayDecls = arrayDecls;
+        this.modifiers = modifiers;
+    }
+    
+    /**
+     * Construct a field node representing the second or a subsequent field
+     * declared in a field declaration.
+     * @param parent     The parent parsed node (should be a TypeInnerNode)
+     * @param firstNode  The node representing the first declared field
+     */
+    public FieldNode(JavaParentNode parent, String name, FieldNode firstNode, int arrayDecls)
+    {
+        super(parent);
+        this.name = name;
+        this.firstNode = firstNode;
+        this.arrayDecls = arrayDecls;
+    }
+    
+    @Override
+    public int getNodeType()
+    {
+        return ParsedNode.NODETYPE_FIELD;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return true;
+    }
+    
+    /**
+     * Get the type of this field (as a JavaEntity, which needs to be resolved as a type).
+     */
+    public JavaEntity getFieldType()
+    {
+        JavaEntity ftype = firstNode == null ? fieldType : firstNode.fieldType;
+        for (int i = 0; i < arrayDecls; i++) {
+            ftype = new UnresolvedArray(ftype);
+        }
+        return ftype;
+    }
+    
+    /**
+     * Get the modifiers of this field 
+     * @return
+     */
+    public int getModifiers()
+    {
+        if (firstNode != null) {
+            return firstNode.getModifiers();
+        }
+        return modifiers;
+    }
+    
+    @Override
+    protected CodeSuggestions getExpressionType(int pos, int nodePos, JavaEntity defaultType, Document document)
+    {
+        NodeAndPosition<ParsedNode> child = getNodeTree().findNode(Math.max(pos - 1, 0), nodePos);
+        if (child != null) {
+            return child.getNode().getExpressionType(pos, child.getPosition(), defaultType, document);
+        }
+        
+        // A field node can actually be an expression with a missing semicolon, followed
+        // by an identifier (which is actually meant to be part of the next statement).
+        //
+        //   eg:
+        //      some.expr
+        //      someMethodCall();
+        //
+        // So, we'll pretend we're an expression.
+        return ExpressionNode.suggestAsExpression(pos, nodePos, this, defaultType, document);
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ImportNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ImportNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..46e89545e653dcfaf5f636441bf1808fcfc5bc43
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ImportNode.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+/**
+ * A parsed node representing an import statement.
+ * 
+ * @author Davin McCall
+ */
+public class ImportNode extends InnerNode
+{
+    public ImportNode(JavaParentNode parent)
+    {
+        super(parent);
+    }
+    
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/IncrementalParsingNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/IncrementalParsingNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1cabc339a4fcc29aa4ae6f9f6386e9d671ba17b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/IncrementalParsingNode.java
@@ -0,0 +1,803 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.LinkedList;
+import java.util.Stack;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+
+import bluej.editor.moe.MoeSyntaxDocument;
+import bluej.parser.DocumentReader;
+import bluej.parser.EditorParser;
+import bluej.parser.EscapedUnicodeReader;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * An abstract base class for nodes which can do incremental parsing.<p>
+ * 
+ * We assume that such a node is broken into pieces which can be parsed separately.
+ * At least some such pieces will form complete sub-nodes which allow us to determine
+ * where we can re-parse from if a modification is made.<p>
+ * 
+ * Sub-classes must provide implementations for several methods to parse a piece,
+ * determine whether a subnode represents a complete piece, etc.<p>
+ * 
+ * IncrementalParsingNode has basic support for sequential parse states, where a node
+ * consists of several parts in sequence and each part must be parsed differently. The
+ * "stateMarkers" array contains the offset (from the node beginning) of each state
+ * transition; subclasses should assign it an array of appropriate size. A value of -1
+ * in any entry means the marker is invalid.
+ * 
+ * @author Davin McCall
+ */
+public abstract class IncrementalParsingNode extends JavaParentNode
+{
+    /**
+     * The end position of each parse state. -1 means the marker is invalid.
+     */
+    protected int [] stateMarkers = new int[0];
+    /**
+     * Whether the corresponding state marker specifically marks the end of the state (true), or if it rather
+     * marks the beginning of the next state (false).
+     */
+    protected boolean [] marksEnd = new boolean[0];
+    
+    
+    /** The final token in the last partial parse. Should be set by doPartialParse if possible. */
+    protected LocatableToken last;
+    
+    // Partial parse status values
+    protected final static int PP_OK = 0;
+    /** Node ends, due to a parser error */
+    protected final static int PP_INCOMPLETE = 1;
+    /** Node ends just before the "last" token */
+    protected final static int PP_ENDS_NODE = 2;
+    /** Node ends at end of the "last" token */
+    protected final static int PP_ENDS_NODE_AFTER = 3;
+    /** Parse completely failed. The node must be removed and the parent re-parsed. */
+    protected final static int PP_EPIC_FAIL = 4;
+    /** The "last" token ends the state. The new state begins after it. */
+    protected final static int PP_ENDS_STATE = 5;
+    /** The "last" token is the beginning of the next state */
+    protected final static int PP_BEGINS_NEXT_STATE = 6;
+    /** The current state fails, requiring a regression to the previous parse state */
+    protected final static int PP_REGRESS_STATE = 7;
+    /** Pull the next child up behind the "last" token and continue parsing inside it */
+    protected final static int PP_PULL_UP_CHILD = 8;
+    /**
+     * Abort the parse. This must be safe; either the parse has completed or an
+     * appropriate re-parse has been scheduled. params.abortPos must be set.
+     */
+    protected final static int PP_ABORT = 9;
+    
+    
+    /**
+     * Construct an incremental parsing node with the given parent node.
+     */
+    public IncrementalParsingNode(JavaParentNode parent)
+    {
+        super(parent);
+    }
+    
+    /**
+     * Check whether the given node represents a complete parsed piece. If
+     * it does, we can safely resume incremental parsing just beyond its
+     * end. Also, if we are incrementally parsing, and we complete a piece
+     * at the boundary with this node, we don't need to continue parsing.
+     */
+    protected abstract boolean isDelimitingNode(NodeAndPosition<ParsedNode> nap);
+    
+    /**
+     * Actually perform a partial parse. If possible, this method should set
+     * "last" to the last token forming part of the parsed piece or null if there was a
+     * parsing error. (It is safe to always set it to null).<p>
+     * 
+     * The return value is one of the PP_ constants: PP_OK, PP_ENDS_NODE if the parse
+     * succeeds but requires that the node ends immediately, PP_EPIC_FAIL if the parse
+     * fails and indicates that the node is not what it purports to be.
+     */
+    protected abstract int doPartialParse(ParseParams params, int state);
+    
+    protected boolean isNodeEndMarker(int tokenType)
+    {
+        return tokenType == JavaTokenTypes.RCURLY;
+    }
+    
+    @Override
+    protected int reparseNode(Document document, int nodePos, int offset, int maxParse, NodeStructureListener listener)
+    {
+        int parseEnd = Math.min(offset + maxParse, nodePos + getSize());
+        int state = getCurrentState(offset - nodePos);
+        int originalOffset = offset;
+        
+        // Find the nearest container node or state boundary prior to the reparse point.
+        int stateBoundary = (state != 0) ? stateMarkers[state - 1] + nodePos : nodePos;
+        NodeAndPosition<ParsedNode> nap = null;
+        if (offset > stateBoundary) {
+            nap = getNodeTree().findNodeAtOrBefore(offset - 1, nodePos);
+        }
+        
+        while (nap != null && !isDelimitingNode(nap)) {
+            if (nap.getPosition() >= stateBoundary) {
+                nap = getNodeTree().findNodeAtOrBefore(nap.getPosition() - 1, nodePos);
+            }
+            else {
+                nap = null;
+            }
+        }
+        
+        NodeAndPosition<ParsedNode> nextNap = null;
+        if (nap != null) {
+            nextNap = nap.nextSibling();
+            offset = nap.getEnd();
+        }
+        else {
+            offset = stateBoundary; // reparse from previous state marker
+        }
+                        
+        // Pull out the current child nodes into a queue. We re-insert them if we get the opportunity;
+        // otherwise we'll have to dispose of them properly later.
+        NodeAndPosition<ParsedNode> boundaryNap = nap;
+        LinkedList<NodeAndPosition<ParsedNode>> childQueue = new LinkedList<NodeAndPosition<ParsedNode>>();
+        if (nap == null) {
+            nap = findNodeAtOrAfter(offset + 1, nodePos);
+        }
+        else {
+            nap = nextNap;
+        }
+        while (nap != null) {
+            childQueue.add(nap);
+            nextNap = nap.nextSibling();
+            nap.getNode().remove();
+            nap = nextNap;
+        }
+
+        // Find the next child node, which we may bump into when we are parsing.
+        NodeAndPosition<ParsedNode> nextChild = childQueue.peek();
+        
+        // Make a reader and parser
+        int pline = document.getDefaultRootElement().getElementIndex(offset) + 1;
+        int pcol = offset - document.getDefaultRootElement().getElement(pline - 1).getStartOffset() + 1;
+        Reader r = new DocumentReader(document, offset, parseEnd);
+        EditorParser parser = new EditorParser(document, r, pline, pcol, offset, buildScopeStack());
+                
+        LocatableToken laToken = parser.getTokenStream().LA(1);
+        int ttype = laToken.getType();
+        int tokpos = lineColToPos(document, laToken.getLine(), laToken.getColumn());
+        nap = boundaryNap;
+        
+        boolean extendPrev = false;
+        if (nap != null) {
+            if (! nap.getNode().complete) {
+                // Two cases:
+                //
+                // 1. the node marks its own end. In this case the node might
+                // not have extended as far as possible - consider if{} without an else.
+                // The else clause must attach to the if{} block if it is inserted later.
+                // (Similarly for try/catch/catch/finally).
+                //
+                // 2. the node end is marked by something in the parent node (i.e this node).
+                // in that case the node should be extended only if the token overlaps the
+                // original reparse offset.
+                //
+                // At the moment we can't tell which of the two cases, so we always extend.
+                extendPrev = true;
+            }
+        }
+        
+        if (extendPrev) {
+            int tokend = lineColToPos(document, laToken.getEndLine(), laToken.getEndColumn());
+            if (ttype == JavaTokenTypes.EOF) {
+                boolean weCanGrow = nodePos + getSize() < document.getLength();
+                if (! weCanGrow && tokend == nap.getEnd()) {
+                    // No possibility for growth.
+                    ((MoeSyntaxDocument) document).markSectionParsed(offset, tokend - offset + 1);
+                    return ALL_OK;
+                }
+                
+                if (weCanGrow) {
+                    boolean grew = getParentNode().growChild(document,
+                            new NodeAndPosition<ParsedNode>(this, nodePos, getSize()),
+                            listener);
+                    if (!grew) {
+                        return REMOVE_NODE;
+                    }
+                    complete = false;
+                    return ALL_OK; // because we haven't marked anything as parsed, this
+                    // will cause a re-parse
+                }
+            }
+            // The first token we read "joins on" to the end of the incomplete previous node.
+            // So, we'll attempt to add it in.
+            nextChild = removeOverwrittenChildren(childQueue, tokend, listener);
+            int oldSize = nap.getSize(); // record original size
+            nap.setSize(tokend - nap.getPosition()); // append the token
+            listener.nodeChangedLength(nap, nap.getPosition(), oldSize);
+            int pr = nap.getNode().reparseNode(document, nap.getPosition(), tokpos, parseEnd - tokpos, listener);
+            if (pr == REMOVE_NODE) {
+                removeChild(nap, listener);
+                // Schedule from the original offset, as we may get stuck in a loop otherwise
+                // (Because the piecemeal parse amount is less than the original node size).
+                ((MoeSyntaxDocument)document).scheduleReparse(originalOffset,
+                        tokend - originalOffset);
+                return ALL_OK;
+            }
+            else {
+                if (nap.getNode().getSize() != oldSize) {
+                    if (! nap.getNode().complete) {
+                        // just reschedule
+                        //((MoeSyntaxDocument)document).scheduleReparse(originalOffset, 0);
+                        return ALL_OK;
+                    }
+                    offset = nap.getPosition() + nap.getNode().getSize();
+                    pline = document.getDefaultRootElement().getElementIndex(offset) + 1;
+                    pcol = offset - document.getDefaultRootElement().getElement(pline - 1).getStartOffset() + 1;
+                    r = new DocumentReader(document, offset, parseEnd);
+                    parser = new EditorParser(document, r, pline, pcol, offset, buildScopeStack());
+                    laToken = parser.getTokenStream().LA(1);
+                    tokpos = lineColToPos(document, laToken.getLine(), laToken.getColumn());
+                }
+            }
+        }
+                        
+        int nextStatePos = (state < stateMarkers.length) ? stateMarkers[state] : -1;
+        nextStatePos += (nextStatePos == -1) ? 0 : nodePos;
+        
+        ParseParams pparams = new ParseParams();
+        pparams.listener = listener;
+        pparams.parser = parser;
+        pparams.tokenStream = parser.getTokenStream();
+        pparams.document = (MoeSyntaxDocument) document;
+        pparams.nodePos = nodePos;
+        pparams.childQueue = childQueue;
+        
+        while (! isNodeEndMarker(ttype)) {
+            
+            // Do a partial parse and check the result
+            int ppr = doPartialParse(pparams, state);
+            nextChild = childQueue.peek();
+            if (ppr == PP_ENDS_NODE || ppr == PP_ENDS_NODE_AFTER || (ppr == PP_INCOMPLETE
+                    && last.getType() != JavaTokenTypes.EOF)) {
+                int pos;
+                if (ppr == PP_ENDS_NODE_AFTER) {
+                    pos = lineColToPos(document, last.getEndLine(), last.getEndColumn());
+                }
+                else {
+                    pos = lineColToPos(document, last.getLine(), last.getColumn());
+                }
+                pparams.document.markSectionParsed(offset, pos - offset);
+                int newsize = pos - nodePos;
+                if (! complete) {
+                    pparams.document.scheduleReparse(nodePos + newsize, 0);
+                }
+                complete = (ppr != PP_INCOMPLETE);
+                int oldSize = getSize();
+                endNodeCleanup(pparams, state, Integer.MAX_VALUE, nodePos + newsize);
+                if (newsize != oldSize) {
+                    setSize(newsize);
+                    nap = new NodeAndPosition<ParsedNode>(this, nodePos, newsize);
+                    listener.nodeChangedLength(nap, nodePos, oldSize);
+                    return NODE_SHRUNK;
+                }
+                return ALL_OK;
+            }
+            else if (ppr == PP_INCOMPLETE) {
+                // Due to check above, we can be sure that last is the EOF token.
+                if (parseEnd != nodePos + getSize()) {
+                    // Partial parse - we should just re-schedule.
+                    pparams.document.scheduleReparse(parseEnd, 0);
+                    pparams.document.markSectionParsed(offset, parseEnd - offset);
+                    return ALL_OK;
+                }
+                complete = false;
+                // Fall through to EOF condition below
+            }
+            else if (ppr == PP_EPIC_FAIL) {
+                removeOverwrittenChildren(childQueue, Integer.MAX_VALUE, listener);
+                return REMOVE_NODE;
+            }
+            else if (ppr == PP_ENDS_STATE || ppr == PP_BEGINS_NEXT_STATE) {
+                int pos;
+                if (ppr == PP_ENDS_STATE) {
+                    pos = lineColToPos(document, last.getEndLine(), last.getEndColumn());
+                }
+                else {
+                    pos = lineColToPos(document, last.getLine(), last.getColumn());
+                }
+                if (stateMarkers[state] == (pos - nodePos)) {
+                    // We transitioned to the existing state border.
+                    nextChild = removeOverwrittenChildren(childQueue, pos, listener);
+                    processChildQueue(nodePos, childQueue, nextChild);
+                    parser.completedNode(this, nodePos, pos - nodePos);
+                    pparams.document.markSectionParsed(offset, pos - offset);
+                    return ALL_OK;
+                }
+                stateMarkers[state] = pos - nodePos;
+                marksEnd[state] = (ppr == PP_ENDS_STATE);
+                state++;
+                nextStatePos = (state < stateMarkers.length) ? stateMarkers[state] : -1;
+            }
+            else if (ppr == PP_REGRESS_STATE) {
+                state--;
+                int rppos = stateMarkers[state] + nodePos;
+                pparams.document.scheduleReparse(rppos, Math.max(offset - rppos, 0));
+                stateMarkers[state] = -1;
+                int epos = lineColToPos(document, last.getLine(), last.getColumn());
+                removeOverwrittenChildren(childQueue, epos, listener);
+                processChildQueue(nodePos, childQueue, nextChild);
+                return ALL_OK;
+            }
+            else if (ppr == PP_PULL_UP_CHILD) {
+                nextChild = childQueue.peek();
+                processChildQueue(nodePos, childQueue, nextChild);
+                parser.completedNode(this, nodePos, pparams.abortPos - nodePos);
+                tokpos = lineColToPos(document, last.getLine(), last.getColumn());
+                int ncpos = nextChild.getPosition();
+                if (ncpos != pparams.abortPos) {
+                    int slideAmount = nextChild.getPosition() - pparams.abortPos;
+                    
+                    nextChild.slide(-slideAmount); // move, and insert text next
+                    // There is some parsing to do in the child:
+                    int rr = nextChild.getNode().textInserted((MoeSyntaxDocument) document,
+                            nextChild.getPosition(),
+                            nextChild.getPosition(),
+                            slideAmount, listener);
+                    if (rr == ParsedNode.REMOVE_NODE) {
+                        removeChild(nextChild, listener);
+                    }
+                    else {
+                        nextChild.setNapSize(nextChild.getNode().getSize());
+                        childResized(pparams.document, nodePos, nextChild);
+                    }
+                    
+                    listener.nodeChangedLength(nextChild, ncpos, nextChild.getSize() - slideAmount);
+                    // Note we do not process any more comments into the child node: these will be
+                    // picked up by the child automatically, in textInserted() or as a result of it.
+                    //parser.completedNode(nextChild.getNode(), nextChild.getPosition(), epos - pparams.abortPos);
+                    pparams.document.scheduleReparse(nextChild.getPosition(), slideAmount);
+                }
+                pparams.document.markSectionParsed(offset, pparams.abortPos - offset);
+                return ALL_OK;
+            }
+            else if (ppr == PP_ABORT) {
+                nextChild = removeOverwrittenChildren(childQueue, pparams.abortPos, listener);
+                processChildQueue(nodePos, childQueue, nextChild);
+                parser.completedNode(this, nodePos, pparams.abortPos - nodePos);
+                pparams.document.markSectionParsed(offset, pparams.abortPos - offset);
+                return ALL_OK;
+            }
+            
+            LocatableToken nlaToken = parser.getTokenStream().LA(1);
+            if (nlaToken == laToken) {
+                // We didn't manage to parse anything?
+                parser.getTokenStream().nextToken();
+                nlaToken = parser.getTokenStream().LA(1);
+            }
+            
+            // If we've overwritten state markers / old children, invalidate them.
+            int nlaPos = lineColToPos(document, nlaToken.getLine(), nlaToken.getColumn());
+            for (int i = state; i < stateMarkers.length; i++) {
+                if (stateMarkers[i] + nodePos < nlaPos) {
+                    stateMarkers[i] = -1;
+                }
+            }
+                        
+            if (nlaToken.getType() == JavaTokenTypes.EOF) {
+                endNodeCleanup(pparams, state, parseEnd, parseEnd);
+                processChildQueue(nodePos, childQueue, childQueue.peek());
+                if (parseEnd < nodePos + getSize()) {
+                    // We had limited the parse amount deliberately. Schedule a continuation.
+                    parser.completedNode(this, nodePos, getSize());
+                    pparams.document.markSectionParsed(offset, parseEnd - offset);
+                    pparams.document.scheduleReparse(parseEnd, 0);
+                    return ALL_OK;
+                }
+                if (! complete) {
+                    // The parsed piece wants more...
+                    ParsedNode parentNode = getParentNode();
+                    if (parentNode != null && parentNode.growChild(document,
+                            new NodeAndPosition<ParsedNode>(this, nodePos, getSize()), listener)) {
+                        // Successfully grew... now do some more parsing
+                        pparams.document.markSectionParsed(offset, parseEnd - offset);
+                        pparams.document.scheduleReparse(parseEnd, nodePos + getSize() - parseEnd);
+                        return NODE_GREW;
+                    }
+                    else if (nodePos + getSize() < document.getLength()) {
+                        // No option but to reparse the parent node.
+                        return REMOVE_NODE;
+                    }
+                }
+                pparams.document.markSectionParsed(offset, parseEnd - offset);
+                return checkEnd(document, nodePos, listener);
+            }
+            
+            laToken = nlaToken;
+            ttype = laToken.getType();
+            tokpos = nlaPos;
+        }
+
+        removeOverwrittenChildren(childQueue, Integer.MAX_VALUE, listener);
+        tokpos = lineColToPos(document, laToken.getLine(), laToken.getColumn());
+        pparams.document.markSectionParsed(offset, tokpos - offset);
+        // Did we shrink?
+        int newsize = tokpos - nodePos;
+        parser.completedNode(this, nodePos, newsize);
+        if (! complete) {
+            pparams.document.scheduleReparse(nodePos + newsize, 0);
+        }
+        complete = true;
+        int oldSize = getSize();
+        if (newsize < oldSize) {
+            setSize(newsize);
+            nap = new NodeAndPosition<ParsedNode>(this, nodePos, newsize);
+            listener.nodeChangedLength(nap, nodePos, oldSize);
+            return NODE_SHRUNK;
+        }
+        
+        return ALL_OK;
+    }
+    
+    /**
+     * Check whether the next token is the boundary (beginning) of a delimiting node, in which
+     * case we may be able to finish re-parsing. Returns true if a boundary has been reached;
+     * in this case params.abortpos will be set appropriately.
+     * This is intended as a utility for use by subclasses.
+     */
+    protected boolean checkBoundary(ParseParams params, LocatableToken token)
+    {
+        int lpos = lineColToPos(params.document, token.getLine(), token.getColumn());
+        int hpos = lpos;
+
+        LocatableToken hidden = token.getHiddenBefore();
+        if (hidden != null) {
+            hpos = lineColToPos(params.document, hidden.getLine(), hidden.getColumn());
+        }
+        
+        NodeAndPosition<ParsedNode> nextChild = params.childQueue.peek();
+        while (nextChild != null) {
+            if (isDelimitingNode(nextChild)) {
+                boolean hasComment = nextChild.getNode().isCommentAttached();
+                if (hasComment && nextChild.getPosition() == hpos) {
+                    params.abortPos = hpos;
+                    return true;
+                }
+
+                if (!hasComment && nextChild.getPosition() == lpos) {
+                    int nextType = nextChild.getNode().getNodeType();
+                    boolean wantsComment = nextType == ParsedNode.NODETYPE_TYPEDEF
+                        || nextType == ParsedNode.NODETYPE_METHODDEF;
+                    params.abortPos = wantsComment ? hpos : lpos;
+                    return true;
+                }
+            }
+            
+            if (nextChild.getPosition() > lpos) {
+                break;
+            }
+            childRemoved(nextChild, params.listener);
+            params.childQueue.poll();
+            nextChild = params.childQueue.peek();
+        }
+        return false;
+    }
+    
+    /**
+     * Perform some general cleanup after a parse operation. Overwritten children are removed,
+     * Overwritten state markers are invalidated; comments seen by the parser are added as
+     * children of this node.
+     * 
+     * @param params The parse parameters
+     * @param state  The current parse state
+     * @param rpos   The point up to which overwritten children and state markers should be removed
+     * @param epos   The position where the parse ended
+     */
+    private void endNodeCleanup(ParseParams params, int state, int rpos, int epos)
+    {
+        while (state < stateMarkers.length) {
+            if (stateMarkers[state] < rpos || stateMarkers[state] == rpos && marksEnd[state]) {
+                stateMarkers[state] = -1;
+            }
+            state++;
+        }
+        removeOverwrittenChildren(params.childQueue, rpos, params.listener);
+        params.parser.completedNode(this, params.nodePos, epos - params.nodePos);
+    }
+    
+    private Stack<JavaParentNode> buildScopeStack()
+    {
+        Stack<JavaParentNode> r = new Stack<JavaParentNode>();
+        JavaParentNode pn = this;
+        do {
+            r.add(0, pn);
+            pn = pn.getParentNode();
+        } while (pn != null);
+        
+        return r;
+    }
+    
+    /**
+     * If during parsing we reach some point (epos) then we have overwritten any old child nodes
+     * which overlap or occur before epos and so we need to remove them properly.
+     */
+    private NodeAndPosition<ParsedNode> removeOverwrittenChildren(LinkedList<NodeAndPosition<ParsedNode>> childQueue,
+            int epos, NodeStructureListener listener)
+    {
+        NodeAndPosition<ParsedNode> nextChild = childQueue.peek();
+        while (nextChild != null && (epos > nextChild.getPosition() || epos >= nextChild.getEnd())) {
+            // Remove nextChild, we've eaten into it.
+            childRemoved(nextChild, listener);
+            childQueue.removeFirst();
+            nextChild = childQueue.peek();
+        }
+        
+        return nextChild;
+    }
+    
+    /**
+     * Restore children in the child queue which were removed temporarily, but not actually overwritten during parsing.
+     */
+    private void processChildQueue(int nodePos, LinkedList<NodeAndPosition<ParsedNode>> childQueue,
+            NodeAndPosition<ParsedNode> nextChild)
+    {
+        while (nextChild != null) {
+            insertNode(nextChild.getNode(), nextChild.getPosition() - nodePos, nextChild.getSize());
+            childQueue.removeFirst();
+            nextChild = childQueue.peek();
+        }
+    }
+    
+    /**
+     * Convert a line and column number to an absolute position.
+     */
+    protected static int lineColToPos(Document document, int line, int col)
+    {
+        return document.getDefaultRootElement().getElement(line - 1).getStartOffset() + col - 1;
+    }
+    
+    private int getCurrentState(int pos)
+    {
+        for (int i = stateMarkers.length - 1; i >= 0; i--) {
+            if (pos >= stateMarkers[i] && stateMarkers[i] >= 0) {
+                return i + 1;
+            }
+        }
+        return 0;
+    }
+    
+    @Override
+    public int textInserted(MoeSyntaxDocument document, int nodePos, int insPos,
+            int length, NodeStructureListener listener)
+    {
+        for (int i = 0; i < stateMarkers.length; i++) {
+            if (stateMarkers[i] > (insPos - nodePos)
+                    || (stateMarkers[i] == (insPos - nodePos) && !marksEnd[i])) {
+                stateMarkers[i] += length;
+                for (; i < stateMarkers.length; i++) {
+                    if (stateMarkers[i] >= 0) {
+                        stateMarkers[i] += length;
+                    }
+                }
+                break;
+            }
+        }
+        int result = super.textInserted(document, nodePos, insPos, length, listener);
+        return result;
+    }
+    
+    @Override
+    public int textRemoved(MoeSyntaxDocument document, int nodePos, int delPos,
+            int length, NodeStructureListener listener)
+    {
+        for (int i = 0; i < stateMarkers.length; i++) {
+            if (stateMarkers[i] > (delPos - nodePos) || (marksEnd[i] && stateMarkers[i] == (delPos - nodePos))) {
+                stateMarkers[i] -= length;
+                if (stateMarkers[i] < (delPos - nodePos)
+                        || (stateMarkers[i] == (delPos - nodePos) && marksEnd[i])) {
+                    // The removed text straddles the state marker
+                    stateMarkers[i] = -1;
+                }
+                else if (stateMarkers[i] == (delPos - nodePos)) {
+                    // The text was removed right at the end of a state;
+                    // reparse a bit before to prevent reparsing the wrong
+                    // state:
+                    int spos = (i == 0) ? 0 : Math.max(stateMarkers[i-1], 0);
+                    NodeAndPosition<ParsedNode> nap = getNodeTree().findNodeAtOrBefore(stateMarkers[i] - 1 + nodePos, nodePos);
+                    if (nap != null && isDelimitingNode(nap)) {
+                        // Note in some cases the node will overlap the statemarker, as the node
+                        // hasn't yet been shrunk. That should be ok; the node will handle the
+                        // parse.
+                        spos = Math.max(spos, nap.getEnd() - nodePos);
+                    }
+                    if (stateMarkers[i] > spos) {
+                        // See comment above; this is conditional because the child node might
+                        // overlap the state marker.
+                        document.scheduleReparse(spos + nodePos, stateMarkers[i] - spos);
+                    }
+                }
+            }
+        }
+        return super.textRemoved(document, nodePos, delPos, length, listener);
+    }
+    
+    /**
+     * Check if a single line comment exists at the end of this node, which is not properly
+     * terminated - that is, it ends before the end of the line. This can happen if such a
+     * comment is inserted into an existing node which ends on the same line.
+     */
+    private int checkEnd(Document document, int nodePos, NodeStructureListener listener)
+    {
+        int end = nodePos + getSize();
+        if (end >= document.getLength()) {
+            return ALL_OK;
+        }
+        NodeAndPosition<ParsedNode> nap = findNodeAt(end - 1, nodePos);
+        if (nap == null) {
+            return ALL_OK;
+        }
+        int offset = nap.getPosition();
+        if (offset + nap.getSize() < end
+                || nap.getNode().getNodeType() != ParsedNode.NODETYPE_COMMENT) {
+            // The final child node isn't a comment, or it ends before the end of this node.
+            return ALL_OK;
+        }
+        
+        Reader r = new DocumentReader(document, offset, nodePos + getSize());
+        EscapedUnicodeReader eur = new EscapedUnicodeReader(r);
+        try {
+            if (eur.read() == '/' && eur.read() == '/') {
+                // It's a single-line comment
+                String str = document.getText(end, 1);
+                if (str.charAt(0) != '\n') {
+                    // The comment should extend to the end of the line, but it doesn't.
+                    ParsedNode parentNode = getParentNode();
+                    if (parentNode != null && parentNode.growChild(document,
+                            new NodeAndPosition<ParsedNode>(this, nodePos, getSize()), listener)) {
+                        // Successfully grew... now do some more parsing
+                        int pr = reparseNode(document, nodePos, offset, getSize(), listener);
+                        return pr == ALL_OK ? NODE_GREW : pr;
+                    }
+                    return REMOVE_NODE;
+                }
+            }
+        }
+        catch (IOException ioe) {}
+        catch (BadLocationException ble) {
+            // We might actually get this, but it's fine to return.
+        }
+        return ALL_OK;
+    }
+    
+    @Override
+    protected int handleDeletion(Document document, int nodePos, int dpos,
+            NodeStructureListener listener)
+    {
+        int offset = dpos;
+        int state = getCurrentState(offset - nodePos);
+        
+        // Find the nearest container node or state boundary prior to the reparse point.
+        int stateBoundary = (state != 0) ? stateMarkers[state - 1] + nodePos : nodePos;
+        NodeAndPosition<ParsedNode> nap = null;
+        
+        if (offset > stateBoundary) {
+            nap = getNodeTree().findNodeAtOrBefore(offset, nodePos);
+            while (nap != null && nap.getSize() == 0) {
+                // Remove 0-size nodes at the delete position
+                NodeAndPosition<ParsedNode> pnap = nap.prevSibling();
+                removeChild(nap, listener);
+                nap = pnap;
+            }
+            
+            while (nap != null && nap.getEnd() > dpos) {
+                nap = nap.prevSibling();
+            }
+            
+            while (nap != null && !isDelimitingNode(nap)) {
+                boolean isLeadingComment = nap != null && nap.getNode().getNodeType() == ParsedNode.NODETYPE_COMMENT
+                        && nap.getPosition() == stateBoundary;
+                if (isLeadingComment) {
+                    break;
+                }
+                
+                if (nap.getPosition() >= stateBoundary) {
+                    NodeAndPosition<ParsedNode> pnap = nap.prevSibling();
+                    if (pnap != null && isDelimitingNode(pnap) && pnap.getEnd() == dpos && nap.getPosition() == dpos) {
+                        // Special case: two nodes have been collapsed together
+                        removeChild(nap, listener);
+                        return super.handleDeletion(document, nodePos, dpos, listener);
+                    }
+                    nap = pnap;
+                }
+                else {
+                    nap = null;
+                }
+            }
+        }
+        
+        int adjustedPos = (nap != null) ? nap.getEnd() : stateBoundary;
+        return super.handleDeletion(document, nodePos, adjustedPos, listener);
+    }
+    
+    @Override
+    protected boolean growChild(Document document, NodeAndPosition<ParsedNode> child,
+            NodeStructureListener listener)
+    {
+        int mypos = child.getPosition() - child.getNode().getOffsetFromParent();
+        int oldSize = child.getSize();
+        
+        NodeAndPosition<ParsedNode> nap = child.nextSibling();
+        if (nap != null && nap.getPosition() > child.getEnd()) {
+            int newSize = nap.getPosition() - child.getPosition();
+            child.setSize(newSize);
+            childResized((MoeSyntaxDocument)document, mypos, child);
+            listener.nodeChangedLength(child, child.getPosition(), oldSize);
+            return true;
+        }
+        
+        int myEnd = mypos + getSize();
+        if (nap != null) {
+            // Next child is pushing up against the one which wants to grow - so we'll
+            // have to remove it.
+            removeChild(nap, listener);
+            child.setSize(nap.getEnd() - child.getPosition());
+            if (myEnd == nap.getEnd() && marksOwnEnd()) {
+                complete = false;
+            }
+            childResized((MoeSyntaxDocument)document, mypos, child);
+            listener.nodeChangedLength(child, child.getPosition(), oldSize);
+            return true;
+        }
+        
+        // The child can soak up anything remaining at the end of this node.
+        if (myEnd > child.getEnd()) {
+            int newsize = myEnd - child.getPosition();
+            child.resize(newsize);
+            if (marksOwnEnd()) {
+                complete = false;
+            }
+            childResized((MoeSyntaxDocument)document, mypos, child);
+            listener.nodeChangedLength(child, child.getPosition(), oldSize);
+            return true;
+        }
+        
+        // Maybe this node can grow, and then its child can also grow.
+        ParsedNode parentNode = getParentNode();
+        if (parentNode != null && parentNode.growChild(document,
+                new NodeAndPosition<ParsedNode>(this, mypos, getSize()), listener)) {
+            myEnd = mypos + getSize();
+            ((MoeSyntaxDocument) document).scheduleReparse(myEnd, 0);
+            complete = false;
+            int newsize = myEnd - child.getPosition();
+            child.resize(newsize);
+            childResized((MoeSyntaxDocument)document, mypos, child);
+            listener.nodeChangedLength(child, child.getPosition(), oldSize);
+            return true;
+        }
+        
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/InnerNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/InnerNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..685d8fa1ba19bae46cc55bd11371382feacfac14
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/InnerNode.java
@@ -0,0 +1,87 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.PackageOrClass;
+import bluej.parser.entity.ParsedReflective;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.entity.ValueEntity;
+
+/**
+ * A generic "inner" representation (for eg. loop bodies)
+ * 
+ * @author Davin McCall
+ */
+public class InnerNode extends JavaParentNode
+{
+    public InnerNode(JavaParentNode parent)
+    {
+        super(parent);
+    }
+    
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return false;
+    }
+    
+    @Override
+    public JavaEntity getValueEntity(String name, Reflective querySource, int fromPosition)
+    {
+        FieldNode var = variables.get(name);
+        if (var != null && var.getOffsetFromParent() <= fromPosition) {
+            JavaEntity fieldType = var.getFieldType().resolveAsType();
+            if (fieldType != null) {
+                return new ValueEntity(fieldType.getType());
+            }
+        }
+        
+        JavaEntity rval = null;
+        if (parentNode != null) {
+            rval = parentNode.getValueEntity(name, querySource, getOffsetFromParent());
+        }
+        
+        if (rval == null) {
+            rval = resolvePackageOrClass(name, querySource, fromPosition);
+        }
+        
+        return rval;
+    }
+    
+    @Override
+    public PackageOrClass resolvePackageOrClass(String name,
+            Reflective querySource, int fromPosition)
+    {
+        ParsedNode cnode = classNodes.get(name);
+        if (cnode != null && cnode.getOffsetFromParent() <= fromPosition) {
+            return new TypeEntity(new ParsedReflective((ParsedTypeNode) cnode));
+        }
+        
+        PackageOrClass rval = null;
+        if (parentNode != null) {
+            rval = parentNode.resolvePackageOrClass(name, querySource);
+        }
+        return rval;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/JavaParentNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/JavaParentNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ef6c08604f81cd837437b5f442e3ee1259451d1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/JavaParentNode.java
@@ -0,0 +1,460 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.Reflective;
+import bluej.editor.moe.Token;
+import bluej.parser.CodeSuggestions;
+import bluej.parser.DocumentReader;
+import bluej.parser.JavaParser;
+import bluej.parser.TokenStream;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.PackageOrClass;
+import bluej.parser.entity.ParsedReflective;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.entity.ValueEntity;
+import bluej.parser.lexer.JavaLexer;
+import bluej.parser.lexer.JavaTokenFilter;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+import bluej.utility.GeneralCache;
+
+/**
+ * A ParentParsedNode extension with Java specific functionality.
+ * Amongst other things this extends the ParsedNode into an
+ * EntityResolver implementation.
+ * 
+ * @author Davin McCall
+ */
+public abstract class JavaParentNode extends ParentParsedNode
+    implements EntityResolver
+{
+    protected GeneralCache<String,JavaEntity> valueEntityCache =
+        new GeneralCache<String,JavaEntity>(10);
+    protected GeneralCache<String,PackageOrClass> pocEntityCache =
+        new GeneralCache<String,PackageOrClass>(10);
+
+    protected JavaParentNode parentNode;
+    
+    protected Map<String,ParsedNode> classNodes = new HashMap<String,ParsedNode>();
+    protected Map<String,FieldNode> variables = new HashMap<String,FieldNode>();
+
+    public JavaParentNode(JavaParentNode parent)
+    {
+        super(parent);
+        parentNode = parent;
+    }
+    
+    @Override
+    protected JavaParentNode getParentNode()
+    {
+        return parentNode;
+    }
+    
+    @Override
+    public void insertNode(ParsedNode child, int position, int size)
+    {
+        getNodeTree().insertNode(child, position, size);
+        int childType = child.getNodeType();
+        String childName = child.getName();
+        if (childName != null) {
+            if (childType == NODETYPE_TYPEDEF) {
+                classNodes.put(childName, child);
+            }
+        }
+    }
+    
+    /**
+     * Insert a FieldNode representing a variable/field declaration into this node.
+     */
+    public void insertVariable(FieldNode varNode, int pos, int size)
+    {
+        super.insertNode(varNode, pos, size);
+        if (! variables.containsKey(varNode.getName())) {
+            variables.put(varNode.getName(), varNode);
+        }
+    }
+    
+    /**
+     * Insert a field child (alias for insertVariable).
+     */
+    public void insertField(FieldNode child, int position, int size)
+    {
+        insertVariable(child, position, size);
+    }
+    
+    @Override
+    public void childChangedName(ParsedNode child, String oldName)
+    {
+        super.childChangedName(child, oldName);
+        if (child.getNodeType() == NODETYPE_TYPEDEF) {
+            if (classNodes.get(oldName) == child) {
+                classNodes.remove(oldName);
+            }
+            classNodes.put(child.getName(), child);
+        }
+        if (child.getNodeType() == NODETYPE_FIELD) {
+            if (variables.get(oldName) == child) {
+                variables.remove(oldName);
+            }
+            variables.put(child.getName(), (FieldNode) child);
+        }
+    }
+
+    @Override
+    protected void childRemoved(NodeAndPosition<ParsedNode> child,
+            NodeStructureListener listener)
+    {
+        super.childRemoved(child, listener);
+        String childName = child.getNode().getName();
+        if (childName != null) {
+            if (classNodes.get(childName) == child.getNode()) {
+                classNodes.remove(childName);
+            }
+            if (variables.get(childName) == child.getNode()) {
+                variables.remove(childName);
+            }
+        }
+    }
+    
+    /**
+     * Find a type node for a type definition with the given name.
+     */
+    public ParsedNode getTypeNode(String name)
+    {
+        return classNodes.get(name);
+    }
+
+    // =================== EntityResolver interface ====================
+    
+    /*
+     * @see bluej.parser.entity.EntityResolver#resolveQualifiedClass(java.lang.String)
+     */
+    public TypeEntity resolveQualifiedClass(String name)
+    {
+        if (parentNode != null) {
+            return parentNode.resolveQualifiedClass(name);
+        }
+        return null;
+    }
+    
+    /*
+     * @see bluej.parser.entity.EntityResolver#resolvePackageOrClass(java.lang.String, java.lang.String)
+     */
+    public PackageOrClass resolvePackageOrClass(String name, Reflective querySource)
+    {
+        ParsedNode cnode = classNodes.get(name);
+        if (cnode != null) {
+            return new TypeEntity(new ParsedReflective((ParsedTypeNode) cnode));
+        }
+        
+        String accessp = name + ":" + (querySource != null ? querySource.getName() : ""); 
+        PackageOrClass rval = pocEntityCache.get(accessp);
+        if (rval != null || pocEntityCache.containsKey(accessp)) {
+            return rval;
+        }
+        
+        if (parentNode != null) {
+            rval = parentNode.resolvePackageOrClass(name, querySource);
+            pocEntityCache.put(accessp, rval);
+        }
+        return rval;
+    }
+    
+    /**
+     * Resolve a package or type, based on what is visible from the given position in the node.
+     * This allows for forward declarations not being visible.
+     */
+    public PackageOrClass resolvePackageOrClass(String name, Reflective querySource, int fromPosition)
+    {
+        return resolvePackageOrClass(name, querySource);
+    }
+    
+    /*
+     * @see bluej.parser.entity.EntityResolver#getValueEntity(java.lang.String, java.lang.String)
+     */
+    public JavaEntity getValueEntity(String name, Reflective querySource)
+    {
+        FieldNode var = variables.get(name);
+        if (var != null) {
+            JavaEntity fieldType = var.getFieldType().resolveAsType();
+            if (fieldType != null) {
+                return new ValueEntity(fieldType.getType());
+            }
+        }
+        
+        String accessp = name + ":" + (querySource != null ? querySource.getName() : ""); 
+        JavaEntity rval = valueEntityCache.get(accessp);
+        if (rval != null || valueEntityCache.containsKey(accessp)) {
+            return rval;
+        }
+        
+        if (parentNode != null) {
+            rval = parentNode.getValueEntity(name, querySource, getOffsetFromParent());
+        }
+        
+        if (rval == null) {
+            rval = resolvePackageOrClass(name, querySource, getOffsetFromParent());
+        }
+        
+        valueEntityCache.put(accessp, rval);
+        return rval;
+    }
+    
+    /**
+     * Resolve a value, based on what is visible from a given position within the node.
+     * This allows for forward declarations not being visible.
+     */
+    public JavaEntity getValueEntity(String name, Reflective querySource, int fromPosition)
+    {
+        return getValueEntity(name, querySource);
+    }
+    
+    @Override
+    protected CodeSuggestions getExpressionType(int pos, int nodePos, JavaEntity defaultType, Document document)
+    {
+        // Clear the caches now to remove any entries which have become invalid due
+        // to editing.
+        valueEntityCache.clear();
+        pocEntityCache.clear();
+        
+        NodeAndPosition<ParsedNode> child = getNodeTree().findNodeAtOrBefore(pos, nodePos);
+        if (child != null && child.getEnd() >= pos) {
+            return child.getNode().getExpressionType(pos, child.getPosition(), defaultType, document);
+        }
+        
+        int startpos = nodePos;
+        if (child != null) {
+            startpos = child.getEnd();
+        }
+        
+        // We want to find the relevant suggestion token.
+        
+        Element map = document.getDefaultRootElement();
+        int line = map.getElementIndex(pos) + 1;
+        Element lineEl = map.getElement(line - 1);
+        startpos = Math.max(startpos, lineEl.getStartOffset());
+        int col = startpos - map.getElement(line - 1).getStartOffset() + 1;
+        Reader r = new DocumentReader(document, startpos, pos);
+        
+        JavaLexer lexer = new JavaLexer(r, line, col, startpos);
+        JavaTokenFilter filter = new JavaTokenFilter(lexer);
+        LocatableToken token = filter.nextToken();
+        LocatableToken prevToken = null;
+        while (token.getType() != JavaTokenTypes.EOF) {
+            prevToken = token;
+            token = filter.nextToken();
+        }
+        
+        if (prevToken != null && prevToken.getEndLine() != token.getEndLine()) {
+            if (prevToken.getEndColumn() != token.getEndColumn()) {
+                // If the token doesn't end right at the completion point, it's not used.
+                prevToken = null;
+            }
+        }
+        
+        if (prevToken != null && startpos == nodePos) {
+            // The completion position is at the end of some token.
+            // The parent might have a prior expression sibling which might end in a dot.
+            int offset = getOffsetFromParent();
+            int ppos = nodePos - offset;
+            child = parentNode.getNodeTree().findNodeAtOrBefore(nodePos - 1, ppos);
+            if (child != null && child.getNode().getNodeType() == ParsedNode.NODETYPE_EXPRESSION
+                    && child.getEnd() == nodePos) {
+                CodeSuggestions suggests = ExpressionNode.suggestAsExpression(pos, child.getPosition(),
+                        this, defaultType, document);
+                if (suggests != null) {
+                    return suggests;
+                }
+            }
+        }
+        
+        // No identifiable expression. The suggestion type is the enclosing type.
+        
+        GenTypeClass atype = (defaultType != null) ? defaultType.getType().asClass() : null;
+        if (atype == null) {
+            return null;
+        }
+        boolean isStaticCtxt = (defaultType.resolveAsType() != null);
+        if (prevToken != null && ! Character.isJavaIdentifierPart(prevToken.getText().codePointAt(0))) {
+            prevToken = null;
+        }
+        return new CodeSuggestions(atype, atype, prevToken, isStaticCtxt);
+    }
+
+    @Override
+    public Token getMarkTokensFor(int pos, int length, int nodePos,
+            Document document)
+    {
+        Token tok = new Token(0, Token.END); // dummy
+        if (length == 0) {
+            return tok;
+        }
+        Token dummyTok = tok;
+        
+        NodeAndPosition<ParsedNode> np = getNodeTree().findNodeAtOrAfter(pos, nodePos);
+        while (np != null && np.getEnd() == pos) np = np.nextSibling(); 
+        
+        int cp = pos;
+        while (np != null && np.getPosition() < (pos + length)) {
+            if (cp < np.getPosition()) {
+                int nextTokLen = np.getPosition() - cp;
+                tok.next = tokenizeText(document, cp, nextTokLen);
+                while (tok.next.id != Token.END) tok = tok.next;
+                cp = np.getPosition();
+            }
+            
+            int remaining = pos + length - cp;
+            remaining = Math.min(remaining, np.getEnd() - cp);
+            
+            if (remaining != 0) {
+                tok.next = np.getNode().getMarkTokensFor(cp, remaining, np.getPosition(), document);
+                cp += remaining;
+                while (tok.next.id != Token.END) {
+                    tok = tok.next;
+                }
+            }
+            np = np.nextSibling();
+        }
+        
+        // There may be a section left
+        if (cp < pos + length) {
+            int nextTokLen = pos + length - cp;
+            tok.next = tokenizeText(document, cp, nextTokLen);
+            while (tok.next.id != Token.END) tok = tok.next;
+        }
+
+        tok.next = new Token(0, Token.END);
+        return dummyTok.next;
+    }
+    
+    protected static Token tokenizeText(Document document, int pos, int length)
+    {
+        DocumentReader dr = new DocumentReader(document, pos, pos+length);
+        TokenStream lexer = JavaParser.getLexer(dr);
+        TokenStream tokenStream = new JavaTokenFilter(lexer, null);
+
+        Token dummyTok = new Token(0, Token.END);
+        Token token = dummyTok;
+        
+        int curcol = 1;
+        while (length > 0) {
+            LocatableToken lt = (LocatableToken) tokenStream.nextToken();
+
+            if (lt.getLine() > 1 || lt.getColumn() - curcol >= length) {
+                token.next = new Token(length, Token.NULL);
+                token = token.next;
+                break;
+            }
+            if (lt.getColumn() > curcol) {
+                // some space before the token
+                token.next = new Token(lt.getColumn() - curcol, Token.NULL);
+                token = token.next;
+                length -= token.length;
+                curcol += token.length;
+            }
+
+            byte tokType = Token.NULL;
+            if (JavaParser.isPrimitiveType(lt)) {
+                tokType = Token.PRIMITIVE;
+            }
+            else if (JavaParser.isModifier(lt)) {
+                tokType = Token.KEYWORD1;
+            }
+            else if (lt.getType() == JavaTokenTypes.STRING_LITERAL) {
+                tokType = Token.LITERAL1;
+            }
+            else if (lt.getType() == JavaTokenTypes.CHAR_LITERAL) {
+                tokType = Token.LITERAL2;
+            }
+            else {
+                switch (lt.getType()) {
+                case JavaTokenTypes.LITERAL_assert:
+                case JavaTokenTypes.LITERAL_for:
+                case JavaTokenTypes.LITERAL_switch:
+                case JavaTokenTypes.LITERAL_while:
+                case JavaTokenTypes.LITERAL_do:
+                case JavaTokenTypes.LITERAL_try:
+                case JavaTokenTypes.LITERAL_catch:
+                case JavaTokenTypes.LITERAL_throw:
+                case JavaTokenTypes.LITERAL_throws:
+                case JavaTokenTypes.LITERAL_finally:
+                case JavaTokenTypes.LITERAL_return:
+                case JavaTokenTypes.LITERAL_case:
+                case JavaTokenTypes.LITERAL_default:
+                case JavaTokenTypes.LITERAL_break:
+                case JavaTokenTypes.LITERAL_continue:
+                case JavaTokenTypes.LITERAL_if:
+                case JavaTokenTypes.LITERAL_else:
+                case JavaTokenTypes.LITERAL_new:
+                    tokType = Token.KEYWORD1;
+                    break;
+
+                case JavaTokenTypes.LITERAL_class:
+                case JavaTokenTypes.LITERAL_package:
+                case JavaTokenTypes.LITERAL_import:
+                case JavaTokenTypes.LITERAL_extends:
+                case JavaTokenTypes.LITERAL_interface:
+                case JavaTokenTypes.LITERAL_enum:
+                case JavaTokenTypes.LITERAL_implements:
+                    tokType = Token.KEYWORD2;
+                    break;
+
+                case JavaTokenTypes.LITERAL_this:
+                case JavaTokenTypes.LITERAL_null:
+                case JavaTokenTypes.LITERAL_super:
+                case JavaTokenTypes.LITERAL_true:
+                case JavaTokenTypes.LITERAL_false:
+                    tokType = Token.KEYWORD3;
+                    break;
+                
+                case JavaTokenTypes.LITERAL_instanceof:
+                    tokType = Token.OPERATOR;
+                    break;
+
+                default:
+                }
+            }
+            int toklen = lt.getLength();
+            if (lt.getEndLine() > 1) {
+                toklen = length;
+            }
+            token.next = new Token(toklen, tokType);
+            token = token.next;
+            length -= toklen;
+            curcol += toklen;
+        }
+        
+        token.next = new Token(0, Token.END);
+        return dummyTok.next;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/MethodBodyNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/MethodBodyNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..6e132f2e01477d16b7c735d0d0462ea7f9bff08f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/MethodBodyNode.java
@@ -0,0 +1,131 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.PackageOrClass;
+import bluej.parser.entity.ParsedReflective;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.entity.ValueEntity;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * A node representing a method or constructor inner body (the part between, but not
+ * including, the '{' and '}').
+ * 
+ * @author Davin McCall
+ */
+public class MethodBodyNode extends IncrementalParsingNode
+{    
+    public MethodBodyNode(JavaParentNode parent)
+    {
+        super(parent);
+        complete = true;
+        setInner(true);
+    }
+    
+    @Override
+    protected boolean isDelimitingNode(NodeAndPosition<ParsedNode> nap)
+    {
+        ParsedNode pn = nap.getNode();
+        return pn.isContainer() || pn.getNodeType() == ParsedNode.NODETYPE_FIELD;
+    }
+    
+    @Override
+    protected int doPartialParse(ParseParams params, int state)
+    {
+        last = params.tokenStream.nextToken();
+
+        if (last.getType() == JavaTokenTypes.RCURLY) {
+            return PP_ENDS_NODE;
+        }
+        if (last.getType() == JavaTokenTypes.EOF) {
+            return complete ? PP_OK : PP_INCOMPLETE;
+        }
+        
+        if (checkBoundary(params, last)) {
+            return PP_PULL_UP_CHILD;
+        }
+        
+        last = params.parser.parseStatement(last, false);
+        if (last == null) {
+            last = params.tokenStream.LA(1);
+            if (last.getType() == JavaTokenTypes.EOF) {
+                return PP_INCOMPLETE;
+            }
+        }
+        return PP_OK;
+    }
+        
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return false;
+    }
+    
+    @Override
+    public boolean growsForward()
+    {
+        return true;
+    }
+    
+    @Override
+    public JavaEntity getValueEntity(String name, Reflective querySource, int fromPosition)
+    {
+        FieldNode var = variables.get(name);
+        if (var != null && var.getOffsetFromParent() <= fromPosition) {
+            JavaEntity fieldType = var.getFieldType().resolveAsType();
+            if (fieldType != null) {
+                return new ValueEntity(fieldType.getType());
+            }
+        }
+        
+        JavaEntity rval = null;
+        if (parentNode != null) {
+            rval = parentNode.getValueEntity(name, querySource, getOffsetFromParent());
+        }
+        
+        if (rval == null) {
+            rval = resolvePackageOrClass(name, querySource, fromPosition);
+        }
+        
+        return rval;
+    }
+    
+    @Override
+    public PackageOrClass resolvePackageOrClass(String name,
+            Reflective querySource, int fromPosition)
+    {
+        ParsedNode cnode = classNodes.get(name);
+        if (cnode != null && cnode.getOffsetFromParent() <= fromPosition) {
+            return new TypeEntity(new ParsedReflective((ParsedTypeNode) cnode));
+        }
+        
+        PackageOrClass rval = null;
+        if (parentNode != null) {
+            rval = parentNode.resolvePackageOrClass(name, querySource);
+        }
+        return rval;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/MethodNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/MethodNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..b993049c17e30458731535c01fd079d1d37e9849
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/MethodNode.java
@@ -0,0 +1,269 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.text.Document;
+
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.CodeSuggestions;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.PackageOrClass;
+import bluej.parser.entity.TparEntity;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.entity.ValueEntity;
+
+
+/**
+ * A node representing a parsed method or constructor.
+ * 
+ * @author Davin McCall
+ */
+public class MethodNode extends JavaParentNode
+{
+    private String name;
+    private String javadoc;
+    private JavaEntity returnType;
+    private List<String> paramNames = new ArrayList<String>();
+    private List<JavaEntity> paramTypes = new ArrayList<JavaEntity>();
+    private List<TparEntity> typeParams = null;
+    private boolean isVarArgs = false;
+    private int modifiers = 0;
+    
+    /**
+     * Construct a MethodNode representing a constructor or method.
+     * @param parent  The parent node (containing this node)
+     * @param name    The constructor/method name
+     * @param javadoc The javadoc comment text (or null)
+     */
+    public MethodNode(JavaParentNode parent, String name, String javadoc)
+    {
+        super(parent);
+        this.name = name;
+        this.javadoc = javadoc;
+        setCommentAttached(javadoc != null);
+    }
+
+    /**
+     * Set the return type of this method.
+     * 
+     * <p>(If the returnType is unresolved, it must resolve against type parameters for
+     * this actual method).
+     */
+    public void setReturnType(JavaEntity returnType)
+    {
+        this.returnType = returnType;
+    }
+    
+    /**
+     * Add a method parameter
+     * @param name  The parameter name
+     * @param type  The parameter type
+     */
+    public void addParameter(String name, JavaEntity type)
+    {
+        paramNames.add(name);
+        paramTypes.add(type);
+    }
+    
+    /**
+     * Set the type parameters for this method.
+     */
+    public void setTypeParams(List<TparEntity> typeParams)
+    {
+        this.typeParams = typeParams;
+    }
+    
+    /**
+     * Mark this method as a varargs method (or not).
+     * @param isVarArgs  Whether this method is a varargs method.
+     */
+    public void setVarArgs(boolean isVarArgs)
+    {
+        this.isVarArgs = isVarArgs;
+    }
+    
+    /**
+     * Check whether this method is a varargs method.
+     */
+    public boolean isVarArgs()
+    {
+        return isVarArgs;
+    }
+    
+    /**
+     * Set the modifiers on this method (as per java.lang.reflect.Modifier)
+     */
+    public void setModifiers(int modifiers)
+    {
+        this.modifiers = modifiers;
+    }
+    
+    /**
+     * Get the modifiers on this method (as per java.lang.reflect.Modifier)
+     */
+    public int getModifiers()
+    {
+        return modifiers;
+    }
+    
+    /**
+     * Get the parameter names of this method
+     * @return
+     */
+    public List<String> getParamNames()
+    {
+        return paramNames;
+    }
+    
+    /**
+     * Get the parameter types of this method.
+     */
+    public List<JavaEntity> getParamTypes()
+    {
+        return paramTypes;
+    }
+    
+    /**
+     * Get the javadoc comment text for this node. May return null.
+     */
+    public String getJavadoc()
+    {
+        return javadoc;
+    }
+    
+    @Override
+    public boolean isContainer()
+    {
+        return true;
+    }
+    
+    @Override
+    public int getNodeType()
+    {
+        return ParsedNode.NODETYPE_METHODDEF;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+    
+    /**
+     * Get the return type of the method represented by this node.
+     * Returns a possibly unresolved JavaEntity. For a constructor,
+     * returns null.
+     */
+    public JavaEntity getReturnType()
+    {
+        return returnType;
+    }
+    
+    /**
+     * Get the type parameters for this method.
+     */
+    public List<GenTypeDeclTpar> getTypeParams()
+    {
+        if (typeParams == null) {
+            return null;
+        }
+        
+        List<GenTypeDeclTpar> tparList = new ArrayList<GenTypeDeclTpar>(typeParams.size());
+        for (TparEntity tparEnt : typeParams) {
+            GenTypeDeclTpar tparType = tparEnt.getType();
+            if (tparType != null) {
+                tparList.add(tparType);
+            }
+        }
+        return tparList;
+    }
+    
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return true;
+    }
+    
+    @Override
+    public JavaEntity getValueEntity(String name, Reflective querySource)
+    {
+        JavaEntity paramEntity = getParameterEntity(name, querySource);
+        if (paramEntity != null) {
+            return paramEntity;
+        }
+        return super.getValueEntity(name, querySource);
+    }
+    
+    /**
+     * Look for a value entity in the method parameters.
+     */
+    private JavaEntity getParameterEntity(String name, Reflective querySource)
+    {
+        Iterator<String> i = paramNames.iterator();
+        Iterator<JavaEntity> j = paramTypes.iterator();
+        while (i.hasNext()) {
+            if (i.next().equals(name)) {
+                TypeEntity tent = j.next().resolveAsType();
+                if (tent != null) {
+                    return new ValueEntity(name, tent.getType());
+                }
+                return null;
+            }
+            j.next();
+        }
+        return null;
+    }
+    
+    @Override
+    public PackageOrClass resolvePackageOrClass(String name,
+            Reflective querySource)
+    {
+        if (typeParams != null) {
+            for (TparEntity tpar : typeParams) {
+                if (tpar.getName().equals(name)) {
+                    return tpar.resolveAsType();
+                }
+            }
+        }
+        return super.resolvePackageOrClass(name, querySource);
+    }
+    
+    @Override
+    protected CodeSuggestions getExpressionType(int pos, int nodePos,
+            JavaEntity defaultType, Document document)
+    {
+        if (Modifier.isStatic(modifiers)) {
+            JavaType dtype = defaultType.getType();
+            if (dtype != null) {
+                defaultType = new TypeEntity(dtype);
+            }
+        }
+        return super.getExpressionType(pos, nodePos, defaultType, document);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/NodeStructureListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/NodeStructureListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..33bce577a067b3dabbc4b39c9c15776fb04bb2e0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/NodeStructureListener.java
@@ -0,0 +1,36 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * An interface for listeners to the parse tree structure.
+ * 
+ * @author Davin McCall
+ */
+public interface NodeStructureListener
+{
+    public void nodeRemoved(NodeAndPosition<ParsedNode> node);
+    
+    public void nodeChangedLength(NodeAndPosition<ParsedNode> node, int oldPos, int oldSize);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/NodeTree.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/NodeTree.java
new file mode 100644
index 0000000000000000000000000000000000000000..eb2f766da534f7891fb9cb013acb5b51f9f2e35b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/NodeTree.java
@@ -0,0 +1,959 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.util.Iterator;
+import java.util.function.Consumer;
+
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+
+/**
+ * Represents a set of ParsedNode using a (red/black) tree structure.
+ *
+ * @author davmac
+ */
+public class NodeTree<T extends RBTreeNode<T>>
+{
+    // The following two instance variables specify the position of the contained ParsedNode,
+    // relative to the position that this NodeTree represents.
+    private int pnodeOffset; // offset of the ParsedNode in this tree node from the node start
+    private int pnodeSize; // size of the ParsedNode in this tree node
+
+    private NodeTree<T> parent;
+
+    private NodeTree<T> left;
+    private T pnode;
+    private NodeTree<T> right; // offset pnodeOffset + pnodeSize
+
+    private boolean black;  // true = black, false = red
+
+    /**
+     * Construct an empty node tree.
+     */
+    public NodeTree()
+    {
+        black = true;
+    }
+
+    /**
+     * Get an iterator which iterates through nodes in the tree, in order
+     * 
+     * @param offset  The position of node containing the node tree
+     */
+    public Iterator<NodeAndPosition<T>> iterator(int offset)
+    {
+        return new NodeTreeIterator<T>(offset, this);
+    }
+
+    /**
+     * Find the ParsedNode leaf corresponding to a certain position within the parent.
+     * Returns null if no leaf contains exactly the given position.
+     * 
+     * <p>Note that the leaf range may intersect the position parameter at any point -
+     * start, end, or anywhere in between. The "leftmost" match will always be
+     * returned i.e. if the position falls exactly between two leaves, the leftmost
+     * will be found.
+     */
+    public NodeAndPosition<T> findNode(int pos)
+    {
+        return findNode(pos, 0);
+    }
+
+    public NodeAndPosition<T> findNode(int pos, int startpos)
+    {
+        if (pnode == null) {
+            return null; // empty node tree
+        }
+
+        if (startpos + pnodeOffset >= pos) {
+            NodeAndPosition<T> r = null;
+            if (left != null) {
+                r = left.findNode(pos, startpos);
+            }
+            if (r == null && startpos + pnodeOffset == pos) {
+                // Corner case: we match exactly the starting position.
+                // We favour the leftmost branch in this case, so as
+                // to always return the leftmost matching node.
+                r = new NodeAndPosition<T>(pnode, startpos + pnodeOffset, pnodeSize);
+            }
+            return r;
+        }
+
+        if (startpos + pnodeSize + pnodeOffset >= pos) {
+            return new NodeAndPosition<T>(pnode, startpos + pnodeOffset, pnodeSize);
+        }
+
+        if (right != null) {
+            return right.findNode(pos, startpos + pnodeOffset + pnodeSize);
+        }
+
+        return null;
+    }
+
+    /**
+     * Find the (rightmost) node which occurs at or before the given position.
+     */
+    public NodeAndPosition<T> findNodeAtOrBefore(int pos)
+    {
+        return findNodeAtOrBefore(pos, 0);
+    }
+
+    /**
+     * Find the (rightmost) node at or before the given position (when this node's own position
+     * is given by {@code startpos}).
+     */
+    public NodeAndPosition<T> findNodeAtOrBefore(int pos, int startpos)
+    {
+        if (pnode == null) {
+            return null; // empty node tree
+        }
+
+        if (startpos + pnodeOffset > pos) {
+            if (left != null) {
+                return left.findNodeAtOrBefore(pos, startpos);
+            }
+            else {
+                return null;
+            }
+        }
+
+        if (startpos + pnodeSize + pnodeOffset > pos) {
+            // This node straddles the requested position, so there can't be any other node to our
+            // right which is still at-or-before the position.
+            return new NodeAndPosition<T>(pnode, startpos + pnodeOffset, pnodeSize);
+        }
+
+        NodeAndPosition<T> rval = null;
+        if (right != null) {
+            //pos -= (pnodeOffset + pnodeSize);
+            rval = right.findNodeAtOrBefore(pos, startpos + pnodeOffset + pnodeSize);
+        }
+
+        if (rval == null) {
+            rval = new NodeAndPosition<T>(pnode, startpos + pnodeOffset, pnodeSize);
+        }
+
+        return rval;
+    }
+
+    /**
+     * Find a node ending at or after the given position.
+     * 
+     * @param pos       The position to start the search from
+     */
+    public NodeAndPosition<T> findNodeAtOrAfter(int pos)
+    {
+        return findNodeAtOrAfter(pos, 0);
+    }
+
+    /**
+     * Find a node ending at or after the given position, accounting for this node representing
+     * a specified start position
+     * .
+     * @param pos       The position to start the search from
+     * @param startpos  The offset to assume the tree represents
+     */
+    public NodeAndPosition<T> findNodeAtOrAfter(int pos, int startpos)
+    {
+        if (pnode == null) {
+            return null; // empty node tree
+        }
+
+        if (startpos + pnodeOffset >= pos) {
+            if (left != null) {
+                NodeAndPosition<T> rval = left.findNodeAtOrAfter(pos, startpos);
+                if (rval != null) {
+                    return rval;
+                }
+            }
+        }
+
+        if (startpos + pnodeSize + pnodeOffset >= pos) {
+            return new NodeAndPosition<T>(pnode, startpos + pnodeOffset, pnodeSize);
+        }
+
+        NodeAndPosition<T> rval = null;
+        if (right != null) {
+            rval = right.findNodeAtOrAfter(pos, startpos + pnodeOffset + pnodeSize);
+        }
+        return rval;
+    }
+
+    /**
+     * Set the size of the contained ParsedNode. This is to be used in cases where the
+     * node has shrunk or grown because of text being removed or inserted, not for cases
+     * when the node is taking on more (or less) text from the document (see also setSize()).
+     */
+    public void resize(int newSize)
+    {
+        int delta = newSize - pnodeSize;
+        pnodeSize = newSize;
+        NodeTree<T> nt = this;
+        while (nt.parent != null) {
+            if (nt.parent.left == nt) {
+                nt.parent.pnodeOffset += delta;
+            }
+            nt = nt.parent;
+        }
+    }
+    
+    /**
+     * Set the size of the contained ParsedNode, without moving nodes to the right of it.
+     * See also resize().
+     */
+    public void setSize(int newSize)
+    {
+        int delta = newSize - pnodeSize;
+        pnodeSize = newSize;
+        NodeTree<T> nt = this.right;
+        while (nt != null) {
+            nt.pnodeOffset -= delta;
+            nt = nt.left;
+        }
+    }
+
+    /**
+     * Move the node. This also has the effect of moving all following nodes.
+     * @param offset  The amount by which to move the node
+     */
+    public void slideNode(int offset)
+    {
+        pnodeOffset += offset;
+        NodeTree<T> nt = this;
+        while (nt.parent != null) {
+            if (nt.parent.left == nt) {
+                nt.parent.pnodeOffset += offset;
+            }
+            nt = nt.parent;
+        }
+    }
+    
+    /**
+     * Move the node's beginning, but not its end position. This shrinks or grows
+     * the node accordingly. The position of any subsequent node is not affected.
+     */
+    public void slideStart(int offset)
+    {
+        pnodeOffset += offset;
+        pnodeSize -= offset;
+    }
+
+    /**
+     * Get the size of the contained ParsedNode.
+     */
+    public int getNodeSize()
+    {
+        return pnodeSize;
+    }
+
+    /**
+     * Insert a node into the tree, without affecting the position of other nodes.
+     */
+    public void insertNode(T newNode, int pos, int size)
+    {
+        if (pnode == null) {
+            pnode = newNode;
+            pnode.setContainingNodeTree(this);
+            pnodeOffset = pos;
+            pnodeSize = size;
+            size = pos + size;
+        }
+        else {
+            if (pos < pnodeOffset) {
+                assert(pos + size <= pnodeOffset);
+                if (left == null) {
+                    left = new NodeTree<T>(this, newNode, pos, size);
+                    fixupNewNode(left);
+                }
+                else {
+                    left.insertNode(newNode, pos, size);
+                }
+            }
+            else {
+                assert(pnodeOffset + pnodeSize <= pos);
+                pos -= (pnodeOffset + pnodeSize);
+                if (right == null) {
+                    right = new NodeTree<T>(this, newNode, pos, size);
+                    fixupNewNode(right);
+                }
+                else {
+                    right.insertNode(newNode, pos, size);
+                }
+            }
+        }
+    }
+
+    /**
+     * Remove this node from the tree. Position of following nodes is preserved.
+     */
+    public void remove()
+    {
+        if (left == null || right == null) {
+            one_child_remove();
+        }
+        else {
+            NodeTree<T> sub = left;
+            int nmoffset = 0;
+            while (sub.right != null) {
+                nmoffset += (sub.pnodeOffset + sub.pnodeSize);
+                sub = sub.right;
+            }
+            swapNodeData(this, sub);
+
+            pnodeOffset += nmoffset;
+            int rchange = (sub.pnodeOffset + sub.pnodeSize) - (pnodeOffset + pnodeSize);
+            right.adjustLeftOffsets(rchange);
+
+            sub.one_child_remove();
+        }
+    }
+
+    /**
+     * Get the relative position of the contained parsed node to the parent node (root of the
+     * NodeTree).
+     */
+    public int getPosition()
+    {
+        int pos = pnodeOffset;
+
+        NodeTree<T> parent = this.parent;
+        NodeTree<T> current = this;
+
+        while (parent != null) {
+            if (current == parent.right) {
+                pos += parent.pnodeOffset + parent.pnodeSize;
+            }
+            current = parent;
+            parent = current.parent;
+        }
+
+        return pos;
+    }
+
+    private void adjustLeftOffsets(int amount)
+    {
+        NodeTree<T> nt = this;
+        while (nt != null) {
+            nt.pnodeOffset += amount;
+            nt = nt.left;
+        }
+    }
+
+    /**
+     * Re-structure the tree so that one node (with) takes the place of another (dest).
+     * The "dest" node (and any of its subtrees, except "with") will then no longer be part
+     * of the tree.
+     */
+    private static <T extends RBTreeNode<T>> void replace_node(NodeTree<T> dest, NodeTree<T> with)
+    {
+        if (dest.parent != null) {
+            if (dest.parent.left == dest) {
+                dest.parent.left = with;
+            }
+            else {
+                dest.parent.right = with;
+            }
+        }
+        if (with != null) {
+            with.parent = dest.parent;
+        }
+    }
+
+    /**
+     * Remove, in the special case that one or both children are null.
+     */
+    private void one_child_remove()
+    {
+        if (left == null && right == null) {
+            pnode = null;
+            if (parent != null) {
+                if (black) {
+                    delete_case_1();
+                }
+                // If we're not black, we are red. So removing us doesn't change
+                // the number of black nodes in any path from the parent.
+                if (parent.left == this) {
+                    parent.left = null;
+                }
+                else {
+                    parent.right = null;
+                }
+            }
+        }
+        else {
+            // We must be black. The child must be red.
+            if (parent == null) {
+                // Special case - mustn't move the root.
+                if (left == null) {
+                    int offset = pnodeOffset + pnodeSize;
+                    swapNodeData(this, right);
+                    pnodeOffset += offset;
+                    right = null;
+                }
+                else {
+                    swapNodeData(this, left);
+                    left = null;
+                }
+                black = true;
+            }
+            else if (left == null) {
+                int offset = pnodeOffset + pnodeSize;
+                replace_node(this, right);
+                right.adjustLeftOffsets(offset);
+                right.black = true;
+            }
+            else {
+                replace_node(this, left);
+                left.black = true;
+            }
+        }
+    }
+
+    private NodeTree<T> getSibling()
+    {
+        if (parent != null) {
+            if (parent.left == this) {
+                return parent.right;
+            }
+            else {
+                return parent.left;
+            }
+        }
+        else {
+            return null;
+        }
+    }
+
+    /**
+     * A black node was deleted. We need to add a black node to this path
+     * (or remove one from all other paths).
+     */
+    private void delete_case_1()
+    {
+        // If we get here, the current node is black (which will not change).
+        // We may or may not have any children; regardless, we must have a sibling.
+        if (parent != null) {
+            // delete case 2
+            NodeTree<T> sibling = getSibling();
+            if (! sibling.black) {
+                // we are black, so our red sibling must have children...
+                parent.black = false;
+                sibling.black = true;
+                if (this == parent.left) {
+                    rotateLeft(parent);
+                }
+                else {
+                    rotateRight(parent);
+                }
+                // ... one of which is our new sibling.
+            }
+            delete_case_3();
+        }
+    }
+
+    private void delete_case_3()
+    {
+        // To get here, we must have both a parent and a sibling.
+        NodeTree<T> sibling = getSibling();
+        if (parent.black && sibling.black && isBlack(sibling.left) && isBlack(sibling.right)) {
+            // That's a lot of black.
+            sibling.black = false; // remove a black node from sibling path...
+            parent.delete_case_1(); // and continue up the tree.
+        }
+        else {
+            // delete case 4
+            if (! parent.black && sibling.black && isBlack(sibling.left) && isBlack(sibling.right)) {
+                sibling.black = false;
+                parent.black = true;
+            }
+            else {
+                // delete case 5
+                if (isBlack(sibling)) {
+                    if (this == parent.left && isBlack(sibling.right) && !isBlack(sibling.left)) {
+                        sibling.black = false;
+                        sibling.left.black = true;
+                        rotateRight(sibling);
+                    }
+                    else if (this == parent.right && isBlack(sibling.left) && !isBlack(sibling.right)) {
+                        sibling.black = false;
+                        sibling.right.black = true;
+                        rotateLeft(sibling);
+                    }
+                }
+
+                // delete case 6
+                sibling.black = parent.black;
+                parent.black = true;
+                if (this == parent.left) {
+                    sibling.right.black = true;
+                    rotateLeft(parent);
+                }
+                else {
+                    sibling.left.black = true;
+                    rotateRight(parent);
+                }
+            }
+        }
+    }
+
+    /**
+     * Clear the tree - remove all nodes
+     */
+    public void clear()
+    {
+        left = null;
+        pnode = null;
+        right = null;
+    }
+
+    /**
+     * This node has been inserted into the tree. Fix up the tree to maintain balance.
+     */
+    private static <T extends RBTreeNode<T>> void fixupNewNode(NodeTree<T> n)
+    {
+        if (n.parent == null) {
+            n.black = true;
+            return;
+        }
+
+        if (n.parent.isBlack()) {
+            return; // ok - we are balanced
+        }
+
+        // We know from here on the parent is red.
+
+        NodeTree<T> grandparent = n.getGrandparent(); // cannot be null (root is always black).
+        NodeTree<T> uncle = n.getUncle();
+        if (! isBlack(uncle)) {
+            uncle.black = true;
+            n.parent.black = true;
+            grandparent.black = false;
+            fixupNewNode(grandparent);
+            return;
+        }
+
+        NodeTree<T> parent = n.parent;
+        if (n == parent.right && parent == grandparent.left) {
+            rotateLeft(parent);
+            //grandparent = parent;
+            //parent = n;
+            //n = n.left;
+        }
+        else if (n == parent.left && parent == grandparent.right) {
+            rotateRight(n.parent);
+            //grandparent = parent;
+            //parent = n;
+            //n = n.right;
+        }
+
+        parent.black = true;
+        grandparent.black = false;
+        if (n == parent.left && parent == grandparent.left) {
+            rotateRight(grandparent);
+        }
+        else {
+            rotateLeft(grandparent);
+        }
+    }
+    
+    /**
+     * Swap the data of two nodes. This doesn't correctly adjust the
+     * pnode offset in either node.
+     * 
+     * @param n  The first node
+     * @param m  The second node
+     */
+    private static <T extends RBTreeNode<T>> void swapNodeData(NodeTree<T> n, NodeTree<T> m)
+    {
+        T pn = n.pnode;
+        int offset = n.pnodeOffset;
+        int size = n.pnodeSize;
+
+        n.pnode = m.pnode;
+        n.pnodeOffset = m.pnodeOffset;
+        n.pnodeSize = m.pnodeSize;
+
+        m.pnode = pn;
+        m.pnodeOffset = offset;
+        m.pnodeSize = size;
+
+        if (n.pnode != null) {
+            n.pnode.setContainingNodeTree(n);
+        }
+
+        if (m.pnode != null) {
+            m.pnode.setContainingNodeTree(m);
+        }
+    }
+
+    private static <T extends RBTreeNode<T>> void rotateLeft(NodeTree<T> n)
+    {
+        // Right child of n becomes n's parent
+        // We swap the data to avoid actually moving node n.
+        swapNodeData(n, n.right);
+        boolean nblack = n.black;
+        n.black = n.right.black;
+        n.right.black = nblack;
+
+        n.pnodeOffset += n.right.pnodeOffset + n.right.pnodeSize;
+        
+        if (n.left == null) {
+            // A simple case.
+            //assert(n.right.left == null);
+            n.left = n.right;
+            n.right = n.left.right;
+            if (n.right != null) {
+                n.right.parent = n;
+            }
+            n.left.right = null;
+            return;
+        }
+        
+        NodeTree<T> oldLeft = n.left;
+        n.left = n.right;
+        n.right = n.left.right;
+        if (n.right != null) {
+            n.right.parent = n;
+        }
+        n.left.right = n.left.left;
+        n.left.left = oldLeft;
+        if (oldLeft != null) {
+            oldLeft.parent = n.left;
+        }
+    }
+    
+    private static <T extends RBTreeNode<T>> void rotateRight(NodeTree<T> n)
+    {
+        // Left child of n becomes n's parent
+        // We swap the data to avoid actually moving node n.
+        swapNodeData(n, n.left);
+        boolean nblack = n.black;
+        n.black = n.left.black;
+        n.left.black = nblack;
+
+        if (n.right == null) {
+            // A simple case.
+            //assert(n.left.right == null);
+            n.right = n.left;
+            n.left = n.right.left;
+            if (n.left != null) {
+                n.left.parent = n;
+            }
+            n.right.left = null;
+            n.right.pnodeOffset -= (n.pnodeOffset + n.pnodeSize);
+            return;
+        }
+                
+        NodeTree<T> oldRight = n.right;
+        n.right = n.left;
+        n.left = n.right.left;
+        if (n.left != null) {
+            n.left.parent = n;
+        }
+        n.right.left = n.right.right;
+        n.right.right = oldRight;
+        if (oldRight != null) {
+            oldRight.parent = n.right;
+        }
+        
+        n.right.pnodeOffset -= (n.pnodeOffset + n.pnodeSize);
+    }
+    
+    private NodeTree<T> getGrandparent()
+    {
+        if (parent != null) {
+            return parent.parent;
+        }
+        else {
+            return null;
+        }
+    }
+
+    private NodeTree<T> getUncle()
+    {
+        return parent.getSibling();
+    }
+
+    private NodeTree(NodeTree<T> parent, T node, int offset, int size)
+    {
+        this.parent = parent;
+        pnode = node;
+        pnode.setContainingNodeTree(this);
+        this.pnodeSize = size;
+        this.pnodeOffset = offset;
+        black = false; // initial colour is red
+    }
+
+    private boolean isBlack()
+    {
+        return black;
+    }
+
+    private static boolean isBlack(NodeTree<?> n)
+    {
+        return n == null || n.black;
+    }
+
+    /**
+     * A class to represent a [node, position] tuple.
+     */
+    public static class NodeAndPosition<T extends RBTreeNode<T>>
+    {
+        private T parsedNode;
+        private int position;
+        private int size;
+
+        public NodeAndPosition(T pn, int position, int size)
+        {
+            this.parsedNode = pn;
+            this.position = position;
+            this.size = size;
+        }
+
+        public T getNode()
+        {
+            return parsedNode;
+        }
+
+        public int getPosition()
+        {
+            return position;
+        }
+
+        public int getSize()
+        {
+            return size;
+        }
+        
+        public int getEnd()
+        {
+            return position + size;
+        }
+        
+        /**
+         * Find the next sibling node - that is, the sibling that occurs closest after this one in
+         * terms of position. If the node tree is manipulated only via methods on this object then
+         * a call to nextSibling() is valid, otherwise the return is undefined,
+         * 
+         * @return  The next sibling, or null if there is no next sibling.
+         */
+        public NodeAndPosition<T> nextSibling()
+        {
+            NodeTree<T> nt = parsedNode.getContainingNodeTree();
+            if (nt.right != null) {
+                // go right and then as far left as possible
+                int offs = position + nt.pnodeSize;
+                nt = nt.right;
+                while (nt.left != null) {
+                    nt = nt.left;
+                }
+                return new NodeAndPosition<T>(nt.pnode, offs + nt.pnodeOffset, nt.pnodeSize);
+            }
+            
+            // Otherwise go up until we have gone up to the right
+            int offs = position - nt.pnodeOffset;
+            while (nt.parent != null) {
+                if (nt.parent.left == nt) {
+                    nt = nt.parent;
+                    return new NodeAndPosition<T>(nt.pnode, offs + nt.pnodeOffset, nt.pnodeSize);
+                }
+                nt = nt.parent;
+                offs -= (nt.pnodeOffset + nt.pnodeSize); 
+            }
+            
+            return null; // no prior node
+        }
+        
+        /**
+         * Find the previous sibling node - that is, the sibling that occurs closest before this one in
+         * terms of position. If the node tree is manipulated only via methods on this object then
+         * a call to prevSibling() is valid, otherwise the return is undefined,
+         * 
+         * @return  The previous sibling, or null if there is no next sibling.
+         */
+        public NodeAndPosition<T> prevSibling()
+        {
+            NodeTree<T> nt = parsedNode.getContainingNodeTree();
+            if (nt.left != null) {
+                // go left and then as far right as possible
+                int offs = position - nt.pnodeOffset;
+                nt = nt.left;
+                while (nt.right != null) {
+                    offs += nt.pnodeOffset + nt.pnodeSize;
+                    nt = nt.right;
+                }
+                return new NodeAndPosition<T>(nt.pnode, offs + nt.pnodeOffset, nt.pnodeSize);
+            }
+            
+            // Otherwise go up until we have gone up to the left
+            while (nt.parent != null) {
+                int offs = position - nt.pnodeOffset;
+                if (nt.parent.right == nt) {
+                    nt = nt.parent;
+                    return new NodeAndPosition<T>(nt.pnode, offs - nt.pnodeSize, nt.pnodeSize);
+                }
+                nt = nt.parent;
+            }
+            
+            return null; // no prior node
+        }
+        
+        /**
+         * Slide the node and all following nodes by the given amount.
+         */
+        public void slide(int amount)
+        {
+            getNode().slide(amount);
+            position += amount;
+        }
+        
+        /**
+         * Slide the start of the node by the given amount, but leave its end in place.
+         */
+        public void slideStart(int amount)
+        {
+            getNode().slideStart(amount);
+            position += amount;
+            size -= amount;
+        }
+        
+        /**
+         * Resize the node. Any following nodes will move accordingly.
+         */
+        public void resize(int newSize)
+        {
+            getNode().resize(newSize);
+            size = newSize;
+        }
+        
+        /**
+         * Set the size of the contained node, without moving following nodes. It is the
+         * caller's responsibility to ensure that setting the new size does not cause the
+         * node to overlap following nodes.
+         * @param newSize  The new size of the node.
+         */
+        public void setSize(int newSize)
+        {
+            getNode().setSize(newSize);
+            size = newSize;
+        }
+        
+        /**
+         * Set the size as recorded in the NodeAndPosition object, without
+         * affecting the relative node.
+         */
+        public void setNapSize(int newSize)
+        {
+            size = newSize;
+        }
+    }
+    
+    /**
+     * An iterator through a node tree.
+     */
+    private static class NodeTreeIterator<T extends RBTreeNode<T>> implements Iterator<NodeAndPosition<T>>
+    {
+        @Override
+      public void forEachRemaining(Consumer<? super NodeAndPosition<T>> action) {
+        // TODO Auto-generated method stub
+        
+      }
+
+        //Stack<NodeTree> stack;
+        int pos = 0; // 0 - left, 1 = middle, 2 = right
+        int offset = 0;
+        NodeTree<T> current = null;
+
+        /**
+         * Construct a new NodeTreeIterator over the given tree
+         * @param offset     The offset of the tree
+         * @param tree       The tree
+         * @param leftFirst  Whether to process the left branch first (otherwise iteration starts
+         *                   at the node in {@code tree}.
+         */
+        public NodeTreeIterator(int offset, NodeTree<T> tree)
+        {
+            this.offset = offset;
+            if (tree.pnode != null) {
+                current = tree;
+                if (tree.left == null) {
+                    pos = 1;
+                }
+            }
+        }
+
+        public boolean hasNext()
+        {
+            return current != null;
+        }
+
+        public NodeAndPosition<T> next()
+        {
+            while (true) {
+                while (pos == 0) {
+                    current = current.left;
+                    if (current.left == null) {
+                        pos = 1;
+                    }
+                }
+                NodeTree<T> top = current;
+
+                if (pos == 1) {
+                    pos = 2;
+                    NodeAndPosition<T> rval = new NodeAndPosition<T>(top.pnode,
+                            top.pnodeOffset + offset,
+                            top.pnodeSize);
+                    if (top.right == null) {
+                        downStackRight();
+                    }
+                    return rval;
+                }
+
+                // pos == 2
+                if (top.right == null) {
+                    throw new NullPointerException();
+                }
+                offset += top.pnodeOffset + top.pnodeSize;
+                top = top.right;
+                current = top;
+                pos = (top.left != null) ? 0 : 1;
+            }
+        }
+        
+        private void downStackRight()
+        {
+            NodeTree<T> top = current;
+            current = current.parent;
+            while (current != null && current.right == top) {
+                top = current;
+                current = current.parent;
+                offset -= top.pnodeOffset + top.pnodeSize; 
+            }
+            pos = 1; // middle!
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParentParsedNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParentParsedNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..473f780e704b561f4d776feba089f6485e5e8a4a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParentParsedNode.java
@@ -0,0 +1,220 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import javax.swing.text.Document;
+
+import bluej.editor.moe.MoeSyntaxDocument;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * An abstract ParsedNode which delegates to child nodes.
+ * 
+ * @author Davin McCall
+ */
+public abstract class ParentParsedNode extends ParsedNode
+{    
+    protected ParentParsedNode()
+    {
+        super();
+    }
+    
+    public ParentParsedNode(ParsedNode myParent)
+    {
+        super(myParent);
+    }
+            
+    @Override
+    public int textInserted(MoeSyntaxDocument document, int nodePos, int insPos,
+            int length, NodeStructureListener listener)
+    {
+        // grow ourself:
+        int newSize = getSize() + length;
+        resize(newSize);
+        
+        NodeAndPosition<ParsedNode> child = getNodeTree().findNodeAtOrAfter(insPos, nodePos);
+        if (child != null && (child.getPosition() < insPos
+                || child.getPosition() == insPos && child.getNode().growsForward())) {
+            ParsedNode cnode = child.getNode();
+            // let the child handle the change.
+            int r = cnode.textInserted(document, child.getPosition(), insPos, length, listener);
+            if (r == NODE_GREW || r == NODE_SHRUNK) {
+                newSize = child.getNode().getSize();
+                child = new NodeAndPosition<ParsedNode>(cnode, child.getPosition(), newSize);
+                childResized(document, nodePos, child);
+                //return reparseNode(document, nodePos, child.getPosition() + newSize, listener);
+                document.scheduleReparse(child.getPosition() + newSize, 0);
+                return ALL_OK;
+            }
+            else if (r == REMOVE_NODE) {
+                removeChild(child, listener);
+                //return reparseNode(document, nodePos, child.getPosition(), listener);
+                document.scheduleReparse(child.getPosition(), child.getSize());
+                return ALL_OK;
+            }
+            return ALL_OK;
+        }
+        else {
+            // We must handle the insertion ourself
+            // Slide any children:
+            if (child != null) {
+                child.getNode().getContainingNodeTree().slideNode(length);
+            }
+            //return reparseNode(document, nodePos, insPos, listener);
+            return handleInsertion(document, nodePos, insPos, length, listener);
+        }
+    }
+    
+    /**
+     * Handle the case of text being inserted directly into this node (not a child).
+     */
+    protected int handleInsertion(Document document, int nodePos, int insPos, int length,
+            NodeStructureListener listener)
+    {
+        ((MoeSyntaxDocument) document).scheduleReparse(insPos, length);
+        return ALL_OK;
+    }
+    
+    @Override
+    public int textRemoved(MoeSyntaxDocument document, int nodePos, int delPos,
+            int length, NodeStructureListener listener)
+    {
+        // shrink ourself:
+        int newSize = getSize() - length;
+        resize(newSize);
+        
+        int endPos = delPos + length;
+        
+        NodeAndPosition<ParsedNode> child = getNodeTree().findNodeAtOrAfter(delPos, nodePos);
+        while (child != null && child.getEnd() == delPos) {
+            if (! child.getNode().marksOwnEnd()) {
+                child.getNode().setComplete(false);
+            }
+            child = child.nextSibling();
+        }
+        
+        if (child != null && child.getPosition() < delPos) {
+            // Remove the end portion (or middle) of the child node
+            int childEndPos = child.getEnd();
+            if (childEndPos >= endPos) {
+                // Remove the middle of the child node
+                int r = child.getNode().textRemoved(document, child.getPosition(), delPos, length, listener);
+                if (r == REMOVE_NODE) {
+                    removeChild(child, listener);
+                    document.scheduleReparse(child.getPosition(), child.getSize());
+                }
+                else if (r != ALL_OK) {
+                    newSize = child.getNode().getSize();
+                    if (newSize < child.getSize()) {
+                        document.scheduleReparse(child.getPosition() + newSize, child.getSize() - newSize);
+                    }
+                    else {
+                        document.scheduleReparse(child.getPosition() + newSize, 0);
+                    }
+                }
+                return ALL_OK;
+            }
+            
+            // Remove the end portion of the child node
+            int rlength = childEndPos - delPos; // how much is removed
+
+            // Remove any following nodes as necessary
+            NodeAndPosition<ParsedNode> next = child.nextSibling();
+            while (next != null && next.getPosition() < endPos) {
+                NodeAndPosition<ParsedNode> nnext = next.nextSibling();
+                removeChild(next, listener);
+                next = nnext;
+            }
+
+            if (next != null) {
+                // Slide the portion which remains
+                next.getNode().slide(rlength - length);
+            }
+            // Inform the child of the removed text 
+            int r = child.getNode().textRemoved(document, child.getPosition(), delPos, rlength, listener);
+            int reparseOffset;
+            if (r == REMOVE_NODE) {
+                reparseOffset = child.getPosition();
+                removeChild(child, listener);
+            }
+            else {
+                reparseOffset = child.getPosition() + child.getNode().getSize();
+            }
+
+            return handleDeletion(document, nodePos, reparseOffset, listener);
+        }
+        
+        // Any child node that has its beginning removed is just removed.
+        while (child != null && child.getPosition() < endPos) {
+            NodeAndPosition<ParsedNode> nextChild = child.nextSibling();
+            removeChild(child, listener);
+            child = nextChild;
+        }
+
+        if (child != null) {
+            child.slide(-length);
+            if (child.getPosition() == delPos && child.getNode().growsForward()) {
+                // The child had text immediately preceding it removed, and it
+                // grows forward, meaning that the parent probably determines where
+                // it starts. If we schedule a re-parse at delPos, the child will
+                // get re-parsed instead of the parent - so we just remove the child.
+                removeChild(child, listener);
+            }
+        }
+        
+        return handleDeletion(document, nodePos, delPos, listener);
+    }
+    
+    /**
+     * Handle the case of text being removed directly from this node (rather than a
+     * child node).
+     */
+    protected int handleDeletion(Document document, int nodePos, int dpos,
+            NodeStructureListener listener)
+    {
+        if (nodePos + getSize() == dpos && marksOwnEnd()) {
+            complete = false;
+        }
+        
+        ((MoeSyntaxDocument)document).scheduleReparse(dpos, 0);
+        return ALL_OK;
+    }
+    
+    /*
+     * Default implementation, just causes the parent to re-parse
+     */
+    @Override
+    protected int reparseNode(Document document, int nodePos, int offset, int maxParse, NodeStructureListener listener)
+    {
+        return REMOVE_NODE;
+    }
+    
+    @Override
+    protected boolean growChild(Document document, NodeAndPosition<ParsedNode> child,
+            NodeStructureListener listener)
+    {
+        // Without any further knowledge, we're just going to have to do a full reparse.
+        // Subclasses should override this to improve performance.
+        return false;
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParseParams.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParseParams.java
new file mode 100644
index 0000000000000000000000000000000000000000..58d5dbc768b847b094b4b08184f6bb3c67eebadd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParseParams.java
@@ -0,0 +1,54 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.util.LinkedList;
+
+import bluej.editor.moe.MoeSyntaxDocument;
+import bluej.parser.EditorParser;
+import bluej.parser.lexer.JavaTokenFilter;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * Parameter block for certain parsing methods.
+ * 
+ * <p>The sole use of objects of this class are to pass around a large number of
+ * parameters. For this reason fields are publicly accessible.
+ * 
+ * @author Davin McCall
+ */
+public class ParseParams
+{
+    // Parameters passed to the subclass partial parse method
+    
+    public NodeStructureListener listener;
+    public EditorParser parser;
+    public JavaTokenFilter tokenStream;
+    public MoeSyntaxDocument document;
+    public int nodePos;
+    public LinkedList<NodeAndPosition<ParsedNode>> childQueue;
+    
+    // Parameters returned from the partial parse method
+    
+    /** Where exactly parsing got to, when partial parse returns PP_ABORT */
+    public int abortPos;
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParsedCUNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParsedCUNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..39d6a90d5f1dfd8682c433e55d089ffd9511253a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParsedCUNode.java
@@ -0,0 +1,226 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.util.List;
+
+import javax.swing.text.Document;
+
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.ImportsCollection;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.PackageOrClass;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+import bluej.utility.JavaNames;
+
+
+/**
+ * A parsed compilation unit node.
+ * 
+ * @author Davin McCall
+ */
+public class ParsedCUNode extends IncrementalParsingNode
+{
+    private EntityResolver parentResolver;
+    private ImportsCollection imports = new ImportsCollection();
+
+    private int size = 0;
+    
+    /**
+     * Construct a parsed node for as yet unknown source.
+     */
+    public ParsedCUNode()
+    {
+        super(null);
+    }
+    
+    /**
+     * Construct a parsed node for the given document. The node will
+     * assume its size is 0; the text from the document (if any) should
+     * be explicitly inserted.
+     */
+    public ParsedCUNode(Document document)
+    {
+        super(null);
+        size = 0;
+    }
+    
+    /**
+     * Set the entity resolver used to resolve symbols.
+     */
+    public void setParentResolver(EntityResolver parentResolver)
+    {
+        this.parentResolver = parentResolver;
+    }
+
+    public ImportsCollection getImports()
+    {
+        return imports;
+    }
+    
+    public EntityResolver getParentResolver()
+    {
+        return parentResolver;
+    }
+    
+    /**
+     * Overridden getSize() which returns the document size.
+     * 
+     * @see bluej.parser.nodes.ParsedNode#getSize()
+     */
+    public int getSize()
+    {
+        return size;
+    }
+
+    @Override
+    public void resize(int newSize)
+    {
+        size = newSize;
+    }
+    
+    @Override
+    public void setSize(int newSize)
+    {
+        size = newSize;
+    }
+    
+    @Override
+    protected int doPartialParse(ParseParams params, int state)
+    {
+        last = params.tokenStream.LA(1);
+       
+        if (checkBoundary(params, last)) {
+            return PP_PULL_UP_CHILD;
+        }
+        
+        params.parser.parseCUpart(state);
+        return PP_OK;
+    };
+    
+    @Override
+    protected boolean isDelimitingNode(NodeAndPosition<ParsedNode> nap)
+    {
+        // All node types: package statement, import (Inner), type definition,
+        // are all delimiting nodes. Only a comment is not.
+        int nt = nap.getNode().getNodeType();
+        return nt != ParsedNode.NODETYPE_COMMENT;
+    }
+    
+    @Override
+    protected boolean isNodeEndMarker(int tokenType)
+    {
+        return false;
+    }
+    
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return true;
+    }
+    
+    @Override
+    public PackageOrClass resolvePackageOrClass(String name, Reflective querySource)
+    {
+        PackageOrClass poc = super.resolvePackageOrClass(name, querySource);
+        if (poc == null) {
+            poc = imports.getTypeImport(name);
+        }
+        if (poc == null && parentResolver != null && querySource != null) {
+            String prefix = JavaNames.getPrefix(querySource.getName());
+            String fqName = JavaNames.combineNames(prefix, name);
+            poc = parentResolver.resolveQualifiedClass(fqName);
+        }
+        if (poc == null) {
+            poc = imports.getTypeImportWC(name);
+        }
+        if (poc == null && parentResolver != null) {
+            // Implicit "import java.lang.*"
+            poc = parentResolver.resolveQualifiedClass("java.lang." + name);
+        }
+        if (poc == null && parentResolver != null) {
+            return parentResolver.resolvePackageOrClass(name, querySource);
+        }
+        return poc;
+    }
+    
+    @Override
+    public JavaEntity getValueEntity(String name, Reflective querySource)
+    {
+        // We may have static imports
+        
+        List<JavaEntity> simports = imports.getStaticImports(name);
+        for (JavaEntity importType : simports) {
+            importType = importType.resolveAsType();
+            if (importType == null) {
+                continue;
+            }
+            JavaEntity subEnt = importType.getSubentity(name, querySource);
+            if (subEnt != null) {
+                JavaEntity value = subEnt.resolveAsValue();
+                if (value != null) {
+                    return value;
+                }
+            }
+        }
+        
+        simports = imports.getStaticWildcardImports();
+        for (JavaEntity importType : simports) {
+            importType = importType.resolveAsType();
+            if (importType == null) {
+                continue;
+            }
+            JavaEntity subEnt = importType.getSubentity(name, querySource);
+            if (subEnt != null) {
+                JavaEntity value = subEnt.resolveAsValue();
+                if (value != null) {
+                    return value;
+                }
+            }
+        }
+        
+        return resolvePackageOrClass(name, querySource);
+    }
+    
+    @Override
+    public TypeEntity resolveQualifiedClass(String name)
+    {
+        if (parentResolver != null) {
+            return parentResolver.resolveQualifiedClass(name);
+        }
+        return null;
+    }
+    
+//    public static void printTree(ParsedNode node, int nodepos, int indent)
+//    {
+//        for (int i = 0; i < indent; i++) {
+//            System.out.print("  ");
+//        }
+//        System.out.println("Node=" + node + " pos=" + nodepos + " size=" + node.getSize());
+//        for (Iterator<NodeAndPosition<ParsedNode>> i = node.getChildren(nodepos); i.hasNext(); ) {
+//            NodeAndPosition<ParsedNode> nap = i.next();
+//            printTree(nap.getNode(), nap.getPosition(), indent+1);
+//        }
+//    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParsedNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParsedNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5041e91611f98401b7dcc85376d5d08fa574786
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParsedNode.java
@@ -0,0 +1,495 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.util.Iterator;
+
+import javax.swing.text.Document;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.editor.moe.MoeSyntaxDocument;
+import bluej.editor.moe.Token;
+import bluej.parser.CodeSuggestions;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * A "parsed node" represents a node in a limited parse tree. The tree is limited because
+ * it contains only a subset of elements that might normally be found in a full parse tree.
+ * A ParsedNode tree does however contain information to precisely map nodes to source code
+ * document positions.<p>
+ * 
+ * Also included is basic infrastructure for incremental parsing.
+ * 
+ * @author Davin McCall
+ */
+public abstract class ParsedNode extends RBTreeNode<ParsedNode>
+{
+    public static final int NODETYPE_NONE = 0;
+    public static final int NODETYPE_TYPEDEF = 1;
+    public static final int NODETYPE_METHODDEF = 2;
+    public static final int NODETYPE_ITERATION = 3; // for, while, etc
+    public static final int NODETYPE_SELECTION = 4; // if/then, try/catch
+    
+    public static final int NODETYPE_FIELD = 5;  // field declaration
+    public static final int NODETYPE_EXPRESSION = 6; // expression
+    
+    public static final int NODETYPE_COMMENT = 7;
+    
+    /** The NodeTree containing the child nodes of this node */
+    private NodeTree<ParsedNode> nodeTree;
+    /** The parent ParsedNode which contains us */
+    private ParsedNode parentNode;
+    
+    private boolean hasAttachedComment;
+    
+    /**
+     * Specifies whether this node is complete, in that its end is properly marked with an
+     * appropriate token. 
+     */
+    protected boolean complete;
+    
+    private boolean isInner = false;
+    
+    public ParsedNode()
+    {
+        nodeTree = new NodeTree<ParsedNode>();
+    }
+    
+    ParsedNode(ParsedNode parentNode)
+    {
+        this();
+        this.parentNode = parentNode;
+    }
+
+    public Iterator<NodeAndPosition<ParsedNode>> getChildren(int offset)
+    {
+        return nodeTree.iterator(offset);
+    }
+    
+    /**
+     * Get the type of this node. One of:
+     * <ul>
+     * <li>NODETYPE_NONE - unspecified
+     * <li>NODETYPE_TYPEDEF - a type definition (class, interface etc)
+     * <li>NODETYPE_METHODDEF - a method defintion
+     * <li>NODETYPE_ITERATION - an iteration construct (for loop etc)
+     * <li>NODETYPE_SELECTION - a selection construct (if/else etc)
+     * <li>NODETYPE_FIELD     - a field or variable declaration
+     * <li>NODETYPE_EXPRESSION - an expression
+     * <li>NODETYPE_COMMENT   - a code comment
+     * </ul>
+     */
+    public int getNodeType()
+    {
+        return NODETYPE_NONE;
+    }
+    
+    /**
+     * Specify whether this node is complete - that is, it is ended by an appropriate token.
+     */
+    public void setComplete(boolean complete)
+    {
+        this.complete = complete;
+    }
+    
+    /**
+     * Check whether this node is known to be complete.
+     */
+    public boolean isComplete()
+    {
+        return complete;
+    }
+    
+    /**
+     * Get the name of the entity this node represents. For methods, returns the method name.
+     * May return null.
+     */
+    public String getName()
+    {
+        return null;
+    }
+    
+    public boolean equals(Object obj)
+    {
+        return obj == this;
+    }
+    
+    /**
+     * If text is inserted immediately before this node, should it be made part of this
+     * node? For instance in a method inner body, this would be true, seeing as anything
+     * after the '{' (which is part of the outer body) must by definition be part of the
+     * inner body.
+     */
+    public boolean growsForward()
+    {
+        return false;
+    }
+    
+    /**
+     * Returns true if this node marks its own end, that is, the token signifying
+     * the end of this node is contained within this node itself, rather than in
+     * the parent node.
+     */
+    protected abstract boolean marksOwnEnd();
+    
+    /**
+     * Insert a new child node (without affecting position of other children).
+     */
+    public void insertNode(ParsedNode child, int position, int size)
+    {
+        getNodeTree().insertNode(child, position, size);
+    }
+    
+    public void childChangedName(ParsedNode child, String oldName)
+    {
+        // Do nothing.
+    }
+    
+    /**
+     * Find the child node (if any) overlapping (including starting or ending at) the given position.
+     * 
+     * @param position   The position of the child node to find
+     * @param startpos   The position of this node
+     * @return the "leftmost" child which overlaps the position
+     */
+    public final NodeAndPosition<ParsedNode> findNodeAt(int position, int startpos)
+    {
+        return nodeTree.findNode(position, startpos);
+    }
+
+    /**
+     * Find the child node (if any) at or after the given position
+     * @param position   The position of the child node to find
+     * @param startpos   The position of this node
+     */
+    public final NodeAndPosition<ParsedNode> findNodeAtOrAfter(int position, int startpos)
+    {
+        return nodeTree.findNodeAtOrAfter(position, startpos);
+    }    
+    
+    /**
+     * Set the size of this node. Following nodes shift position according to the change in
+     * size; this should normally be used when inserting or removing text from the node.
+     * @param newSize  The new node size
+     */
+    public void resize(int newSize)
+    {
+        getContainingNodeTree().resize(newSize);
+    }
+    
+    /**
+     * Set the size of this node, without moving following nodes. It is the caller's
+     * responsibility to ensure that setting the new size does not cause this node
+     * to overlap following nodes.
+     * @param newSize  The new size of this node.
+     */
+    public void setSize(int newSize)
+    {
+        getContainingNodeTree().setSize(newSize);
+    }
+    
+    /**
+     * Get the offset of this node from its parent node.
+     */
+    public int getOffsetFromParent()
+    {
+        if (getContainingNodeTree() == null) {
+            return 0;
+        }
+        return getContainingNodeTree().getPosition();
+    }
+    
+    /**
+     * Remove this node from the parent, without disturbing the position of any sibling nodes.
+     * Probably, you don't want to call this directly; call removeChild() on the parent instead.
+     */
+    public void remove()
+    {
+        getContainingNodeTree().remove();
+    }
+    
+    /**
+     * Is this a "container" scope for highlighting purposes
+     * @return
+     */
+    public boolean isContainer()
+    {
+        return false;
+    }
+    
+    /**
+     * Is this an "inner" scope for highlighting purposes
+     */
+    public boolean isInner()
+    {
+        return isInner;
+    }
+    
+    /**
+     * Set whether this is an inner scope for highlighting purposes
+     */
+    public void setInner(boolean inner)
+    {
+        isInner = inner;
+    }
+    
+    /**
+     * Get the size of this node.
+     */
+    public int getSize()
+    {
+        return getContainingNodeTree().getNodeSize();
+    }
+
+    /* Constants for status of various methods defined below */
+    protected final static int ALL_OK = 0;
+    protected final static int NODE_GREW = 1;
+    protected final static int NODE_SHRUNK = 2;
+    protected final static int REMOVE_NODE = 3; // (and reparse parent)
+    
+    /**
+     * Insert the given text.
+     * 
+     * <p>The result should be one of ALL_OK, NODE_GREW, NODE_SHRUNK, or REMOVE_NODE.
+     * The latter indicates that the caller should remove the node. Except in the
+     * case of ALL_OK, the parent node must generally be re-parsed.
+     * 
+     * <p>Note, it is expected that the node grows by the amount of text inserted -
+     * the return should be ALL_OK rather than NODE_GREW if that is the case.
+     * 
+     * @param document   The document
+     * @param nodePos    The position of "this" node (relative to the document).
+     * @param insPos     The position of the insert (relative to the document).
+     * @param length     The length of the insert
+     * @param listener   The listener for node structural changes
+     */
+    public abstract int textInserted(MoeSyntaxDocument document, int nodePos, int insPos,
+            int length, NodeStructureListener listener);
+
+    /**
+     * The specified portion of text within the node has been removed.<p>
+     * 
+     * <p>The result should be one of ALL_OK, NODE_GREW, NODE_SHRUNK, or REMOVE_NODE.
+     * The latter indicates that the caller should remove the node. Except in the
+     * case of ALL_OK, the parent node must generally be re-parsed.
+     * 
+     * <p>It is expected that the node shrink by the amount of text removed - the
+     * return should be ALL_OK rather than NODE_SHRUNK if that is the case.
+     * 
+     * @param document   The document
+     * @param nodePos    The position of "this" node (relative to the document).
+     * @param insPos     The position of the removal (relative to the document).
+     * @param length     The length of the removal
+     * @param listener   The listener for node structural changes
+     */
+    public abstract int textRemoved(MoeSyntaxDocument document, int nodePos, int delPos,
+            int length, NodeStructureListener listener);
+
+    /**
+     * This node should be re-parsed from the specified point. The node position
+     * and offset are relative to the document beginning.<p>
+     * 
+     * The result should be one of ALL_OK, NODE_GREW, NODE_SHRUNK, or REMOVE_NODE.
+     * The latter indicates that the caller should remove the node. Except in the
+     * case of ALL_OK, the parent node must generally also be re-parsed.<p>
+     * 
+     * This method should always mark which range it parsed in the document.
+     */
+    protected int reparseNode(Document document, int nodePos, int offset, int maxParse, NodeStructureListener listener)
+    {
+        return ALL_OK;
+    }
+    
+    /**
+     * Perform a re-parse of the document at a given point. The parse may be partial; a certain amount of
+     * parsing will be performed and further re-parses will be queued as necessary against the document.
+     * 
+     * @param document  The document
+     * @param nodePos   The position of this node
+     * @param offset    The position within the document of the re-parse
+     * @param maxParse  The (advisory) maximum amount of document to re-parse in one hit
+     * @param listener  The structure listener to be notified of structural changes
+     */
+    public void reparse(MoeSyntaxDocument document, int nodePos, int offset, int maxParse, NodeStructureListener listener)
+    {
+        int size = getSize();
+        int r = reparseNode(document, nodePos, offset, maxParse, listener);
+        if (r == REMOVE_NODE) {
+            ParsedNode parent = getParentNode();
+            parent.removeChild(new NodeAndPosition<ParsedNode>(this,
+                    nodePos, getSize()), listener);
+            document.scheduleReparse(nodePos + size - 1, 0);
+        }
+        else if (r == NODE_GREW || r == NODE_SHRUNK) {
+            int nsize = getSize();
+            ParsedNode parent = getParentNode();
+            if (parent != null) {
+                int ppos = nodePos - getOffsetFromParent();
+                parent.childResized(document, ppos,
+                        new NodeAndPosition<ParsedNode>(this, nodePos, nsize));
+            }
+            document.scheduleReparse(nodePos + nsize, Math.max(size - nsize, 0));
+        }
+    }
+    
+    /**
+     * Get a sequence of "tokens" which indicate the colour and position/size of various tokens
+     * in a line of source code text. 
+     * @param pos       The position of the text to tokenize (document relative). Must be on a
+     *                  line or token boundary.
+     * @param length    The length of the text to tokenize. Must be on a line or token boundary.
+     * @param nodePos   The position of the node
+     * @param document  The source document
+     * @return  A linked list of Token objects
+     */
+    public abstract Token getMarkTokensFor(int pos, int length, int nodePos, Document document);
+
+    protected ParsedNode getParentNode()
+    {
+        return parentNode;
+    }
+
+    protected NodeTree<ParsedNode> getNodeTree()
+    {
+        return nodeTree;
+    }
+
+    /**
+     * This node is shortened, it no longer needs all the text assigned to it.
+     */
+    protected void nodeShortened(int newLength) {}
+
+    /**
+     * This node has become incomplete (needs to be extended).
+     */
+    protected void nodeIncomplete() {}
+    
+    /**
+     * growChild() is called by a child node when, during incremental parsing, it determines
+     * that it needs to grow in size. The response must be to increase the size of the child
+     * and return true, or (if increasing size is really not possible) to return false, or to
+     * return false and assume responsibility for re-parsing.<p>
+     * 
+     * It is the responsibility of this method to notify the listener of the child's change
+     * in size, if it occurs.
+     */
+    protected boolean growChild(Document document, NodeAndPosition<ParsedNode> child,
+            NodeStructureListener listener)
+    {
+        return false;
+    }
+    
+    /**
+     * Called after a child node changed size. This is just a notification
+     * and should not cause a reparse to be performed or scheduled, as that
+     * should be done elsewhere.
+     * 
+     * @param document   The document which parse structure is represented
+     * @param nodePos    The absolute position of this node
+     * @param child      The child node which has changed size
+     */
+    public void childResized(MoeSyntaxDocument document, int nodePos, NodeAndPosition<ParsedNode> child)
+    {
+        
+    }
+        
+    /**
+     * Get code completion suggestions at a particular point. May return null.
+     */
+    public CodeSuggestions getExpressionType(int pos, Document document)
+    {
+        return getExpressionType(pos, 0, null, document);
+    }
+        
+    /**
+     * Get code completion suggestions at a particular point. May return null.
+     *
+     * @param pos     The position to suggest completions for
+     * @param nodePos   The position of this node
+     * @param defaultType  The type to return if there is no explicit type at the given location 
+     * @param document  The source document
+     */
+    protected CodeSuggestions getExpressionType(int pos, int nodePos, JavaEntity defaultType, Document document)
+    {
+        NodeAndPosition<ParsedNode> child = getNodeTree().findNode(pos, nodePos);
+        if (child != null) {
+            return child.getNode().getExpressionType(pos, child.getPosition(), defaultType, document);
+        }
+
+        GenTypeClass atype = (defaultType != null) ? defaultType.getType().asClass() : null;
+        if (atype == null) {
+            return null;
+        }
+        boolean isStaticCtxt = (defaultType.resolveAsType() != null);
+        return new CodeSuggestions(atype, atype, null, isStaticCtxt);
+    }
+    
+    /**
+     * Remove a child node, and notify the NodeStructureListener that the child and
+     * its descendants have been removed.  Won't disturb the position of subsequent
+     * children. The "child" NodeAndPosition parameter specifies the absolute location
+     * of the child node, not its position relative to "this" node.
+     */
+    protected final void removeChild(NodeAndPosition<ParsedNode> child, NodeStructureListener listener)
+    {
+        child.getNode().remove();
+        childRemoved(child, listener);
+    }
+    
+    protected void childRemoved(NodeAndPosition<ParsedNode> child, NodeStructureListener listener)
+    {
+        listener.nodeRemoved(child);
+        removeChildren(child, listener);
+    }
+    
+    /**
+     * Notify the NodeStructureListener that all descendants of a particular node
+     * are removed, due to the node itself having been removed. (Note this does not actually
+     * remove the children from the parent node).
+     */
+    protected static void removeChildren(NodeAndPosition<ParsedNode> node, NodeStructureListener listener)
+    {
+        Iterator<NodeAndPosition<ParsedNode>> i = node.getNode().getChildren(node.getPosition());
+        while (i.hasNext()) {
+            NodeAndPosition<ParsedNode> nap = i.next();
+            listener.nodeRemoved(nap);
+            removeChildren(nap, listener);
+        }
+    }
+    
+    /**
+     * Check whether a documentary comment is attached to this node.
+     */
+    public boolean isCommentAttached()
+    {
+        return hasAttachedComment;
+    }
+    
+    /**
+     * Specify whether or not this node has a documentary comment attached to it.
+     */
+    public void setCommentAttached(boolean commentAttached)
+    {
+        hasAttachedComment = commentAttached;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParsedTypeNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParsedTypeNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..bcd98a24ef08dc2a1de434e178e8418bdf540563
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/ParsedTypeNode.java
@@ -0,0 +1,407 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.text.Document;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.Reflective;
+import bluej.editor.moe.MoeSyntaxDocument;
+import bluej.parser.CodeSuggestions;
+import bluej.parser.JavaParser;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.PackageOrClass;
+import bluej.parser.entity.ParsedReflective;
+import bluej.parser.entity.TparEntity;
+import bluej.parser.entity.TypeEntity;
+import bluej.parser.entity.ValueEntity;
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+
+
+/**
+ * A node representing a parsed type (class, interface, enum)
+ * 
+ * @author Davin McCall
+ */
+public class ParsedTypeNode extends IncrementalParsingNode
+{
+    private String name;
+    private String prefix;
+    private TypeInnerNode inner;
+    private List<TparEntity> typeParams;
+    private List<JavaEntity> extendedTypes;
+    private List<JavaEntity> implementedTypes;
+    private int modifiers;
+    private ParsedTypeNode containingClass;
+    
+    private int type; // one of JavaParser.TYPEDEF_CLASS, INTERFACE, ENUM, ANNOTATION
+    
+    /**
+     * Construct a new ParsedTypeNode.
+     * 
+     * @param parent  The parent node
+     * @param containingClass   The node representing the class containing this one
+     * @param type    The type of this type: JavaParser.{TYPEDEF_CLASS,_INTERFACE,_ENUM or _ANNOTATION}
+     * @param prefix  The prefix of the name, including the final ".", to make this a full
+     *                type name
+     * @param modifiers  The class modifiers (see java.lang.reflect.Modifier)
+     */
+    public ParsedTypeNode(JavaParentNode parent, ParsedTypeNode containingClass, int type, String prefix, int modifiers)
+    {
+        super(parent);
+        stateMarkers = new int[2];
+        marksEnd = new boolean[2];
+        stateMarkers[0] = -1;
+        stateMarkers[1] = -1;
+        this.type = type;
+        this.prefix = prefix;
+        this.modifiers = modifiers;
+        this.containingClass = containingClass;
+        
+        // Set defaults for various members
+        typeParams = Collections.emptyList();
+        extendedTypes = Collections.emptyList();
+        implementedTypes = Collections.emptyList();
+    }
+    
+    /**
+     * Gets the kind of type which this node represents. Returns one of:
+     * JavaParser.TYPEDEF_CLASS, _INTERFACE, _ENUM or _ANNOTATION
+     */
+    public int getTypeKind()
+    {
+        return type;
+    }
+    
+    /**
+     * Get the modifiers of the type this node represents (see java.lang.reflect.Modifier).
+     */
+    public int getModifiers()
+    {
+        return modifiers;
+    }
+    
+    /**
+     * Get the node representing the class containing this one.
+     */
+    public ParsedTypeNode getContainingClass()
+    {
+        return containingClass;
+    }
+    
+    /**
+     * Set the type parameters for this type (empty list for none).
+     */
+    public void setTypeParams(List<TparEntity> typeParams)
+    {
+        this.typeParams = typeParams;
+    }
+    
+    /**
+     * Get the type parameters for this type (empty list if none).
+     */
+    public List<TparEntity> getTypeParams()
+    {
+        return typeParams;
+    }
+    
+    /**
+     * Set the types that this type is declared to implement (empty list for none).
+     */
+    public void setImplementedTypes(List<JavaEntity> implementedTypes)
+    {
+        this.implementedTypes = implementedTypes;
+    }
+    
+    /**
+     * Get the types this type is declared to implement (empty list if none).
+     */
+    public List<JavaEntity> getImplementedTypes()
+    {
+        return implementedTypes;
+    }
+    
+    /**
+     * Specify which types this type explicitly extends (empty list for none).
+     */
+    public void setExtendedTypes(List<JavaEntity> extendedTypes)
+    {
+        this.extendedTypes = extendedTypes;
+    }
+    
+    /**
+     * Return the types which this type explicit extends.
+     * For an anonymous inner class, the returned list will contain a single
+     * type which may be a class or interface.
+     */
+    public List<JavaEntity> getExtendedTypes()
+    {
+        return extendedTypes;
+    }
+    
+    @Override
+    public int getNodeType()
+    {
+        return NODETYPE_TYPEDEF;
+    }
+    
+    @Override
+    public boolean isContainer()
+    {
+        return true;
+    }
+    
+    /**
+     * Set the unqualified name of the type this node represents.
+     */
+    public void setName(String name)
+    {
+        String oldName = this.name;
+        this.name = name;
+        getParentNode().childChangedName(this, oldName);
+    }
+    
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+    
+    /**
+     * Get the package qualification prefix for the type this node represents.
+     */
+    public String getPrefix()
+    {
+        return prefix;
+    }
+    
+    /**
+     * Insert the inner node for the type definition.
+     * The inner node will hold the field definitions etc.
+     */
+    public void insertInner(TypeInnerNode child, int position, int size)
+    {
+        super.insertNode(child, position, size);
+        inner = child;
+        stateMarkers[1] = position + size;
+    }
+    
+    /**
+     * Get the inner node for the type, if one exists. May return null.
+     */
+    public TypeInnerNode getInner()
+    {
+        return inner;
+    }
+    
+    @Override
+    protected void childRemoved(NodeAndPosition<ParsedNode> child,
+            NodeStructureListener listener)
+    {
+        if (child.getNode() == inner) {
+            inner = null;
+            stateMarkers[1] = -1;
+        }
+        super.childRemoved(child, listener);
+    }
+    
+    @Override
+    protected int doPartialParse(ParseParams params, int state)
+    {
+        if (state == 0) {
+            // [modifiers] {class|interface|enum|@interface} name [<type params>] [extends...]
+            LocatableToken la = params.tokenStream.LA(1);
+            setCommentAttached(la.getHiddenBefore() != null);
+            int r = params.parser.parseTypeDefBegin();
+            if (r == JavaParser.TYPEDEF_EPIC_FAIL) {
+                return PP_EPIC_FAIL;
+            }
+            
+            type = r;
+            params.parser.initializeTypeExtras();
+            
+            LocatableToken token = params.tokenStream.nextToken();
+            if (token.getType() != JavaTokenTypes.IDENT) {
+                last = token;
+                return PP_INCOMPLETE;
+            }
+            setName(token.getText());
+            
+            token = params.parser.parseTypeDefPart2();
+            if (token == null) {
+                last = params.tokenStream.LA(1);
+                return PP_INCOMPLETE;
+            }
+            last = token;
+            params.tokenStream.pushBack(token);
+            setExtendedTypes(params.parser.getExtendedTypes());
+            setTypeParams(params.parser.getTparList(this));
+            return PP_BEGINS_NEXT_STATE;
+        }
+        else if (state == 1) {
+            // '{' and class body
+            last = params.tokenStream.nextToken();
+            if (last.getType() != JavaTokenTypes.LCURLY) {
+                return PP_REGRESS_STATE;
+            }
+            
+            if (inner == null) {
+                int oldStateMarker = stateMarkers[1];
+                last = params.parser.parseTypeBody(type, last);
+                if (last.getType() == JavaTokenTypes.RCURLY) {
+                    inner.setComplete(true);
+                }
+                params.tokenStream.pushBack(last);
+                stateMarkers[1] = oldStateMarker; // let state transition magic work
+                return PP_BEGINS_NEXT_STATE;
+            }
+            
+            // If we already have an inner we pull it into position.
+            NodeAndPosition<ParsedNode> nextChild = params.childQueue.peek();
+            while (nextChild != null && nextChild.getNode() != inner) {
+                childRemoved(nextChild, params.listener);
+                params.childQueue.poll();
+                nextChild = params.childQueue.peek();
+            }
+            
+            params.abortPos = lineColToPos(params.document, last.getEndLine(), last.getEndColumn());
+            return PP_PULL_UP_CHILD;
+        }
+        else if (state == 2) {
+            // '}'
+            last = params.tokenStream.nextToken();
+
+            int innerOffset = inner.getOffsetFromParent();
+            int innerPos = innerOffset + params.nodePos;
+            int innerSize = inner.getSize();
+
+            if (last.getType() != JavaTokenTypes.RCURLY) {
+                // Extend the inner.
+                inner.setComplete(false);
+                inner.setSize(getSize() - innerOffset);
+                params.listener.nodeChangedLength(
+                        new NodeAndPosition<ParsedNode>(inner, innerPos, getSize() - innerOffset),
+                        innerPos,
+                        innerSize);
+                stateMarkers[1] = getSize();
+                params.document.scheduleReparse(innerPos + innerSize, getSize() - innerOffset - innerSize);
+                params.abortPos = innerPos + innerSize;
+                complete = false;
+                return PP_ABORT;
+            }
+            
+            // Extend the inner node up to the token we just pulled.
+            int lastPos = lineColToPos(params.document, last.getLine(), last.getColumn());
+            if ((innerPos + innerSize) != lastPos || ! inner.complete) {
+                // Expand the inner node to cover the RCURLY, which hopefully actually closes it,
+                // and re-parse
+                inner.complete = false;
+                lastPos = lineColToPos(params.document, last.getEndLine(), last.getEndColumn());
+                inner.setSize(lastPos - innerPos);
+                params.listener.nodeChangedLength(
+                        new NodeAndPosition<ParsedNode>(inner, innerPos, lastPos - innerPos),
+                        innerPos,
+                        innerSize);
+                stateMarkers[1] = lastPos - params.nodePos;
+                params.document.scheduleReparse(innerPos + innerSize, lastPos - innerPos - innerSize);
+                params.abortPos = innerPos + innerSize;
+                return PP_ABORT;
+            }
+            
+            return PP_ENDS_NODE_AFTER;
+        }
+        
+        return PP_EPIC_FAIL;
+    }
+    
+    @Override
+    protected boolean isDelimitingNode(NodeAndPosition<ParsedNode> nap)
+    {
+        return nap.getNode().isInner();
+    }
+    
+    @Override
+    protected boolean isNodeEndMarker(int tokenType)
+    {
+        return false;
+    }
+    
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return true;
+    }
+    
+    @Override
+    public void childResized(MoeSyntaxDocument document, int nodePos, NodeAndPosition<ParsedNode> child)
+    {
+        if (child.getNode() == inner) {
+            stateMarkers[1] = child.getEnd() - nodePos;
+        }
+    }
+    
+    @Override
+    public CodeSuggestions getExpressionType(int pos, int nodePos, JavaEntity defaultType, Document document)
+    {
+        valueEntityCache.clear();
+        pocEntityCache.clear();
+        
+        // The default type if the expression is not known should be this type
+        ValueEntity myType = new ValueEntity(new GenTypeClass(new ParsedReflective(this)));
+        NodeAndPosition<ParsedNode> child = getNodeTree().findNode(pos, nodePos);
+        if (child != null) {
+            return child.getNode().getExpressionType(pos, child.getPosition(), myType, document);
+        }
+        
+        // We don't return the specified default type (which must be an outer type). There
+        // can be no completions because no completions can occur except in the context
+        // of child nodes.
+        return null;
+    }
+    
+    @Override
+    public PackageOrClass resolvePackageOrClass(String name, Reflective querySource)
+    {
+        if (typeParams != null) {
+            JavaEntity ent = null;
+            for (TparEntity tent : typeParams) {
+                if (tent.getName().equals(name)) {
+                    ent = tent;
+                    break;
+                }
+            }
+            if (ent != null) {
+                TypeEntity tent = ent.resolveAsType();
+                if (tent != null) {
+                    return tent;
+                }
+            }
+        }
+        return super.resolvePackageOrClass(name, querySource);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/PkgStmtNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/PkgStmtNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..68545b97a9b94ad5c6cb7822c9a99ddd91033b96
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/PkgStmtNode.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+/**
+ * A node for representing package statements at the beginning of a
+ * compilation unit.
+ * 
+ * @author Davin McCall
+ */
+public class PkgStmtNode extends JavaParentNode
+{
+    public PkgStmtNode(JavaParentNode parent)
+    {
+        super(parent);
+    }
+    
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/RBTreeNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/RBTreeNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ef3876a2096e338d45385cda254988857f640c6
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/RBTreeNode.java
@@ -0,0 +1,94 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2009-2010  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+/**
+ * An RBTreeNode represents the value in a tree node represented by a NodeTree.
+ *  
+ * @author Davin McCall
+ */
+public class RBTreeNode<T extends RBTreeNode<T>>
+{
+    private NodeTree<T> containingNodeTree;
+
+    /**
+     * Set the containing node tree. This is normally only called by NodeTree when inserting
+     * this node into the tree.
+     */
+    protected final void setContainingNodeTree(NodeTree<T> cnode)
+    {
+        containingNodeTree = cnode;
+    }
+    
+    /**
+     * Get the containing node tree for this node.
+     * @return
+     */
+    protected final NodeTree<T> getContainingNodeTree()
+    {
+        return containingNodeTree;
+    }
+    
+    /**
+     * Move the node. This also has the effect of moving all following nodes.
+     * @param offset  The amount by which to move the node
+     */
+    public void slide(int amount)
+    {
+        getContainingNodeTree().slideNode(amount);
+    }
+
+    /**
+     * Move the node's beginning, but not its end position. This shrinks or grows
+     * the node accordingly. The position of following nodes is not affected.
+     */
+    public void slideStart(int offset)
+    {
+        getContainingNodeTree().slideStart(offset);
+    }
+    
+    /**
+     * Set the size of this node. Following nodes shift position according to the change in
+     * size; this should normally be used when inserting or removing text from the node.
+     * @param newSize  The new node size
+     */
+    public void resize(int newSize)
+    {
+        getContainingNodeTree().resize(newSize);
+    }
+    
+    /**
+     * Set the size of this node, without moving following nodes. It is the caller's
+     * responsibility to ensure that setting the new size does not cause this node
+     * to overlap following nodes.
+     * @param newSize  The new size of this node.
+     */
+    public void setSize(int newSize)
+    {
+        getContainingNodeTree().setSize(newSize);
+    }
+    
+    public void remove()
+    {
+        getContainingNodeTree().remove();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/TypeInnerNode.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/TypeInnerNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..21aa431c0899283e35c16130ca4df0602efb50de
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/nodes/TypeInnerNode.java
@@ -0,0 +1,150 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.nodes;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.parser.lexer.JavaTokenTypes;
+import bluej.parser.lexer.LocatableToken;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+
+/**
+ * Node for the inner part of a type definition. This contains the declarations inside
+ * the type.
+ * 
+ * @author Davin McCall
+ */
+public class TypeInnerNode extends IncrementalParsingNode
+{
+    private Map<String,Set<MethodNode>> methods = new HashMap<String,Set<MethodNode>>();
+
+    public TypeInnerNode(JavaParentNode parent)
+    {
+        super(parent);
+    }
+    
+    @Override
+    public boolean isInner()
+    {
+        return true;
+    }
+        
+    /**
+     * A method was added.
+     */
+    public void methodAdded(MethodNode method)
+    {
+        String name = method.getName();
+        Set<MethodNode> methodSet = methods.get(name);
+        if (methodSet == null) {
+            methodSet = new HashSet<MethodNode>();
+            methods.put(name, methodSet);
+        }
+        methodSet.add(method);
+    }
+    
+    @Override
+    public void childChangedName(ParsedNode child, String oldName)
+    {
+        super.childChangedName(child, oldName);
+        if (child.getNodeType() == NODETYPE_METHODDEF) {
+            Set<MethodNode> methodSet = methods.get(oldName);
+            methodSet.remove(child);
+            
+            methodAdded((MethodNode) child);
+        }
+    }
+    
+    @Override
+    protected void childRemoved(NodeAndPosition<ParsedNode> child,
+            NodeStructureListener listener)
+    {
+        super.childRemoved(child, listener);
+        if (child.getNode().getNodeType() == NODETYPE_METHODDEF) {
+            Set<MethodNode> methodSet = methods.get(child.getNode().getName());
+            methodSet.remove(child.getNode());
+        }
+    }
+    
+    /**
+     * Get the fields defined in this type.
+     */
+    public Map<String, FieldNode> getFields()
+    {
+        return variables;
+    }
+    
+    /**
+     * Get the methods defined in this type.
+     */
+    public Map<String,Set<MethodNode>> getMethods()
+    {
+        return methods;
+    }
+    
+    @Override
+    protected int doPartialParse(ParseParams params, int state)
+    {
+        last = null;
+        LocatableToken nextToken = params.tokenStream.nextToken();
+                
+        if (nextToken.getType() == JavaTokenTypes.RCURLY) {
+            last = nextToken;
+            return PP_ENDS_NODE;
+        }
+        if (nextToken.getType() == JavaTokenTypes.EOF) {
+            // We don't really know if the last partial was successful or not.
+            last = nextToken;
+            return PP_INCOMPLETE;
+        }
+        
+        if (checkBoundary(params, nextToken)) {
+            last = nextToken;
+            return PP_PULL_UP_CHILD;
+        }
+        
+        params.parser.parseClassElement(nextToken);
+        complete = false;
+        return PP_OK;
+    }
+    
+    @Override
+    protected boolean isDelimitingNode(NodeAndPosition<ParsedNode> nap)
+    {
+        return nap.getNode().isContainer();
+    }
+    
+    @Override
+    protected boolean marksOwnEnd()
+    {
+        return false;
+    }
+    
+    @Override
+    public boolean growsForward()
+    {
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/symtab/ClassInfo.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/symtab/ClassInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..b129bb698dfec96d908af49120f7e92f32f7315b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/symtab/ClassInfo.java
@@ -0,0 +1,555 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.symtab;
+
+import java.util.*;
+
+import bluej.utility.JavaUtils;
+import bluej.utility.SortedProperties;
+
+/**
+ * Information about a class found in a source file. The information is
+ * gathered and stored in an object of this class by a parser.<p>
+ * 
+ * The information includes:<ul> 
+ * <li>what is the name of this class or interface;
+ * <li>is it a class or an interface or an enum;
+ * <li>is it declared abstract;
+ * <li>what classes are extended and interfaces are implemented;
+ * <li>what are the type parameters;
+ * <li>what other types are referenced from within this type;
+ * <li>what javadoc comments are present; 
+ * <li>the selection (location in text) for the superclass, superinterfaces,
+ * and various other things including type parameters.
+ * </ul><p>
+ * 
+ * Some other information, such as classes which are imported, is stored but
+ * not used in BlueJ.
+ */
+public final class ClassInfo
+{
+    private static final String[] appletClasses = { "java.applet.Applet", "javax.swing.JApplet" };
+    private static final String[] unitTestClasses = { "junit.framework.TestCase" };
+    private static final String[] midletClasses = { "javax.microedition.midlet.MIDlet" }; 
+
+    private boolean foundPublicClass = false;
+
+    private String name;
+    private String superclass;
+
+    private List<String> implemented = new ArrayList<String>();
+    private List<String> imported = new ArrayList<String>();
+    private List<String> used = new ArrayList<String>();
+    private List<SavedComment> comments = new LinkedList<SavedComment>();
+    
+    private List<String> typeParameterTexts;
+    private Selection typeParametersSelection;
+    private Selection extendsReplaceSelection;
+
+    // how we would replace the superclass name in a class
+    private Selection superReplaceSelection;
+
+    private boolean isInterface = false;
+    private boolean isAbstract = false;
+    private boolean isApplet = false;
+    private boolean isUnitTest = false;
+    private boolean isEnum = false;
+    private boolean isMIDlet = false;
+    
+    private boolean hadParseError = false;
+
+    private class SavedComment
+    {
+        public String target;   // the method signature of the item we have a
+                                // comment for. Can be class name or interface
+                                // name in the case of a comment for a whole
+                                // class/interface
+
+        public String comment;  // the actual text of the comment
+
+        public String paramnames;   // if this is a method or constructor, then
+                                    // this is a comma seperated list of name
+                                    // associated with the parameters
+
+        public SavedComment(String target, String comment, String paramnames)
+        {
+            if (target == null)
+                throw new NullPointerException();
+            this.target = target;
+            this.comment = comment;
+            this.paramnames = paramnames;
+        }
+
+        public void save(Properties p, String prefix)
+        {
+            p.put(prefix + ".target", target);
+            if(comment != null)
+                p.setProperty(prefix + ".text", comment);
+            if(paramnames != null)
+                p.setProperty(prefix + ".params", paramnames);
+        }
+    }
+
+    /**
+     * Check whether a public class (interface, enum) was found.
+     */
+    public boolean foundPublicClass()
+    {
+        return foundPublicClass;
+    }
+
+    /**
+     * Set the name of the class/interface/enum.
+     */
+    public void setName(String name, boolean pub)
+    {
+        this.name = name;
+
+        if(pub) {
+            foundPublicClass = true;
+        }
+    }
+
+    public void setSuperclass(String name)
+    {
+        if(name.equals(this.name)) {
+            return;
+        }
+
+        superclass = name;
+        if(used.contains(name)) {
+            used.remove(name);
+        }
+
+        for (int i = 0; i < appletClasses.length; i++) {
+            if(name.equals(appletClasses[i])) {
+                isApplet = true;
+            }
+        }
+
+        for (int i = 0; i < unitTestClasses.length; i++) {
+            if(name.equals(unitTestClasses[i])) {
+                isUnitTest = true;
+            }
+        }
+        
+        for (int i = 0; i < midletClasses.length; i++) {
+            if(name.equals(midletClasses[i])) {
+                isMIDlet = true;
+            }
+        }
+    }
+    
+    public void setEnum(boolean isEnum)
+    {
+        this.isEnum = isEnum;
+    }
+
+    public void addImplements(String name)
+    {
+        if(name.equals(this.name))
+            return;
+
+        if(!implemented.contains(name))
+            implemented.add(name);
+    }
+    
+    public void addImported(String name)
+    {
+        if(name.equals(this.name))
+            return;
+    
+        if(!imported.contains(name))
+            imported.add(name);
+    }
+
+    public void addUsed(String name)
+    {
+        if(name.equals(this.name))
+            return;
+
+        // don't add predefined types (int, boolean, String, etc)
+        //if(SymbolTable.getPredefined().contains(name))
+        //    return;
+
+        // don't add superclass
+        if(name.equals(superclass))
+            return;
+
+        // don't add if already there
+        if(! used.contains(name))
+            used.add(name);
+    }
+
+    /**
+     * Add a method/constructor description (with optional javadoc comment) to this
+     * class. The target specifies the method or constructor which the comment applies
+     * to. It takes the form:<p>
+     * 
+     *  <code>&lt;type-pars&gt; return_type method_name(arg_type_1,arg_type2,arg_type3)</code>
+     * 
+     * <p>Where:
+     * <ul>
+     * <li>type-pars are the type parameters, in the form
+     *    "&ltT extends bound-type,U extends bound-type&gt;". Should not be present if there are no
+     *    type parameters.
+     * <li>return_type is the generic return type, or null for a constructor
+     * <li>method_name is the name of the method (or the class name for a constructor)
+     * <li>arg_type_X is the generic parameter type, followed by "[]" if an array type
+     *     (eg. List&lt;Thread&gt;[][]), followed by " ..." for a vararg parameter.
+     * </ul>
+     * 
+     * @param target  The method/constructor the comment applies to (see description above)
+     * @param comment   The comment text (may be null)
+     * @param paramnames  The parameter names from the method definition, as a space-seperated
+     *                    list. May be null if there are no parameter names.
+     */
+    public void addComment(String target, String comment, String paramnames)
+    {
+        // remove asterisks (*) from beginning of comment
+        comment = JavaUtils.javadocToString(comment);
+        comments.add(new SavedComment(target, comment, paramnames));
+    }
+
+    public void setInterface(boolean b)
+    {
+        isInterface = b;
+    }
+
+    public void setAbstract(boolean b)
+    {
+        isAbstract = b;
+    }
+
+    public void setParseError(boolean err)
+    {
+        hadParseError = err;
+    }
+    
+    /**
+     * Where we would insert the string "extends" in a class/interface
+     */
+    private Selection extendsInsertSelection;
+
+    /**
+     * Record where we would insert the string "extends" in a class or interface.
+     * For a class/interface which already extends other classes/interfaces, should
+     * be set to null.
+     *
+     * @param s the Selection object which records a location to
+     *          insert the "extends" keyword or additional interface
+     */
+    public void setExtendsInsertSelection(Selection s)
+    {
+        extendsInsertSelection = s;
+    }
+
+    /**
+     * Returns where we would insert the string "extends" in a class/interface.
+     * For a class which already extends another classes, returns null.
+     * 
+     * For an interface which extends no other interfaces, returns where to
+     * insert "extends {super-interface-name}". For an interface which extends
+     * one or more other interfaces already, returns where to insert
+     * ", {additional-interface-name}".
+     *
+     * @returns s the Selection object which records a location to
+     *          insert the "extends" keyword
+     */
+    public Selection getExtendsInsertSelection()
+    {
+        return extendsInsertSelection;
+    }
+
+    /**
+     * Where we would insert the string " implements " in a class, or, if the
+     * class has existing interfaces, where we would add a new one in
+     * (as ", [interfacename]").
+     */
+    private Selection implementsInsertSelection;
+
+    /**
+     * Where we would insert the string " implements " in a class, or, if the
+     * class has existing interfaces, where we would add a new one in
+     * (as ", [interfacename]").
+     */
+    public void setImplementsInsertSelection(Selection s)
+    {
+        implementsInsertSelection = s;
+    }
+
+    /**
+     * Where we would insert the string " implements " in a class, or, if the
+     * class has existing interfaces, where we would add a new one in
+     * (as ", [interfacename]").
+     */
+    public Selection getImplementsInsertSelection()
+    {
+        return implementsInsertSelection;
+    }
+
+    /**
+     * Record how we would replace the string "extends" in a class.
+     * (For an interface, this is the first selection in the
+     *  InterfaceSelections list - see setInterfaceSelections)
+     *
+     * @param s the Section object which records the location of
+     *          the "extends" keyword for a class
+     */
+    public void setExtendsReplaceSelection(Selection s)
+    {
+        extendsReplaceSelection = s;
+    }
+
+    /**
+     * How we would replace the string "extends" in a class.
+     * (For an interface, this is the first selection in the
+     *  InterfaceSelections list - see setInterfaceSelections)
+     */
+    public Selection getExtendsReplaceSelection()
+    {
+        return extendsReplaceSelection;
+    }
+
+    public void setSuperReplaceSelection(Selection s)
+    {
+        superReplaceSelection = s;
+    }
+
+    public Selection getSuperReplaceSelection()
+    {
+        return superReplaceSelection;
+    }
+
+    // a vector of Selections of all the elements in a classes
+    // "implements" clause ie.
+    //     "implements" "InterfaceA" "," "InterfaceB"
+    // ... or an interface's "extends" clause ie.
+    //     "extends" "InterfaceA" "," "InterfaceB"
+    // ... or null if there is no clause
+    private List<Selection> interfaceSelections;
+
+    /**
+     * Set the selections for the interfaces, including the "implements" clause (or "extends"
+     * for interfaces), the interfaces themselves, and the commas between them. Eg:
+     * 
+     * "extends"  "InterfaceA"  ","  "InterfaceB"
+     */
+    public void setInterfaceSelections(List<Selection> selections)
+    {
+        interfaceSelections = selections;
+    }
+    
+    public List<String> getTypeParameterTexts()
+    {
+        return typeParameterTexts;
+    }
+
+    public List<Selection> getInterfaceSelections()
+    {
+        return interfaceSelections;
+    }
+
+    public boolean hasInterfaceSelections()
+    {
+        return (interfaceSelections != null) &&
+                (interfaceSelections.size() > 0);
+    }
+
+    /**
+     * Record the locations of the tokens in a source files "package" statement.
+     *
+     * These locations start off at the first line and column of a file.
+     * If a package line exists, they are updated, otherwise they are
+     * left pointing the very start of the file (which is where we would
+     * want to insert a package line if we were to add one)
+     */
+    private boolean packageStatementExists = false;
+    private Selection packageStatementSelection = new Selection(1,1);
+    private Selection packageNameSelection = new Selection(1,1);
+    private Selection packageSemiSelection = new Selection(1,1);
+    private String packageName = "";
+
+    /**
+     * Set the selections for the "package" line of the source file, including the "pakage"
+     * keyword (pkgStatement), the named package (pkgName), and the trailing semicolon
+     * (pkgSemi).
+     * 
+     * @param pkgStatement
+     * @param pkgName
+     * @param pkgNameText
+     * @param pkgSemi
+     */
+    public void setPackageSelections(Selection pkgStatement, Selection pkgName, String pkgNameText,
+                                        Selection pkgSemi)
+    {
+        packageStatementSelection = pkgStatement;
+        packageNameSelection = pkgName;
+        packageName = pkgNameText;
+        packageSemiSelection = pkgSemi;
+
+        packageStatementExists = true;
+    }
+
+    public boolean hasPackageStatement()
+    {
+        return packageStatementExists;
+    }
+
+    public Selection getPackageStatementSelection()
+    {
+        return packageStatementSelection;
+    }
+
+    public Selection getPackageNameSelection()
+    {
+        return packageNameSelection;
+    }
+
+    public Selection getPackageSemiSelection()
+    {
+        return packageSemiSelection;
+    }
+
+    public String getPackage()
+    {
+        return packageName;
+    }
+
+
+
+    // accessors:
+
+    /**
+     * Get the (fully-qualified) name of the superclass of the represented class.
+     * Returns null if the superclass is not established or unspecified (i.e. is
+     * "java.lang.Object").
+     */
+    public String getSuperclass()
+    {
+        return superclass;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    /**
+     * Get a list of the (fully-qualified) interface names that the represented
+     * class implements.
+     */
+    public List<String> getImplements()
+    {
+        return implemented;
+    }
+
+    public void setTypeParametersSelection(Selection s)
+    {
+        typeParametersSelection = s;
+    }
+    
+    public boolean hasTypeParameter()
+    {
+        return (typeParametersSelection != null);
+    }
+    
+    /**
+     * Get the list of referenced classes (a list of String).
+     */
+    public List<String> getUsed()
+    {
+        return used;
+    }
+
+    public Properties getComments()
+    {
+        Properties props = new SortedProperties();
+        props.setProperty("numComments", String.valueOf(comments.size()));
+        Iterator<SavedComment> it = comments.iterator();
+        for(int i = 0; it.hasNext(); i++)
+        {
+            SavedComment c = it.next();
+            c.save(props, "comment" + i);
+        }
+        return props;
+    }
+
+    public boolean isInterface()
+    {
+        return this.isInterface;
+    }
+
+    public boolean isAbstract()
+    {
+        return this.isAbstract;
+    }
+
+    public boolean isApplet()
+    {
+        return this.isApplet;
+    }
+
+    public boolean isMIDlet()
+    {
+        return this.isMIDlet;
+    }
+    
+    public boolean isUnitTest()
+    {
+        return this.isUnitTest;
+    }
+    
+    public boolean isEnum()
+    {
+        return this.isEnum;
+    }
+
+    public boolean hadParseError()
+    {
+        return hadParseError;
+    }
+
+    public void print()
+    {
+        System.out.println();
+        System.out.println("superclass: " + superclass);
+
+        System.out.println();
+        System.out.println("implements:");
+        Iterator<String> it = implemented.iterator();
+        while(it.hasNext())
+            System.out.println("   " + (String)it.next());
+
+        System.out.println();
+        System.out.println("uses:");
+        it = used.iterator();
+        while(it.hasNext())
+            System.out.println("   " + (String)it.next());
+
+        System.out.println();
+        System.out.println("imports:");
+        it = imported.iterator();
+        while(it.hasNext())
+            System.out.println("   " + (String)it.next());
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/parser/symtab/Selection.java b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/symtab/Selection.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd8bca240246d77259264ff533864cfad82a730c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/parser/symtab/Selection.java
@@ -0,0 +1,137 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.parser.symtab;
+
+import bluej.parser.SourceLocation;
+import bluej.parser.SourceSpan;
+
+/*******************************************************************************
+ * An occurrence of an indentifier in a file
+ ******************************************************************************/
+// TODO, get rid of this class, just use SourceSpan
+public class Selection /* extends Occurrence */
+{
+    // private int len;
+    private SourceSpan sspan;
+    //private String origText;
+
+    //==========================================================================
+    //==  Methods
+    //==========================================================================
+
+    /**
+     * Constructor to define an empty selection at a given location.
+     */
+    public Selection(int line, int column)
+    {
+        SourceLocation sl = new SourceLocation(line, column);
+        sspan = new SourceSpan(sl, sl);
+    }
+    
+    public Selection(SourceSpan ss)
+    {
+        sspan = ss;
+    }
+    
+    /**
+     * Constructor for a selection which occupies part of a single line.
+     * @param line    The line
+     * @param column  The starting column
+     * @param length  The length of the selection
+     */
+    public Selection(int line, int column, int length)
+    {
+        SourceLocation start = new SourceLocation(line, column);
+        SourceLocation end = new SourceLocation(line, column + length);
+        sspan = new SourceSpan(start, end);
+    }
+    
+    /**
+     * Combine two selections. The result will comprise of both the original and
+     * the other selection, plus any space in between.
+     */
+    public void combineWith(Selection other)
+    {
+        int otherstartl = other.getLine();
+        int otherstartc = other.getColumn();
+        int mystartl = getLine();
+        int mystartc = getColumn();
+        
+        SourceLocation newStart = null;
+        SourceLocation newEnd = null;
+        
+        if (otherstartl < mystartl || (otherstartl == mystartl && otherstartc < mystartc))
+            newStart = other.getStartLocation();
+        
+        int otherendl = other.getEndLine();
+        int otherendc = other.getEndColumn();
+        int myendl = getEndLine();
+        int myendc = getEndColumn();
+        
+        if (otherendl > myendl || (otherendl == myendl && otherendc > myendc))
+            newEnd = other.getEndLocation();
+     
+        if (newStart != null || newEnd != null) {
+            if (newStart == null)
+                newStart = getStartLocation();
+            if (newEnd == null)
+                newEnd = getEndLocation();
+            sspan = new SourceSpan(newStart, newEnd);
+        }
+    }
+    
+    public void extendEnd(int line, int column)
+    {
+        int myline = getEndLine();
+        if (line >= myline) {
+            int mycol = getEndColumn();
+            if (column >= mycol || line > myline) {
+                SourceLocation newEnd = new SourceLocation(line, column);
+                SourceLocation newStart = getStartLocation();
+                sspan = new SourceSpan(newStart, newEnd);
+            }
+        }
+    }
+    
+    public void extendEnd(SourceLocation sl)
+    {
+        extendEnd(sl.getLine(), sl.getColumn());
+    }
+
+    public int getLine() { return sspan.getStartLine(); }
+    public int getColumn() { return sspan.getStartColumn(); }
+    public SourceLocation getStartLocation() { return sspan.getStartLocation(); }
+    
+    public int getEndLine() { return sspan.getEndLine(); }
+    public int getEndColumn() { return sspan.getEndColumn(); }
+    public SourceLocation getEndLocation() { return sspan.getEndLocation(); }
+        
+    /** return a string representation of the occurrence */
+    public String getLocation() {
+        return "[" + sspan.toString() + "]";
+    }
+
+    /** return a string representation of the occurrence */
+    public String toString() {
+        return "Selection " + getLocation();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/AboutBlue.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/AboutBlue.java
new file mode 100644
index 0000000000000000000000000000000000000000..89c35f44a74654d3908142f0dc5267bc2901c4c1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/AboutBlue.java
@@ -0,0 +1,163 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import bluej.*;
+import bluej.Config;
+import bluej.utility.EscapeDialog;
+import bluej.utility.MultiLineLabel;
+import bluej.utility.DialogManager;
+
+import bluej.utility.Utility;
+import java.net.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * The BlueJ about box.
+ *
+ * @author  Michael Kolling
+ * @version $Id: AboutBlue.java 9004 2011-06-16 13:15:21Z mik $
+ */
+class AboutBlue extends EscapeDialog
+{
+    private static final String BLUEJ_URL = "http://www.bluej.org";
+    private static final Color linkColor = new Color(0, 76, 134);
+
+    public AboutBlue(JFrame parent, String version)
+    {
+        super(parent, Config.getString("menu.help.about"), true);
+
+        // Create About box text
+        JPanel aboutPanel = new JPanel();
+        aboutPanel.setBorder(BlueJTheme.dialogBorder);
+        aboutPanel.setLayout(new BorderLayout(12,0));
+        aboutPanel.setBackground(Color.white);
+
+        // insert logo
+        Icon icon = Config.getFixedImageAsIcon("about-logo.jpg");
+        JLabel logoLabel = new JLabel(icon);
+        aboutPanel.add(logoLabel, BorderLayout.WEST);
+
+        // Create Text Panel
+        MultiLineLabel text = new MultiLineLabel(LEFT_ALIGNMENT, 6);
+        text.setBackground(Color.white);
+        text.addText(Config.getString("about.theTeam") + "\n ", false, true);
+        text.addText("  Neil Brown\n");
+        text.addText("  Michael K\u00F6lling\n");
+        text.addText("  Davin McCall\n");
+        text.addText("  Philip Stevens\n");
+        text.addText("  John Rosenberg\n");
+        text.addText("  Ian Utting\n");
+        text.addText("  Marion Zalk");
+
+        aboutPanel.add(text, BorderLayout.CENTER);
+
+        JPanel bottom = new JPanel();
+        bottom.setLayout(new BoxLayout(bottom, BoxLayout.PAGE_AXIS));
+        bottom.setBackground(Color.white);
+
+        // footer text
+        MultiLineLabel bottomtext = new MultiLineLabel(LEFT_ALIGNMENT);
+        bottomtext.setBackground(Color.white);
+        bottomtext.addText(" ");
+        bottomtext.addText(Config.getString("about.bluej.version") + " "+ version +
+                "  (" + Config.getString("about.java.version") + " " + System.getProperty("java.version") +
+                ")", true, false);
+        bottomtext.addText(" ");
+        bottomtext.addText(Config.getString("about.vm") + " " +
+                System.getProperty("java.vm.name") + " " +
+                System.getProperty("java.vm.version") +
+                " (" + System.getProperty("java.vm.vendor") + ")");
+        bottomtext.addText(Config.getString("about.runningOn") + " " + System.getProperty("os.name") +
+                " " + System.getProperty("os.version") +
+                " (" + System.getProperty("os.arch") + ")");
+        bottomtext.addText(Config.getString("about.javahome") + " " + System.getProperty("java.home"));
+        bottomtext.addText(" ");
+        bottomtext.addText(Config.getString("about.logfile") + " " + Config.getUserConfigFile(Config.debugLogName));
+        bottomtext.addText(" ");
+        
+        bottom.add(bottomtext);
+
+        try {
+            final URL bluejURL = new URL(BLUEJ_URL);
+            JLabel urlField = new JLabel(BLUEJ_URL);
+            urlField.setCursor(new Cursor(Cursor.HAND_CURSOR));
+            urlField.setForeground(linkColor);
+            urlField.addMouseListener(new MouseAdapter()  {
+                public void mouseClicked(MouseEvent e) {
+                    Utility.openWebBrowser(bluejURL.toExternalForm());
+                }
+            });
+
+            JPanel urlPanel = new JPanel();
+            urlPanel.setBackground(Color.white);
+            urlPanel.setAlignmentX(0.0F);
+            urlPanel.add(new JLabel(Config.getString("about.moreInformation")));
+            urlPanel.add(urlField);
+
+            bottom.add(urlPanel);
+        }
+        catch (MalformedURLException exc) {
+            // should not happen - URL is constant
+        }
+
+        aboutPanel.add(bottom, BorderLayout.SOUTH);
+
+
+        // Create Button Panel
+        JPanel buttonPanel = new JPanel();
+        //buttonPanel.setBackground(Color.white);
+        buttonPanel.setLayout(new FlowLayout());
+        JButton ok = BlueJTheme.getOkButton();
+        buttonPanel.add(ok);
+
+        getContentPane().setLayout(new BorderLayout());
+        getContentPane().add(aboutPanel, BorderLayout.CENTER);
+        getContentPane().add(buttonPanel, BorderLayout.SOUTH);
+
+        // Close Action when OK is pressed
+        ok.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event)
+                {
+                    setVisible(false);
+                    dispose();
+                }
+        });
+
+        // Close Action when close button is pressed
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent event)
+                {
+                    Window win = (Window)event.getSource();
+                    win.setVisible(false);
+                    win.dispose();
+                }
+        });
+
+        setResizable(false);
+        pack();
+        DialogManager.centreDialog(this);
+    }
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/AppletParam.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/AppletParam.java
new file mode 100644
index 0000000000000000000000000000000000000000..437848eecd2af2755f5a676b0b4db75558579697
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/AppletParam.java
@@ -0,0 +1,117 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr; 
+
+
+/**
+ * Holds an Applet param entry for use in generating HTML page for Applet.
+ * Can be created from user input via RunAppletDialog or from reading in from
+ * saved project properties.
+ *
+ * @author  Bruce Quig
+ * @version $Id: AppletParam.java 8121 2010-08-20 04:20:13Z davmac $
+ */
+public final class AppletParam 
+{
+    public static final String PARAM = "PARAM";
+    public static final String NAME = "NAME";
+    public static final String PARAM_NAME = PARAM + " " + NAME;
+    public static final String VALUE = "VALUE";
+    
+    private String paramName;
+    private String paramValue;
+    
+    
+    /**
+     * Constructor for creating from input values of key and value
+     * @param key name of parameter
+     * @param value  value of parameter
+     */    
+    public AppletParam(String key, String value) 
+    {
+        paramName = key;
+        paramValue = value;
+    }        
+    
+    /**
+     * Constructor for creating from a stored parameter String
+     * eg. < PARAM NAME=foo VALUE=bar >
+     * @param parameterString  
+     */    
+    public AppletParam(String parameterString) 
+    {
+        //need to parse parameter line and recreate AppletParam object
+        // (?i) ignore case
+        String nameRegEx = "(?i)\\s*<\\s*PARAM NAME\\s*=\\s*\"?|\"?\\s*VALUE\\s*=.*";        
+        String[] names = parameterString.split(nameRegEx);
+        paramName = names[1];
+        
+        String valueRegEx = "(?i).*VALUE\\s*=\\s*\"?|\"?\\s*>\\s*";
+        String[] values = parameterString.split(valueRegEx);
+        paramValue = values[1];
+    }    
+    
+    /** 
+     * Getter for property paramValue.
+     * @return Value of property paramValue.
+     */
+    public String getParamValue() 
+    {
+        return paramValue;
+    }    
+      
+  
+    /** 
+     * Getter for property paramName.
+     * @return Value of property paramName.
+     */
+    public String getParamName() 
+    {
+        return paramName;
+    }    
+    
+    
+    /**
+     * Equality relates to the name of the Applet param name so that AppletParam
+     * can easily be found in a list or DefaultListModel for location and 
+     * replacement.  
+     * @param obj object being evaluated against
+     * @return true if considered equivalent 
+     */    
+    public boolean equals(Object obj) {
+        boolean retValue = false;
+        if(obj instanceof AppletParam) {
+            retValue = paramName.equals(((AppletParam)obj).getParamName());
+        }
+        return retValue;
+    }
+    
+    /**
+     * redefined toString method, used to provide the param string for
+     * the html page
+     */
+    public String toString() {
+        return "<" + PARAM_NAME + " = \"" + paramName
+        + "\"   " + VALUE + " = \"" + paramValue + "\">";        
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/BlueJPackageFile.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/BlueJPackageFile.java
new file mode 100644
index 0000000000000000000000000000000000000000..461fa1ac88bfc3b2e9f01cdd3006a4f38b38ff2b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/BlueJPackageFile.java
@@ -0,0 +1,251 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * Reference to the BlueJ package file(s). This includes references to the old
+ * file called bluej.pkg as well as the current file named package.bluej.
+ * 
+ * There are (or will be) three versions of BlueJ that handles these package
+ * files differently:
+ * 
+ * <ul>
+ * <li><i>Old BlueJ:</i> support only the .pkg extension. This is all versions
+ * before BlueJ 2.3.0.</li>
+ * 
+ * 
+ * <li><i>Transition BlueJ:</i> support both .pkg and .bluej extension. If .pkg
+ * exists, it will load from this file. It will always attempt to save to both
+ * .bluej and .pkg. The first transition version is BlueJ 2.3.0.</li>
+ * 
+ * <li><i>New BlueJ:</i> support for .bluej, and limited for .pkg. If .pkg
+ * exists, it will load from this file. If .pkg doesn't exist it is NOT created.
+ * It will always attempt to save to .bluej. If .pkg exists it will also save to
+ * that. No versions of this exists yet. This has been implemented in version 
+ * 2.6.0</li>
+ * <ul>
+ * 
+ * One implication of this is that a project that has been created with a New
+ * version of BlueJ can not be opened with an Old version of BlueJ (it can be
+ * opened by a Transition version though). The alternative would be to keep the
+ * .pkg around forever, which is not what we want. And if the transition period
+ * is long enough, it should not create to many problems.
+ * 
+ * @author Poul Henriksen
+ */
+public class BlueJPackageFile
+    implements PackageFile
+{
+    private static final String pkgfileName = "package.bluej";
+    private static final String oldPkgfileName = "bluej.pkg";
+
+    private File dir;
+    private File pkgFile;
+    private File oldPkgFile;
+
+    /**
+     * @see PackageFileFactory
+     */
+    BlueJPackageFile(File dir)
+    {
+        this.dir = dir;
+        this.pkgFile = new File(dir, pkgfileName);
+        this.oldPkgFile = new File(dir, oldPkgfileName);
+    }
+
+    public String toString()
+    {
+        return "BlueJ package file in: " + dir.toString();
+    }
+
+    /**
+     * Whether a BlueJ package file exists in this directory.
+     */
+    public static boolean exists(File dir)
+    {
+        if (dir == null)
+            return false;
+
+        // don't try to test Windows root directories (you'll get in
+        // trouble with disks that are not in drives...).
+
+        if (dir.getPath().endsWith(":\\"))
+            return false;
+
+        if (!dir.isDirectory())
+            return false;
+
+        File packageFile = new File(dir, pkgfileName);
+        if (packageFile.exists()) {
+            return true;
+        }
+
+        File oldPackageFile = new File(dir, oldPkgfileName);
+        return oldPackageFile.exists();
+    }
+
+    /**
+     * Will first try to load from the old package file (.pkg) if that fails, it
+     * will try to load from the new one (package.bluej)
+     */
+    public void load(Properties p)
+        throws IOException
+    {
+        FileInputStream input = null;
+        try {
+            // First, try to load from the new  package file since, if it exists,
+            // will be the most up-to-date.
+            if (pkgFile.canRead()) {
+                input = new FileInputStream(pkgFile);
+            }
+            else if (oldPkgFile.canRead()) {
+                input = new FileInputStream(oldPkgFile);
+            }
+            else {
+                throw new IOException("Can't read from package file(s) in: " + this);
+            }
+            p.load(input);
+        }
+        finally {
+            if (input != null) {
+                input.close();
+            }
+        }
+    }
+
+    /**
+     * Save the given properties to the file.
+     * <p>
+     * 
+     * Store properties to both package files. This method will always attempt
+     * to store the properties to both package files (.bluej and .pkg).
+     * <p>
+     * 
+     * It should fail if the oldPkgFile exists but can't be written, because
+     * this is the first one to be loaded if both exists and it would then
+     * result in inconsistent properties. If it manages to store to the
+     * oldPkgFile it doesn't matter if it fails to store to the new one, since
+     * whenever the old one is present, that will be loaded first in all
+     * versions of BlueJ.
+     * 
+     * @throws IOException if something goes wrong while trying to write the
+     *             properties.
+     */
+    public void save(Properties props)
+        throws IOException
+    {
+        // TODO: In some future version of BlueJ the createNewFile invocation
+        // below should be removed to get rid of the old .pkg file.
+        //
+        // And, when the invocation is removed the Javadoc for the method should
+        // include the following lines:
+        //
+        // * Store properties to both package files. It always try to store to
+        // * the pkgFile, and if the oldPkgFile exists it will also try to store
+        // * to that.
+
+        if (oldPkgFile.exists()) {
+            if (!oldPkgFile.canWrite()) {
+                throw new IOException("BlueJ package file not writable: " + oldPkgFile);
+            }
+            saveToFile(props, oldPkgFile);
+        }
+
+        pkgFile.createNewFile();
+        if (!pkgFile.canWrite()) {
+                throw new IOException("BlueJ package file not writable: " + pkgFile);
+        }
+        else {
+            saveToFile(props, pkgFile);
+        }
+    }
+
+    private void saveToFile(Properties props, File file)
+        throws IOException
+    {
+        FileOutputStream output = null;
+        try {
+            output = new FileOutputStream(file);
+            String header = "BlueJ package file";
+            props.store(output, header);
+        }
+        catch (IOException e) {
+            throw new IOException("Error when storing properties to BlueJ package file: " + file);
+        }
+        finally {
+            if (output != null) {
+                output.close();
+            }
+        }
+    }
+
+    /**
+     * Check if the given name matches the name of a BlueJ package file (either
+     * bluej.pkg or package.bluej).
+     */
+    public static boolean isPackageFileName(String name)
+    {
+        return name.equals(pkgfileName) || name.equals(oldPkgfileName);
+    }
+    
+    /**
+     * Check if the given name matches the name of the old BlueJ package file
+     * (bluej.pkg).
+     */
+    public static boolean isOldPackageFileName(String name)
+    {
+        return name.equals(oldPkgfileName);
+    }
+
+    /**
+     * Creates the two package files if they don't already exist. If only
+     * package.bluej exists it will not create bluej.pkg.
+     * 
+     * @return true if it created a package file, false if it didn't create any package files.
+     * @param dir The directory to create package files in.
+     * @throws IOException If the package file(s) could not be created.
+     * 
+     */
+    public boolean create()
+        throws IOException
+    {
+        File pkgFile = new File(dir, pkgfileName);
+        File oldPkgFile = new File(dir, oldPkgfileName);
+
+        boolean created = false;
+        if (pkgFile.exists() && !oldPkgFile.exists()) {
+            return false;
+        }
+
+        if (!pkgFile.exists()) {
+            pkgFile.createNewFile();
+            created = true;
+        }
+        return created;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ClassDiagramPrinter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ClassDiagramPrinter.java
new file mode 100644
index 0000000000000000000000000000000000000000..bde2f18415fcf1425efdb34723220d4b738fbbab
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ClassDiagramPrinter.java
@@ -0,0 +1,195 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.print.*;
+import java.awt.*;
+import java.util.Date;
+import java.text.DateFormat;
+
+import bluej.utility.Utility;
+import bluej.Config;
+
+/**
+ * Provides the ability to print a package class diagram
+ *
+ * @author Bruce Quig
+ *
+ */
+public class ClassDiagramPrinter implements Printable
+{
+
+    private PrinterJob printerJob;
+    private Package pkg;
+    private PageFormat pageFormat;
+    
+    private int pageColumns = 0;
+    private int pageRows = 0;
+    private int pages;
+    private int currentPage;
+    private int currentColumn = 0;
+    private int currentRow = 0;
+    private double scaleFactor = Config.getPropInteger("bluej.print.scale", 50) / 100.0;
+   
+   // Add a title to printouts
+    static final int TITLEBOX_HEIGHT = 20;
+    static final int PRINT_HMARGIN = 1;
+    static final int PRINT_VMARGIN = TITLEBOX_HEIGHT + 1;
+    static final Font printTitleFont = new Font("SansSerif", Font.PLAIN, 12);
+                                           //Config.printTitleFontsize);
+    static final Font printInfoFont = new Font("SansSerif", Font.ITALIC, 9);
+                                           //Config.printInfoFontsize);
+    
+    public ClassDiagramPrinter(PrinterJob printer, Package pkg, PageFormat pageFormat)
+    {
+        this.printerJob = printer;
+        this.pkg = pkg;
+        this.pageFormat = pageFormat;
+    }
+
+    /**
+     * Print the package class diagram for the package that is held by this printer.
+     */
+    public void printPackage()
+    {
+        printerJob.setPrintable(this, pageFormat);
+
+        calculatePages();
+        try {
+            // call the Printable interface to do the actual printing
+            printerJob.print();
+            
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        pkg.setStatus(Config.getString("pkgmgr.info.printed"));
+    }
+
+
+    /**
+     * Calculate how many pages, rows and columns are needed to print this diagram.
+     * This method initialises the instance fields with this information.
+     */
+    private void calculatePages()
+    {
+        Dimension graphSize = pkg.getMinimumSize();
+        graphSize.setSize(graphSize.getWidth() * scaleFactor, 
+                          graphSize.getHeight() * scaleFactor);
+        Rectangle printArea = getPrintArea(pageFormat);
+        
+        pageColumns = (graphSize.width + printArea.width - 1) / printArea.width;
+        pageRows = (graphSize.height + printArea.height - 1) / printArea.height;
+        pages = pageColumns * pageRows;
+        currentColumn = currentRow = 0;
+    }
+
+
+    /**
+     * Method that implements Printable interface and does that actual printing of
+     * class diagram.
+     */
+    public int print(Graphics g, PageFormat pageFormat, int pageIndex)
+    {
+        if(pageIndex >= pages) {
+            return Printable.NO_SUCH_PAGE;
+        }
+        
+        Rectangle printArea = getPrintArea(pageFormat);
+        
+        if(currentColumn < pageColumns) {
+            if(currentPage < pageIndex)
+                currentColumn++;
+        }
+        else if(currentRow < pageRows) {
+            //if(currentPage < pageIndex)
+            currentRow++;
+            currentColumn = 0;
+        }
+
+        printTitle(g, pageFormat, pageIndex + 1);
+
+        g.translate(printArea.x - currentColumn * printArea.width,
+                    printArea.y - currentRow * printArea.height);
+        g.setClip(currentColumn * printArea.width, currentRow * printArea.height,
+                  printArea.width, printArea.height);
+        ((Graphics2D)g).scale(scaleFactor, scaleFactor);
+
+        pkg.getEditor().paint(g);
+
+        currentPage = pageIndex;
+        return Printable.PAGE_EXISTS;
+    }
+
+ 
+
+    /**
+     * Return the rectangle on the page in which to draw the class diagram.
+     * The rectangle is the page minus margins minus space for header and
+     * footer text.
+     */
+    private Rectangle getPrintArea(PageFormat pageFormat)
+    {
+        return new Rectangle((int)pageFormat.getImageableX() + PRINT_HMARGIN,
+                             (int)pageFormat.getImageableY() + PRINT_VMARGIN,
+                             (int)pageFormat.getImageableWidth() - (2 * PRINT_HMARGIN),
+                             (int)pageFormat.getImageableHeight() - (2 * PRINT_VMARGIN));
+    }
+
+    /**
+     * Print the page title and other page decorations (frame, footer).
+     */
+    private void printTitle(Graphics g, PageFormat pageFormat, int pageNum)
+    {
+        FontMetrics ifm = g.getFontMetrics(printInfoFont);
+        Rectangle printArea = new Rectangle((int)pageFormat.getImageableX(),
+                                            (int)pageFormat.getImageableY(),
+                                            (int)pageFormat.getImageableWidth(),
+                                            (int)pageFormat.getImageableHeight());
+
+        // shade and frame header area
+        g.setColor(Color.lightGray);
+        g.fillRect(printArea.x, printArea.y, printArea.width-1, TITLEBOX_HEIGHT);
+        g.setColor(Color.black);
+        g.drawRect(printArea.x, printArea.y, printArea.width-1, TITLEBOX_HEIGHT);
+
+        // frame print area
+        g.drawRect(printArea.x, printArea.y, printArea.width-1,
+                   printArea.height - PRINT_VMARGIN);
+
+        // write header
+        String title = "Project " + pkg.getProject().getProjectName();
+        String packageName = pkg.getQualifiedName();
+        if(packageName.length() > 0)
+            title += " [package " + packageName + "]";
+        
+        g.setFont(printTitleFont);
+        Utility.drawCentredText(g, title, printArea.x, printArea.y,
+                                printArea.width, TITLEBOX_HEIGHT);
+        // write footer
+        g.setFont(printInfoFont);
+        DateFormat dateFormat = DateFormat.getDateTimeInstance();
+        Utility.drawRightText(g, dateFormat.format(new Date()) + 
+                              "     Page " + pageNum + " of " + pages,
+                              printArea.x, printArea.y + printArea.height - PRINT_VMARGIN,
+                              printArea.width, ifm.getHeight());
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/CommentCache.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/CommentCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..738550278f4999a02cec9796b135ccebab0b0e04
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/CommentCache.java
@@ -0,0 +1,40 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.util.Properties;
+
+import bluej.utility.GeneralCache;
+
+/**
+ * A cache for class comments (javadoc/parameter names). Adding new entries to the cache
+ * will purge old entries, if there are too many.
+ * 
+ * @author Davin McCall
+ */
+public class CommentCache extends GeneralCache<String,Properties>
+{
+    public CommentCache()
+    {
+        super(20);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/DocPathEntry.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/DocPathEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..6d0660400f17f371c9ac1336aa6b55336f197f1e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/DocPathEntry.java
@@ -0,0 +1,56 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.File;
+
+/**
+ * Represents an entry on the Javadoc search path. This can include both a jar/zip file/directory,
+ * and a path prefix which specifies where the source root within the jar/zip/directory really is.
+ * 
+ * @author Davin McCall
+ */
+public class DocPathEntry
+{
+    private File file;
+    private String pathPrefix;
+    
+    /**
+     * Create a new DocPathEntry, for the given file (either a jar, zip, or a directory), and
+     * with sources in the given prefix.
+     */
+    public DocPathEntry(File file, String pathPrefix)
+    {
+        this.file = file;
+        this.pathPrefix = pathPrefix;
+    }
+    
+    public File getFile()
+    {
+        return file;
+    }
+    
+    public String getPathPrefix()
+    {
+        return pathPrefix;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/DocuGenerator.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/DocuGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0a4152a15a147c1dde73334c7a25d3d3ceb376a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/DocuGenerator.java
@@ -0,0 +1,536 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.EventQueue;
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import bluej.BlueJEvent;
+import bluej.Config;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+import bluej.utility.Utility;
+
+/**
+ * This class handles documentation generation from inside BlueJ.
+ * Documentation can be generated for a whole project or for a single class.
+ * For each Project instance there should be one instance of DocuGenerator
+ * that takes care of project documentation. Project documentation is written
+ * into a directory in the project directory.
+ * As the documentation for a single class serves merely as a preview option,
+ * it is generated in a temporary directory.
+ *
+ * @author  Axel Schmolitzky
+ */
+public class DocuGenerator
+{
+    // static fields - tool-independent
+    /** The name of the directory where project documentation is written to. */
+    private static String docDirName =
+                                Config.getPropString("doctool.outputdir");
+
+    /** Header for log file when generating documentation for projects. */
+    private static String projectLogHeader =
+                                Config.getPropString("Project documentation");
+
+    /** Header for log file when generating documentation for classes. */
+    private static String classLogHeader =
+                                Config.getPropString("Class documentation");
+
+    // static fields - tool-dependent
+    /** The name (including path) of the documentation tool used. */
+    private static String docCommand =
+                            Config.getJDKExecutablePath("doctool.command","javadoc");
+
+    /** javadoc parameters for all runs: include author and version 
+     * information, do not generate information about deprecated features,
+     * consider only package, protected, and public classes and members,
+     * include bottom line.
+     */
+    private static String fixedJavadocParams = Config.getPropString("doctool.options");
+
+    /** javadoc parameters for preview runs: do not generate an index,
+     * a tree, a help.
+     */
+    private static String tmpJavadocParams = " -noindex -notree -nohelp -nonavbar";
+
+    /** The project this generator belongs to. */
+    private Project project;
+    /** The project directory. */
+    private File projectDir;
+    /** the path of the project directory, the root for all sources. */
+    private String projectDirPath;
+    /** the directory where documentation is written to. */
+    private File docDir;
+    /** the path of the directory where documentation is written to. */
+    private String docDirPath;
+
+    /* -------------- end of static field declarations ----------------- */
+
+    /**
+     * Creates a separate thread that starts the external call for faster
+     * return to the GUI. If the call was successful the URL given in 'url'
+     * will be shown in a web browser.
+     * @param call the call to the documentation generating tool.
+     * @param url the URL to be shown after successful completion.
+     */
+    private static void generateDoc(String[] call, File result, File log, 
+                                    String header, boolean openBrowser)
+    {
+        // start the call in a separate thread to allow fast return to GUI.
+        Thread starterThread = new Thread(
+                        new DocuRunStarter(call, result, log, header, 
+                                           openBrowser));
+        starterThread.setPriority(Thread.MIN_PRIORITY);
+        starterThread.start();
+        BlueJEvent.raiseEvent(BlueJEvent.GENERATING_DOCU, null);
+    }
+
+
+    /**
+     * This class enables to run the external call for a documentation
+     * generation in a different thread. An instance of this class gets
+     * the string that constitutes the external call as a constructor
+     * parameter. The second constructor parameter is the name of the
+     * HTML file that should be opened by a web browser if the documentation
+     * generation was successful.
+     */
+    private static class DocuRunStarter implements Runnable
+    {
+        private String[] docuCall;
+        private File showFile;
+        private File logFile;
+        private String logHeader;
+        private boolean openBrowser;
+        private static final Object mutex = new Object();
+
+        public DocuRunStarter(String[] call, File result, File log, 
+                              String header, boolean browse)
+        {
+            docuCall = call;
+            showFile = result;
+            logFile = log;
+            logHeader = header;
+            openBrowser = browse;
+        }
+
+        /**
+         * Perform the call that was passed in as a constructor parameter.
+         * If this call was successful let the result be shown in a browser.
+         */
+        @Override
+        public void run()
+        {
+            // Process docuRun;
+            PrintWriter logWriter = null;
+            int exitValue = -1;
+            try {
+                synchronized (mutex) {
+                    // We synchronize because Javadoc can run into problems if several
+                    // instances are running at the same time. Also, this prevents the
+                    // logfile from being written by two threads at once.
+                    OutputStream logStream = new FileOutputStream(logFile);
+                    logWriter = new PrintWriter(logStream,true);
+                    
+                    String[] docuCall2 = new String[docuCall.length-1];
+                    logWriter.println(logHeader);
+                    logWriter.println("<---- javadoc command: ---->");
+                    
+                    int i;
+                    for(i=0; i < docuCall.length; i++) {
+                        logWriter.println(docuCall[i]);
+                        if(i != 0)
+                            docuCall2[i-1] = docuCall[i];
+                    }
+                    
+                    logWriter.println("<---- end of javadoc command ---->");
+                    logWriter.flush();
+                    
+                    // Call Javadoc
+                    Method executeMethod = null;
+                    try {
+                        Class<?> javadocClass = Class.forName("com.sun.tools.javadoc.Main");
+                        executeMethod = javadocClass.getMethod("execute",
+                                new Class [] {String.class, PrintWriter.class, PrintWriter.class,
+                                PrintWriter.class, String.class, String[].class});
+                    }
+                    catch (ClassNotFoundException cnfe) {
+                        cnfe.printStackTrace();
+                    }
+                    catch (NoSuchMethodException nsme) {
+                        nsme.printStackTrace();
+                    }
+                    
+                    // First try and execute javadoc in the same VM via reflection:
+                    if (executeMethod != null) {
+                        try {
+                            Integer result = (Integer) executeMethod.invoke(null,
+                                    new Object [] {"javadoc", logWriter, logWriter,
+                                    logWriter, "com.sun.tools.doclets.standard.Standard",
+                                    docuCall2});
+                            exitValue = result.intValue();
+                        }
+                        catch (IllegalAccessException iae) {
+                            // Try as an external process instead
+                            executeMethod = null;
+                        }
+                        catch (InvocationTargetException ite) {
+                            exitValue = -1;
+                            ite.printStackTrace(logWriter);
+                        }
+                    }
+                    
+                    // If javadoc doesn't seem to be available via reflection,
+                    // execute it as an external process
+                    if (executeMethod == null) {
+                        Process docuRun = Runtime.getRuntime().exec(docuCall);
+                        
+                        // because we don't know what comes first we have to start
+                        // two threads that consume both the standard and the error
+                        // output of the external process. The output is appended to
+                        // the log file.
+                        EchoThread outEcho = new EchoThread(docuRun.getInputStream(),
+                                                            logStream);
+                        EchoThread errEcho = new EchoThread(docuRun.getErrorStream(),
+                                                            logStream);
+                        outEcho.start();
+                        errEcho.start();
+                        try {
+                            docuRun.waitFor();
+                            outEcho.join();
+                            errEcho.join();
+                            exitValue = docuRun.exitValue();
+                        }
+                        catch (InterruptedException ie) {
+                            logWriter.println("Interrupted while waiting for javadoc process to complete.");
+                        }
+                    }
+                }
+                
+                final int finalExitValue = exitValue;
+                EventQueue.invokeLater(new Runnable() {
+                    public void run() {
+                        if (finalExitValue == 0) {
+                            BlueJEvent.raiseEvent(BlueJEvent.DOCU_GENERATED, null);
+                            if (!showFile.exists()) {
+                                Debug.message("showfile does not exist - searching");
+                                showFile = FileUtility.findFile(showFile.getParentFile(),
+                                        showFile.getName());
+                            }
+                            if(openBrowser) {
+                                // logWriter.println("try to open: " + showFile.getPath());
+                                Utility.openWebBrowser(showFile.getPath());
+                            }
+                        }
+                        else {
+                            BlueJEvent.raiseEvent(BlueJEvent.DOCU_ABORTED, null);
+                            DialogManager.showMessageWithText(null,
+                                    "doctool-error",
+                                    logFile.getPath());
+                        }
+                    }
+                });
+            }
+            catch (IOException exc) {
+                EventQueue.invokeLater(new Runnable() {
+                    public void run() {
+                        DialogManager.showMessage(null,"severe-doc-trouble");
+                    }
+                });
+            }
+            finally {
+                if (logWriter != null) {
+                    logWriter.close();
+                }
+            }
+        }
+    }
+
+    /**
+     * A thread which reads from an InputStream and echoes everything read
+     * to an OutputStream. 
+     */
+    private static class EchoThread extends Thread
+    {
+        private InputStream   readStream;
+        private OutputStream outStream;
+        
+        public EchoThread(InputStream r,OutputStream out)
+        {
+            readStream = r;
+            outStream = out;
+        }
+        
+        @Override
+        public void run()
+        {
+            try {
+                byte[] buf = new byte[1024];
+                int n;
+                while((n = readStream.read(buf)) != -1) {
+                    outStream.write(buf, 0, n);
+                }
+            }
+            catch(IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /* ------------------- end of static part ------------------- */
+    /* ---------------------------------------------------------- */
+
+
+    /**
+     * Construct a documentation generator instance for a project.
+     * @param project the project this generator belongs to.
+     */
+    public DocuGenerator(Project project)
+    {
+        // setup tool-independent instance information
+        this.project = project;
+        projectDir = project.getProjectDir();
+        projectDirPath = projectDir.getPath();
+        docDir = new File(projectDir, docDirName);
+        docDirPath = docDir.getPath();
+    }
+
+    /**
+     * Generate documentation for the whole project. As this is done in
+     * a different process this method just returns whether the preconditions
+     * for the generation that are immediately testable are fulfilled.
+     * 
+     * @return "" if the external process was started, an error message
+     *          otherwise.
+     */
+    public String generateProjectDocu()
+    {
+        // test whether the documentation directory is accessible.
+        String docDirStatus = testDocDir();
+        if (docDirStatus != "") {
+            return docDirStatus;
+        }
+
+        File startPage = new File(docDir, "index.html");
+        File logFile = new File(docDir, "logfile.txt");
+
+        if(documentationExists(logFile)) {
+            int result = DialogManager.askQuestion(null, "show-or-generate");
+            if(result == 0) {  // show only
+                Utility.openWebBrowser(startPage.getPath());
+                return "";
+            }
+            if(result == 2) {  // cancel
+                return "";
+            }
+        }
+
+        // tool-specific infos for javadoc
+
+        ArrayList<String> call = new ArrayList<String>();
+        call.add(docCommand);
+        call.add("-sourcepath");
+        call.add(projectDirPath);
+        addGeneralOptions(call);
+        call.add("-doctitle");
+        call.add(project.getProjectName());
+        call.add("-windowtitle");
+        call.add(project.getProjectName());
+        call.addAll(Utility.dequoteCommandLine(fixedJavadocParams));
+
+        // get the parameter that enables javadoc to link the generated
+        // documentation to the API documentation
+        addLinkParam(call);
+
+        // add the names of all the targets for the documentation tool.
+        // first: get the names of all packages that contain java sources.
+        List<String> packageNames = project.getPackageNames();
+        for (Iterator<String> names = packageNames.iterator(); names.hasNext(); ) {
+            String packageName = (String)names.next();
+            // as javadoc doesn't like packages with no java-files, we have to
+            // pass only names of packages that really contain java files.
+            Package pack = project.getPackage(packageName);
+            if (FileUtility.containsFile(pack.getPath(),".java")) {
+                if(packageName.length() > 0) {
+                    call.add(packageName);
+                }
+            }
+        }
+
+        // second: get class names of classes in unnamed package, if any
+        List<String> classNames = project.getPackage("").getAllClassnamesWithSource();
+        String dirName = project.getProjectDir().getAbsolutePath();
+        for (Iterator<String> names = classNames.iterator();names.hasNext(); ) {
+            call.add(dirName + "/" + names.next() + ".java");
+        }
+        String[] javadocCall = (String[])call.toArray(new String[0]);
+
+        generateDoc(javadocCall, startPage, logFile, projectLogHeader, true);
+        return "";
+    }
+
+    /**
+     * Generate documentation for the class in file 'filename'. The
+     * documentation is generated in a temporary directory. If the
+     * generation was successful the result will be displayed in a web browser.
+     * @param filename the fully qualified filename of the class to be
+     * documented.
+     * @return the path of the HTML file that will be generated
+     */
+    public void generateClassDocu(String filename)
+    {
+        //File docDir = getDocTempDir();  use project docDir instead
+        if (docDir == null) {
+            BlueJEvent.raiseEvent(BlueJEvent.DOCU_ABORTED, null);
+        }
+
+        // test whether the documentation directory is accessible.
+        String docDirStatus = testDocDir();
+        if (docDirStatus != "") {
+            BlueJEvent.raiseEvent(BlueJEvent.DOCU_ABORTED, null);
+        }
+
+        // build the call string
+        ArrayList<String> call = new ArrayList<String>();
+        call.add(docCommand);
+        call.addAll(Utility.dequoteCommandLine(fixedJavadocParams));
+        call.addAll(Utility.dequoteCommandLine(tmpJavadocParams));
+        addGeneralOptions(call);
+        call.add(filename);
+
+        String[] javadocCall = call.toArray(new String[0]);
+
+        // build the path for the result to be shown
+        File htmlFile = new File(getDocuPath(filename));
+        File logFile = new File(docDir, "logfile.txt");
+
+        generateDoc(javadocCall, htmlFile, logFile, classLogHeader, false);
+    }
+    
+    private void addGeneralOptions(List<String> call)
+    {
+        String majorVersion = System.getProperty("java.specification.version");        
+        call.add("-source");
+        call.add(majorVersion);
+        call.add("-classpath");
+        call.add(project.getClassLoader().getClassPathAsString());
+        call.add("-d");
+        call.add(docDirPath);
+        call.add("-encoding");
+        call.add(project.getProjectCharset().name());
+        call.add("-charset");
+        call.add(project.getProjectCharset().name());
+        call.add("-docletpath");
+        call.add(new File(Config.getBlueJLibDir(), "bjdoclet.jar").getPath());
+        call.add("-doclet");
+        call.add("bluej.doclet.doclets.formats.html.HtmlDoclet");
+    }
+
+    /**
+     * For a given filename, return the path where the html documentation
+     * file for that file would be generated.
+     */
+    public String getDocuPath(String filename)
+    {
+        if(filename.startsWith(projectDirPath))
+            filename = filename.substring(projectDirPath.length());
+        if (filename.endsWith(".java"))
+            filename = filename.substring(0, filename.indexOf(".java"));
+        return docDirPath + filename + ".html";
+    }
+
+    /**
+     * Test whether documentation directory exists in project dir and
+     * create it, if necessary.
+     * @return "" if directory exists and is accessible, an error message
+     * otherwise.
+     */
+    private String testDocDir()
+    {
+        if (docDir.exists()) {
+            if (!docDir.isDirectory())
+                return DialogManager.getMessage("docdir-blocked-by-file");
+        }
+        else {
+            try {
+                if (!docDir.mkdir())
+                    return DialogManager.getMessage("docdir-not-created");
+            }
+            catch (SecurityException exc) {
+                return DialogManager.getMessage("no-permission-for-docdir");
+            }
+        }
+        return "";
+    }
+
+    /**
+     * Test whether project documentation exists for this project.
+     * @param the logfile in the doc directory
+     */
+    private static boolean documentationExists(File logFile) 
+    {
+        if(!logFile.exists())
+           return false;
+
+        // test whether last doc generation was for project (not single class)
+        try
+        {
+            BufferedReader logReader = new BufferedReader(new FileReader(logFile));
+            String header = logReader.readLine();
+            return header.equals(projectLogHeader);
+        }
+        catch(Exception e)
+        {
+            return false;
+        }
+    }
+
+    /**
+     * javadoc can link the generated documentation to existing documentation.
+     * This method constructs the javadoc parameter to set the link to the
+     * Java API. To make sure that javadoc is happy we test whether the file
+     * that javadoc needs (a list of all package names of the API) is
+     * accessible via the link provided in the BlueJ properties file.
+     * @return the link parameter if the link is working, "" otherwise.
+     */
+    private void addLinkParam(List<String> params)
+    {
+        String linkToLib = Config.getPropString("doctool.linkToStandardLib");
+        if(linkToLib.equals("true")) {
+            String docURL = Config.getPropString("bluej.url.javaStdLib");
+
+            if (docURL.endsWith("index.html")) {
+                docURL = docURL.substring(0, docURL.length() - "index.html".length());
+            }
+
+            params.add("-link");
+            params.add(docURL);
+        }
+    }
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ExportDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ExportDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d6a3d5a3e4b11a97506b1e4bd64b9b23c1b9cd1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ExportDialog.java
@@ -0,0 +1,377 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.net.*;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+import bluej.prefmgr.PrefMgrDialog;
+import bluej.utility.*;
+
+/**
+ * Dialog for exporting the project to a jar file. Here, the jar
+ * creation options can be specified.
+ *
+ * @author  Michael Kolling
+ * @version $Id: ExportDialog.java 8121 2010-08-20 04:20:13Z davmac $
+ */
+class ExportDialog extends EscapeDialog
+{
+    // Internationalisation
+    private static final String dialogTitle = Config.getString("pkgmgr.export.title");
+    private static final String helpLine1 = Config.getString("pkgmgr.export.helpLine1");
+    private static final String helpLine2 = Config.getString("pkgmgr.export.helpLine2");
+    private static final String classLabelText = Config.getString("pkgmgr.export.classLabel");
+    private static final String libsLabel = Config.getString("pkgmgr.export.includeLibs");
+    private static final String sourceLabel = Config.getString("pkgmgr.export.sourceLabel");
+    private static final String pkgFilesLabel = Config.getString("pkgmgr.export.pkgFilesLabel");
+    private static final String noClassText = Config.getString("pkgmgr.export.noClassText");
+
+    private String mainClassName = "";
+
+    private JComboBox classSelect;
+    private JCheckBox sourceBox;
+    private JCheckBox pkgFilesBox;
+    private UserLibInfo[] userLibs;
+    
+    private boolean ok;		// result: which button?
+	private JPanel userLibPanel;
+
+    public ExportDialog(PkgMgrFrame parent)
+    {
+        super(parent, dialogTitle, true);
+        makeDialog(parent.getProject());
+    }
+    
+    public void updateDialog(PkgMgrFrame parent)
+    {
+    	Project project = parent.getProject();
+		fillClassPopup(project);
+    	fillUserLibPanel(project, getSelectedLibs());
+    	String sel = mainClassName;
+    	if (sel.equals(""))
+    		sel = noClassText;
+    	classSelect.setSelectedItem(sel);
+    }
+
+    /**
+     * Show this dialog and return true if "OK" was pressed, false if
+     * cancelled.
+     */
+    public boolean display()
+    {
+        ok = false;
+        setVisible(true);  // returns after OK or Cancel, which set 'ok'
+        return ok;
+    }
+
+    /**
+     * Return the name of the main class in the project.
+     */
+    public String getMainClass()
+    {
+        return mainClassName;
+    }
+
+    /**
+     * Return userlibs selected in the dialogue.
+     * @return  A list of File objects.
+     */
+    public List<File> getSelectedLibs()
+    {
+        List<File> selected = new ArrayList<File>();
+
+        if(userLibs != null) {
+            for(int i = 0; i < userLibs.length; i++) {
+                if(userLibs[i].isSelected())
+                    selected.add(userLibs[i].getFile());
+            }
+        }
+        
+        return selected;
+    }
+
+    /**
+     * Return true if user wants to include the source.
+     */
+    public boolean includeSource()
+    {
+        return sourceBox.isSelected();
+    }
+    
+    /**
+     * Return true if the user wants to include the BlueJ project info files
+     * (.pkg files)
+     */
+    public boolean includePkgFiles()
+    {
+        return pkgFilesBox.isSelected();
+    }
+    
+    /**
+     * Close action when OK is pressed.
+     */
+    private void doOK()
+    {
+        mainClassName = (String)classSelect.getSelectedItem();
+        if(mainClassName.equals(noClassText))
+            mainClassName = "";
+        ok = true;
+        setVisible(false);
+    }
+
+    /**
+     * Close action when Cancel is pressed.
+     */
+    private void doCancel()
+    {
+        ok = false;
+        setVisible(false);
+    }
+
+    /**
+     * Create the dialog interface.
+     */
+    private void makeDialog(Project project)
+    {
+        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+
+        JPanel mainPanel = new JPanel();
+        {
+            mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+            mainPanel.setBorder(BlueJTheme.dialogBorder);
+
+            JLabel helpText1 = new JLabel(helpLine1);
+            mainPanel.add(helpText1);
+
+            JLabel helpText2 = new JLabel(helpLine2);
+            mainPanel.add(helpText2);
+
+            Font smallFont = helpText1.getFont().deriveFont(Font.ITALIC, 11.0f);
+            helpText1.setFont(smallFont);
+            helpText2.setFont(smallFont);
+
+            mainPanel.add(Box.createVerticalStrut(5));
+
+            mainPanel.add(new JSeparator());
+            mainPanel.add(Box.createVerticalStrut(5));
+
+            JPanel inputPanel = new JPanel();
+            {
+                inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS));
+                inputPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                JPanel mainClassPanel = new JPanel();
+                {
+                    JLabel classLabel = new JLabel(classLabelText);
+                    mainClassPanel.add(classLabel);
+                    
+                    createClassPopup();
+                    fillClassPopup(project);
+                    mainClassPanel.add(classSelect);
+                    
+                }
+                mainClassPanel.setAlignmentX(LEFT_ALIGNMENT);
+                inputPanel.add(mainClassPanel);
+                inputPanel.add(Box.createVerticalStrut(5));
+                
+                {
+                	createUserLibPanel();
+                	fillUserLibPanel(project, null);
+                    userLibPanel.setAlignmentX(LEFT_ALIGNMENT);
+                    inputPanel.add(userLibPanel);
+                    inputPanel.add(Box.createVerticalStrut(5));
+                }
+                
+                sourceBox = new JCheckBox(sourceLabel, false);
+                sourceBox.setAlignmentX(LEFT_ALIGNMENT);
+                inputPanel.add(sourceBox);
+                inputPanel.add(Box.createVerticalStrut(5));
+                pkgFilesBox = new JCheckBox(pkgFilesLabel);
+                inputPanel.add(pkgFilesBox);
+            }
+
+            mainPanel.add(inputPanel);
+            mainPanel.add(Box.createVerticalStrut(BlueJTheme.dialogCommandButtonsVertical));
+
+            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+            {
+                buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                JButton continueButton = BlueJTheme.getContinueButton();
+				continueButton.addActionListener(new ActionListener() {
+					public void actionPerformed(ActionEvent evt) { doOK(); }        		
+				});
+
+                JButton cancelButton = BlueJTheme.getCancelButton();
+				cancelButton.addActionListener(new ActionListener() {
+					public void actionPerformed(ActionEvent evt) { doCancel(); }        		
+				});
+
+                DialogManager.addOKCancelButtons(buttonPanel, continueButton, cancelButton);
+
+                getRootPane().setDefaultButton(continueButton);
+            }
+
+            mainPanel.add(buttonPanel);
+        }
+
+        getContentPane().add(mainPanel);
+        pack();
+
+        DialogManager.centreDialog(this);
+    }
+
+	private void createClassPopup()
+	{
+		classSelect = new JComboBox();
+		classSelect.setFont(PrefMgr.getPopupMenuFont());
+	}
+
+    /**
+     * Fill the class name popup selector with all classes of the project
+     */
+    private void fillClassPopup(Project project)
+    {
+    	classSelect.removeAllItems();
+    	classSelect.addItem(noClassText);
+    	
+        List<String> packageNames = project.getPackageNames();
+        Collections.sort(packageNames);
+
+        for (Iterator<String> packages = packageNames.iterator(); packages.hasNext(); ) {
+            String pkgName = (String)packages.next();
+            // SHould be a getPackage, Damiano
+            List<String> classNames = project.getPackage(pkgName).getAllClassnames();
+            Collections.sort(classNames);
+            if(pkgName.length() > 0) 
+                for (Iterator<String> classes = classNames.iterator(); classes.hasNext();)
+                	classSelect.addItem(pkgName + "." + classes.next());
+            else
+                for (Iterator<String> classes = classNames.iterator(); classes.hasNext();)
+                	classSelect.addItem(classes.next());
+        }
+    }
+    
+    /**
+     * Return a prepared panel listing the user libraries with check boxes.
+     * @param project the project the libraries belong to.
+     */
+    private void fillUserLibPanel(Project project, List<File> startChecked)
+    {
+    	userLibPanel.removeAll();
+    	
+        // collect info about jar files from the project classloader.
+        ArrayList<UserLibInfo> userlibList = new ArrayList<UserLibInfo>();
+        
+        // get user specified libs
+        ArrayList<URL> libList = PrefMgrDialog.getInstance().getUserConfigLibPanel().getUserConfigContent(); 
+        
+        // also get any libs in userlib directory
+        libList.addAll(Project.getUserlibContent());
+        
+        for (Iterator<URL> it = libList.iterator(); it.hasNext(); ) {
+            URL url = (URL)it.next();
+            try {
+                File file = new File(new URI(url.toString()));
+                
+                if ( file == null || file.isDirectory() ) continue;
+                
+                boolean shouldBeChecked = startChecked != null && startChecked.contains(file);
+                
+                userlibList.add (new UserLibInfo(file, shouldBeChecked));
+            } catch (URISyntaxException use) {
+                // Should never happen. If there is a problem with the conversion we want to know about it.
+                Debug.reportError("ExportDialog.createUserLibPanel(Project) invalid url=" + url.getPath());
+            }
+            // Skip directories.
+            
+        }
+        
+        if ( userlibList.size() < 1 ) { 
+        	userLibPanel.setVisible(false);
+        }
+        else {
+        	userLibPanel.setVisible(true);
+            userLibs = (UserLibInfo[])userlibList.toArray(new UserLibInfo[userlibList.size()]);
+
+            for(int i = 0; i < userLibs.length; i++) {
+            	userLibPanel.add(userLibs[i].getCheckBox());
+            }
+        }
+    }
+
+	private void createUserLibPanel()
+	{
+		userLibPanel = new JPanel(new GridLayout(0,2));
+
+		userLibPanel.setBorder(BorderFactory.createCompoundBorder(
+                BorderFactory.createTitledBorder(libsLabel),
+                BorderFactory.createEmptyBorder(5, 10, 5, 10)));
+	}
+    
+    class UserLibInfo {
+        private File sourceFile;
+        private JCheckBox checkBox;
+        
+        public UserLibInfo(File source, boolean selected)
+        {
+            sourceFile = source;
+            this.checkBox = new JCheckBox(sourceFile.getName(), selected);
+        }
+        
+        /**
+         * Return a checkBox with this lib's name as a label.
+         * @param shouldBeChecked 
+         */
+        public JCheckBox getCheckBox()
+        {
+            return checkBox;
+        }
+        
+        /**
+         * Return the file of this lib.
+         */
+        public File getFile()
+        {
+            return sourceFile;
+        }
+        
+        /**
+         * Tell whether this lib has been selected.
+         */
+        public boolean isSelected()
+        {
+            return checkBox.isSelected();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ExportManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ExportManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd4783e67f503b5e37978fa5ba40f76ff6f21d46
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ExportManager.java
@@ -0,0 +1,282 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.jar.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+
+import bluej.Config;
+import bluej.utility.*;
+
+/**
+ * Component to manage storing projects to jar file format.
+ *
+ * @author  Michael Kolling
+ */
+final class ExportManager
+{
+    private static final String specifyJar = Config.getString("pkgmgr.export.specifyJar");
+    private static final String createJarText = Config.getString("pkgmgr.export.createJarText");
+    
+    private static final String sourceSuffix = ".java";
+    private static final String contextSuffix = ".ctxt";
+    private static final String packageFilePrefix = "bluej.pk";
+    private static final String packageFileBackup = "bluej.pkh";
+
+    private PkgMgrFrame frame;
+    private ExportDialog dialog;
+
+    public ExportManager(PkgMgrFrame frame)
+    {
+        this.frame = frame;
+    }
+
+    /**
+     * Envoke the "create jar" user function. This starts by displaying the
+     * export dialog, then it reads the options and performs the export to jar.
+     */
+    public void export()
+    {
+        if (dialog == null)
+            dialog = new ExportDialog(frame);
+        else
+            dialog.updateDialog(frame);
+        boolean okay = dialog.display();
+
+        if(!okay)
+            return;
+
+        String fileName = FileUtility.getFileName(frame, specifyJar, createJarText, 
+                                                 null, false);
+        if(fileName == null)
+            return;
+
+        String sourceDir = frame.getProject().getProjectDir().getPath();
+
+        createJar(fileName, sourceDir, dialog.getMainClass(), dialog.getSelectedLibs(),
+                  dialog.includeSource(), dialog.includePkgFiles());
+    }
+
+    /**
+     * Export this project to a jar file.
+     */
+    private void createJar(String fileName, String sourceDir, String mainClass,
+                           List<File> userLibs, boolean includeSource, boolean includePkgFiles)
+    {
+        // Construct classpath with used library jars       
+        String classpath = "";
+        
+        // add jar files from +libs to classpath               
+        List<URL> plusLibs = frame.getProject().getPlusLibsContent();
+        List<File> plusLibAsFiles = new ArrayList<File>();
+        for(Iterator<URL> it = plusLibs.iterator(); it.hasNext();) {
+            URL url = it.next();
+            try {
+                File file = new File(new URI(url.toString()));
+                plusLibAsFiles.add(file);
+                classpath += " " + file.getName();
+            }
+            catch(URISyntaxException urie) {
+                // nothing at the moment
+            }
+            
+        }
+        
+        // add jar files from userlibs to classpath
+        for(Iterator<File> it = userLibs.iterator(); it.hasNext(); ) {
+            classpath += " " + it.next().getName();
+        }
+        
+        File jarFile = null;
+        File parent = null;
+        
+        if(classpath.length() == 0) {
+            // if we don't have library jars, just create a single jar file
+            if(!fileName.endsWith(".jar"))
+                fileName = fileName + ".jar";
+
+            jarFile = new File(fileName);
+            
+            if(jarFile.exists()) {
+                if (DialogManager.askQuestion(frame, "error-file-exists") != 0)
+                    return;
+            }
+        }
+        else {
+            // if we have library jars, create a directory with the new jar file
+            // and all library jar files in it
+            if(fileName.endsWith(".jar"))
+                fileName = fileName.substring(0, fileName.length() - 4);
+            parent = new File(fileName);
+
+            if(parent.exists()) {
+                if (DialogManager.askQuestion(frame, "error-file-exists") != 0)
+                    return;
+            }
+            parent.mkdir();
+            jarFile = new File(parent, parent.getName() + ".jar");
+        }
+        
+        OutputStream oStream = null;
+        JarOutputStream jStream = null;
+
+        try {
+            // create manifest
+            Manifest manifest = new Manifest();
+            Attributes attr = manifest.getMainAttributes();
+            attr.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+            attr.put(Attributes.Name.MAIN_CLASS, mainClass);
+            attr.put(Attributes.Name.CLASS_PATH, classpath);
+
+            // create jar file
+            oStream = new FileOutputStream(jarFile);
+            jStream = new JarOutputStream(oStream, manifest);
+
+            writeDirToJar(new File(sourceDir), "", jStream, includeSource,
+                            includePkgFiles,
+                            jarFile.getCanonicalFile());
+            if(parent != null) {
+                copyLibsToJar(plusLibAsFiles, parent);
+                copyLibsToJar(userLibs, parent);
+            }
+            
+            frame.setStatus(Config.getString("pkgmgr.exported.jar"));
+        }
+        catch(IOException exc) {
+            DialogManager.showError(frame, "error-writing-jar");
+            Debug.reportError("problen writing jar file: " + exc);
+        } finally {
+            try {
+                if(jStream != null)
+                    jStream.close();
+            } catch (IOException e) {}
+        }
+    }
+
+    /**
+     * Write the contents of a directory to a jar stream. Recursively called
+     * for subdirectories.
+     * outputFile should be the canonical file representation of the Jar file
+     * we are creating (to prevent including itself in the Jar file)
+     */
+    private void writeDirToJar(File sourceDir, String pathPrefix,
+                               JarOutputStream jStream, boolean includeSource, boolean includePkg, File outputFile)
+        throws IOException
+    {
+        File[] dir = sourceDir.listFiles();
+        for(int i = 0; i < dir.length; i++) {
+            if(dir[i].isDirectory()) {
+                if(!skipDir(dir[i], includePkg)) {
+                    writeDirToJar(dir[i], pathPrefix + dir[i].getName() + "/",
+                                  jStream, includeSource, includePkg, outputFile);
+                }
+            }
+            else {
+                // check against a list of file we don't want to export and also
+                // check that we don't try to export the jar file we are writing
+                // (hangs the machine)
+                if(!skipFile(dir[i].getName(), !includeSource, !includePkg) &&
+                    !outputFile.equals(dir[i].getCanonicalFile())) {
+                        writeJarEntry(dir[i], jStream, pathPrefix + dir[i].getName());
+                }
+            }
+        }
+    }
+
+    /**
+     * Copy all files specified in the given list to the new jar directory.
+     */
+    private void copyLibsToJar(List<File> userLibs, File destDir)
+        throws IOException
+    {
+        for(Iterator<File> it = userLibs.iterator(); it.hasNext(); ) {
+            File lib = it.next();
+            FileUtility.copyFile(lib, new File(destDir, lib.getName()));
+        }
+    }
+
+    /** array of directory names not to be included in jar file **/
+    private static final String[] skipDirs = { "CVS" };
+
+    /**
+     * Test whether a given directory should be skipped (not included) in
+     * export.
+     */
+    private boolean skipDir(File dir, boolean includePkg)
+    {
+        if (dir.getName().equals(Project.projectLibDirName))
+            return ! includePkg;
+        
+        for(int i = 0; i < skipDirs.length; i++) {
+            if(dir.getName().equals(skipDirs[i]))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether a file should be skipped during a copy operation.
+     * BlueJ specific files (bluej.pkg and *.ctxt) and - optionally - Java
+     * source files are skipped.
+     */
+    private boolean skipFile(String fileName, boolean skipSource, boolean skipPkg)
+    {
+        if(fileName.equals(packageFileBackup))
+            return true;
+        
+        if(fileName.endsWith(sourceSuffix))
+            return skipSource;
+
+        if(fileName.startsWith(packageFilePrefix) || fileName.endsWith(contextSuffix))
+            return skipPkg;
+
+        return false;
+    }
+
+    /**
+     * Write a jar file entry to the jar output stream.
+     * Note: entryName should always be a path with / seperators
+     *       (NOT the platform dependant File.seperator)
+     */
+    private void writeJarEntry(File file, JarOutputStream jStream,
+                                  String entryName)
+        throws IOException
+    {
+        InputStream in = null;
+        try {
+            in = new FileInputStream(file);
+            jStream.putNextEntry(new ZipEntry(entryName));
+            FileUtility.copyStream(in, jStream);
+        }
+        catch(ZipException exc) {
+            Debug.message("warning: " + exc);
+        }
+        finally {
+            if(in != null)
+                in.close();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/FileTransferHandler.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/FileTransferHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7be60442dfd646dbd22599e44c430a067a30185
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/FileTransferHandler.java
@@ -0,0 +1,106 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import bluej.utility.Debug;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import javax.swing.JComponent;
+import javax.swing.TransferHandler;
+
+/**
+ * The TransferHandler handles drop events (the tail end of Drag-and-Drop).
+ * This specific TransferHandler receives file drops (drops of files).
+ * 
+ * It is used for the package editor (the main diagram) so that is can receive
+ * Java source files via drag-and-drop.
+ * 
+ * @author mik
+ * @version 1.0
+ */
+public class FileTransferHandler extends TransferHandler 
+{
+    private DataFlavor fileFlavour;
+    private PkgMgrFrame pmf;
+    
+    /**
+     * Create a new FileTransferHandler for a specific PackageMgrFrame.
+     */
+    public FileTransferHandler(PkgMgrFrame pmf)
+    {
+        fileFlavour = DataFlavor.javaFileListFlavor;
+        this.pmf = pmf;
+    }
+    
+    /**
+     * importData - called when a drop event is received. See whether we
+     * can import the dropped item, and if so, handle it.
+     * 
+     * @param c The component that drop occured on.
+     * @param t The item being dropped.
+     * @return true iff we can import the item
+     */
+    @SuppressWarnings("unchecked")
+    public boolean importData(JComponent c, Transferable t) 
+    {
+        try {
+            if (!canImport(c, t.getTransferDataFlavors())) {
+                return false;
+            }
+
+            List<File> files = (List<File>) t.getTransferData(fileFlavour);
+            pmf.addFiles(files);
+        } catch (UnsupportedFlavorException ex) {
+            Debug.reportError("Cannot handle D&D transfer");
+        } catch (IOException ex) {
+            Debug.reportError("I/O exception during D&D import attempt");
+        }
+        return true;
+    }
+    
+    /**
+     * Check whether we can import the given data flavours into this component.
+     * This will be true if the data items are files.
+     */
+    public boolean canImport(JComponent c, DataFlavor[] flavours)
+    {
+        return hasFileFlavor(flavours);
+    }
+
+    /**
+     * Check whether the data can be received as a file.
+     */
+    private boolean hasFileFlavor(DataFlavor[] flavours)
+    {
+        for (int i = 0; i < flavours.length; i++) {
+            if (fileFlavour.equals(flavours[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/GreenfootProjectFile.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/GreenfootProjectFile.java
new file mode 100644
index 0000000000000000000000000000000000000000..b0d15fbd8e39d32e379763cafa193b71be6a24d4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/GreenfootProjectFile.java
@@ -0,0 +1,178 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * Reference to the Greenfoot project file(s). A Greenfoot project file is
+ * basically just a BlueJ package with some extra information added.
+ * 
+ * @author Poul Henriksen
+ */
+public class GreenfootProjectFile
+    implements PackageFile
+{
+    private static final String pkgfileName = "project.greenfoot";
+    private File dir;
+    private File pkgFile;
+
+    /**
+     * @see PackageFileFactory
+     */
+    GreenfootProjectFile(File dir)
+    {
+        this.dir = dir;
+        this.pkgFile = new File(dir, pkgfileName);
+    }
+
+    public String toString()
+    {
+        return dir.toString() + File.separator + pkgfileName;
+    }
+
+    public void load(Properties p)
+        throws IOException
+    {
+        FileInputStream input = null;
+        try {
+            if (pkgFile.canRead()) {
+                input = new FileInputStream(pkgFile);
+            }
+            else {
+                throw new IOException("Can't read from project file: " + pkgFile);
+            }
+            p.load(input);
+        }
+        finally {
+            if(input != null) {
+                input.close();
+            }
+        }
+    }
+
+    /**
+     * Save the given properties to the file.
+     * 
+     * @throws IOException if something goes wrong while trying to write the
+     *             file.
+     */
+    public void save(Properties props)
+        throws IOException
+    {
+        if (!pkgFile.canWrite()) {
+            throw new IOException("Greenfoot project file not writable: " + this);
+        }
+
+        // This is Greenfoot, this file will contain Greenfoot specific
+        // properties as well that we don't want to overwrite, so we load the
+        // file first. The greenfoot properties will be loaded through the class
+        // greenfoot.core.ProjectProperties. 
+
+        // TODO: It would probably be better to always forward to the BlueJ
+        // version of the properties instead of writing to the same file from
+        // two VMs. That would fix the issue with things not being written from
+        // the Greenfoot VM if exited in the BlueJ vm.
+        try {
+            Properties greenfootProps = new Properties();
+            FileInputStream input = new FileInputStream(pkgFile);
+            greenfootProps.load(input);
+            
+            // Make sure that we do not overwrite any values in props.
+            greenfootProps.putAll(props);
+            props.putAll(greenfootProps);
+        }
+        catch (IOException e) {
+            // If we can't load it for some reason, we just continue.
+        }
+
+        FileOutputStream output = null;
+        try {
+            output = new FileOutputStream(pkgFile);
+            String header = "Greenfoot project file";
+            props.store(output, header);
+        }
+        catch (IOException e) {
+            throw new IOException("Error when storing properties to Greenfoot project file: " + this);
+        }
+        finally {
+            if (output != null) {
+                output.close();
+            }
+        }
+    }
+    
+    /**
+     * Whether a Greenfoot package file exists in this directory.
+     */
+    public static boolean exists(File dir)
+    {
+        if (dir == null)
+            return false;
+
+        // don't try to test Windows root directories (you'll get in
+        // trouble with disks that are not in drives...).
+        if (dir.getPath().endsWith(":\\"))
+            return false;
+
+        if (!dir.isDirectory())
+            return false;
+
+        File packageFile = new File(dir, pkgfileName);
+        return packageFile.exists();
+    }
+    
+    /**
+     * Whether this file is the name has the name of a Greenfoot project file.
+     */
+    public static boolean isProjectFileName(String fileName)
+    {
+        return fileName.endsWith(pkgfileName);
+    }
+    
+    /**
+     * Creates the Greenfoot project file if it does not already exist. 
+     * 
+     * @return true if it created a package file, false if it didn't create any package files.
+     * @param dir The directory to create package file in.
+     * @throws IOException If the package file could not be created.
+     * 
+     */
+    public boolean create()
+        throws IOException
+    {
+        File pkgFile = new File(dir, pkgfileName);
+
+        if (pkgFile.exists()) {
+            return false;
+        }
+        else {
+            pkgFile.createNewFile();
+            return true;
+        }     
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/Import.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/Import.java
new file mode 100644
index 0000000000000000000000000000000000000000..949b335ac3ad70fe7350a23201ae3329554a152a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/Import.java
@@ -0,0 +1,228 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.JFrame;
+
+import bluej.parser.InfoParser;
+import bluej.parser.symtab.ClassInfo;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.JavaNames;
+
+/**
+ * Utility functions to help in the process of importing directory
+ * structures into BlueJ.
+ *
+ * @author  Michael Cahill
+ * @author  Michael Kolling
+ * @author  Axel Schmolitzky
+ * @author  Andrew Patterson
+ */
+public class Import
+{
+    /**
+     * Attempt to convert a non-bluej Path to a Bluej project.
+     * 
+     * <p>If no java source files are found, a warning dialog is displayed and
+     * the conversion doesn't take place.
+     * 
+     * <p>If source files are found whose package line mismatches the apparent
+     * package, a warning dialog is displayed and the user is prompted to
+     * either allow the package line to be corrected, or to cancel the
+     * conversion.
+     *
+     * @param parentWin  The parent window (used for centering dialogs)
+     * @param path       The path of the directory containing the project-to-be
+     * @return  true if the conversion was successfully completed
+     */
+    public static boolean convertNonBlueJ(JFrame parentWin, File path)
+    {
+        // find all sub directories with Java files in them
+        // then find all the Java files in those directories
+        List<File> interestingDirs = Import.findInterestingDirectories(path);
+
+        // check to make sure the path contains some java source files
+        if (interestingDirs.size() == 0) {
+            DialogManager.showError(parentWin, "open-non-bluej-no-java");
+            return false;
+        }
+
+        List<File> javaFiles = Import.findJavaFiles(interestingDirs);
+
+        // for each Java file, lets check its package line against the
+        // package line we think that it should have
+        // for each mismatch we collect the file, the package line it had,
+        // and what we want to convert it to
+        List<File> mismatchFiles = new ArrayList<File>();
+        List<String> mismatchPackagesOriginal = new ArrayList<String>();
+        List<String> mismatchPackagesChanged = new ArrayList<String>();
+
+        Iterator<File> it = javaFiles.iterator();
+
+        while (it.hasNext()) {
+            File f = it.next();
+
+            try {
+                ClassInfo info = InfoParser.parse(f);
+                if (info != null && ! info.hadParseError()) {
+
+                    String qf = JavaNames.convertFileToQualifiedName(path, f);
+
+                    if (!JavaNames.getPrefix(qf).equals(info.getPackage())) {
+                        mismatchFiles.add(f);
+                        mismatchPackagesOriginal.add(info.getPackage());
+                        mismatchPackagesChanged.add(qf);
+                    }
+                }
+            }
+            catch (FileNotFoundException fnfe) {}
+        }
+
+        // now ask if they want to continue if we have detected mismatches
+        if (mismatchFiles.size() > 0) {
+            ImportMismatchDialog imd = new ImportMismatchDialog(parentWin, mismatchFiles, mismatchPackagesOriginal,
+                    mismatchPackagesChanged);
+            imd.setVisible(true);
+
+            if (!imd.getResult())
+                return false;
+        }
+
+        // now add bluej.pkg files through the directory structure
+        Import.convertDirectory(interestingDirs);
+        return true;
+    }
+    
+    /**
+     * Find all directories under a certain directory which
+     * we deem 'interesting'.
+     * An interesting directory is one which either contains
+     * a java source file or contains a directory which in
+     * turn contains a java source file.
+     *
+     * @param   dir     the directory to look in
+     * @returns         a list of File's representing the
+     *                  interesting directories
+     */
+    public static List<File> findInterestingDirectories(File dir)
+    {
+        List<File> interesting = new LinkedList<File>();
+
+        File[] files = dir.listFiles();
+
+        if (files == null)
+            return interesting;
+
+        boolean imInteresting = false;
+
+        for (int i=0; i<files.length; i++) {
+            if (files[i].isDirectory()) {
+                // if any of our sub directories are interesting
+                // then we are interesting
+                // we ensure that the subdirectory would have
+                // a valid java package name before considering
+                // anything in it
+                if(JavaNames.isIdentifier(files[i].getName())) {
+                    List<File> subInteresting = findInterestingDirectories(files[i]);
+
+                    if (subInteresting.size() > 0) {
+                        interesting.addAll(subInteresting);
+                        imInteresting = true;
+                    }
+                }
+            }
+            else {
+                if (files[i].getName().endsWith(".java"))
+                    imInteresting = true;
+            }
+        }
+
+        // if we have found anything of interest (either a java
+        // file or a subdirectory with java files) then we consider
+        // ourselves interesting and add ourselves to the list
+        if (imInteresting)
+            interesting.add(dir);
+
+        return interesting;
+    }
+
+    /**
+     * Find all Java files contained in a list of
+     * directory paths.
+     */
+    public static List<File> findJavaFiles(List<File> dirs)
+    {
+        List<File> interesting = new LinkedList<File>();
+
+        Iterator<File> it = dirs.iterator();
+
+        while(it.hasNext()) {
+            File dir = it.next();
+
+            File[] files = dir.listFiles();
+
+            if (files == null) {
+                continue;
+            }
+
+            for (int i=0; i<files.length; i++) {
+                if (files[i].isFile() && files[i].getName().endsWith(".java")) {
+                    interesting.add(files[i]);
+                }
+            }
+        }
+
+        return interesting;
+    }
+
+    /**
+     * Convert an existing directory structure to one
+     * that BlueJ can open as a project.
+     */
+    public static void convertDirectory(List<File> dirs)
+    {
+        // create a BlueJ package file in every directory that
+        // we have determined to be interesting
+
+        Iterator<File> i = dirs.iterator();
+
+        while(i.hasNext()) {
+            File f = (File) i.next();
+            try {
+                PackageFileFactory.getPackageFile(f).create();
+            }
+            catch (IOException e) {
+                Debug.reportError("Could not create package files in dir: " + f, e);
+            }
+          
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ImportFailedDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ImportFailedDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..b0feaa36580541d54e5defbd312ac76a15861870
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ImportFailedDialog.java
@@ -0,0 +1,118 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import bluej.*;
+import bluej.Config;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * Dialog for showing the user a list of files which failed
+ * an import.
+ *
+ * @author  Andrew Patterson
+ * @version $Id: ImportFailedDialog.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class ImportFailedDialog extends EscapeDialog
+    implements ActionListener
+{
+    private static final String cont = Config.getString("continue");
+
+    private static final String dialogTitle = Config.getString("pkgmgr.importfailed.title");
+    private static final String helpLine1 = Config.getString("pkgmgr.importfailed.helpLine1");
+    private static final String helpLine2 = Config.getString("pkgmgr.importfailed.helpLine2");
+    private static final String helpLine3 = Config.getString("pkgmgr.importfailed.helpLine3");
+
+    public ImportFailedDialog(JFrame parent, Object[] objects)
+    {
+        super(parent, dialogTitle, true);
+
+        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+
+        JPanel mainPanel = new JPanel();
+        {
+            mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+            mainPanel.setBorder(BlueJTheme.dialogBorder);
+
+            JLabel helpText1 = new JLabel(helpLine1);
+            helpText1.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText1);
+
+            JLabel helpText2 = new JLabel(helpLine2);
+            helpText2.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText2);
+
+            JLabel helpText3 = new JLabel(helpLine3);
+            helpText3.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText3);
+
+            Font smallFont = helpText1.getFont().deriveFont(10);
+            helpText1.setFont(smallFont);
+            helpText2.setFont(smallFont);
+            helpText3.setFont(smallFont);
+
+            mainPanel.add(Box.createVerticalStrut(5));
+
+            JList failedList = new JList(objects);
+            {
+                failedList.setAlignmentX(LEFT_ALIGNMENT);
+            }
+
+            JScrollPane scrolly = new JScrollPane(failedList);
+            scrolly.setAlignmentX(LEFT_ALIGNMENT);
+
+            mainPanel.add(scrolly);
+            mainPanel.add(Box.createVerticalStrut(BlueJTheme.dialogCommandButtonsVertical));
+
+            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+            {
+                buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                JButton contButton = new JButton(cont);
+                {
+                    contButton.addActionListener(this);
+                }
+
+                buttonPanel.add(contButton);
+
+                getRootPane().setDefaultButton(contButton);
+            }
+
+            mainPanel.add(buttonPanel);
+        }
+
+        getContentPane().add(mainPanel);
+        pack();
+
+        DialogManager.centreDialog(this);
+    }
+
+    public void actionPerformed(ActionEvent evt)
+    {
+        dispose();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ImportMismatchDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ImportMismatchDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..e81ea2004cbbde5c1752edebff2f90f0b504fadd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ImportMismatchDialog.java
@@ -0,0 +1,166 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.List;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.WindowConstants;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+
+/**
+ * Dialog for showing the user a list of files which
+ * had mismatched package lines on an open non-BlueJ.
+ *
+ * @author  Andrew Patterson
+ */
+public class ImportMismatchDialog extends EscapeDialog
+{
+    private static final String dialogTitle = Config.getString("pkgmgr.importmismatch.title");
+
+    private boolean result = false;
+
+    public ImportMismatchDialog(JFrame parent, List<File> files,
+                                 List<String> packageNamesOriginal, List<String> packageNamesChanged)
+    {
+        super(parent, dialogTitle, true);
+
+        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+
+        JPanel mainPanel = new JPanel();
+        {
+            mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+            mainPanel.setBorder(BlueJTheme.dialogBorder);
+
+            JLabel helpText1 = new JLabel(Config.getString("pkgmgr.importmismatch.helpLine1"));
+            helpText1.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText1);
+            JLabel helpText2 = new JLabel(Config.getString("pkgmgr.importmismatch.helpLine2"));
+            helpText2.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText2);
+            JLabel helpText3 = new JLabel(Config.getString("pkgmgr.importmismatch.helpLine3"));
+            helpText3.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText3);
+            JLabel helpText4 = new JLabel(Config.getString("pkgmgr.importmismatch.helpLine4"));
+            helpText4.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText4);
+            JLabel helpText5 = new JLabel(Config.getString("pkgmgr.importmismatch.helpLine5"));
+            helpText5.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText5);
+            JLabel helpText6 = new JLabel(Config.getString("pkgmgr.importmismatch.helpLine6"));
+            helpText6.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText6);
+            JLabel helpText7 = new JLabel(Config.getString("pkgmgr.importmismatch.helpLine7"));
+            helpText7.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText7);
+            JLabel helpText8 = new JLabel(Config.getString("pkgmgr.importmismatch.helpLine8"));
+            helpText8.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText8);
+            JLabel helpText9 = new JLabel(Config.getString("pkgmgr.importmismatch.helpLine9"));
+            helpText9.setAlignmentX(LEFT_ALIGNMENT);
+            mainPanel.add(helpText9);
+
+            Font smallFont = helpText1.getFont().deriveFont(10);
+            helpText1.setFont(smallFont);
+            helpText2.setFont(smallFont);
+            helpText3.setFont(smallFont);
+            helpText4.setFont(smallFont);
+            helpText5.setFont(smallFont);
+            helpText6.setFont(smallFont);
+            helpText7.setFont(smallFont);
+            helpText8.setFont(smallFont);
+            helpText9.setFont(smallFont);
+
+            mainPanel.add(Box.createVerticalStrut(5));
+
+            JList failedList = new JList(files.toArray());
+            {
+                failedList.setAlignmentX(LEFT_ALIGNMENT);
+            }
+
+            JScrollPane scrolly = new JScrollPane(failedList);
+            scrolly.setAlignmentX(LEFT_ALIGNMENT);
+
+            mainPanel.add(scrolly);
+            mainPanel.add(Box.createVerticalStrut(BlueJTheme.dialogCommandButtonsVertical));
+
+            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+            {
+                buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                JButton continueButton = BlueJTheme.getContinueButton();
+				continueButton.addActionListener(new ActionListener() {
+					public void actionPerformed(ActionEvent evt) { doContinue(); }        		
+				});
+
+                JButton cancelButton = BlueJTheme.getCancelButton();
+				cancelButton.addActionListener(new ActionListener() {
+					public void actionPerformed(ActionEvent evt) { doCancel(); }        		
+				});
+
+                DialogManager.addOKCancelButtons(buttonPanel, continueButton, cancelButton);
+
+                getRootPane().setDefaultButton(cancelButton);
+            }
+
+            mainPanel.add(buttonPanel);
+        }
+
+        getContentPane().add(mainPanel);
+        pack();
+
+        DialogManager.centreDialog(this);
+    }
+
+    public boolean getResult()
+    {
+        return result;
+    }
+
+	private void doContinue()
+	{
+		result = true;
+		dispose();
+	}
+	
+	private void doCancel()
+	{
+		result = false;
+		dispose();
+	}
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/JavadocResolver.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/JavadocResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b60d89ff76092884423e29153653d3272d57947
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/JavadocResolver.java
@@ -0,0 +1,38 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import bluej.debugger.gentype.MethodReflective;
+
+/**
+ * An interface for javadoc resolvers, which retrieve javadoc for a method. 
+ * 
+ * @author Davin McCall
+ */
+public interface JavadocResolver
+{
+    /**
+     * Retrieve the javadoc for the specified method, if possible. The javadoc and
+     * method parameter names will be added to the supplied MethodReflective.
+     */
+    public void getJavadoc(MethodReflective method);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/LayoutComparer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/LayoutComparer.java
new file mode 100644
index 0000000000000000000000000000000000000000..2be60b3f9b3504d10e7cab59d560bfa49dcebe88
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/LayoutComparer.java
@@ -0,0 +1,134 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.util.Comparator;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import bluej.pkgmgr.dependency.*;
+import bluej.pkgmgr.target.*;
+
+/**
+ * An ordering on targets to make layout nicer (reduce line intersections, etc.)
+ *
+ * @author Michael Cahill
+ * @version $Id: LayoutComparer.java 6683 2009-09-16 10:17:14Z davmac $
+ */
+public class LayoutComparer implements Comparator<Dependency>
+{
+    @Override
+  public Comparator<Dependency> reversed() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Comparator<Dependency> thenComparing(
+      Comparator<? super Dependency> other) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public <U> Comparator<Dependency> thenComparing(
+      Function<? super Dependency, ? extends U> keyExtractor,
+      Comparator<? super U> keyComparator) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public <U extends Comparable<? super U>> Comparator<Dependency> thenComparing(
+      Function<? super Dependency, ? extends U> keyExtractor) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Comparator<Dependency> thenComparingInt(
+      ToIntFunction<? super Dependency> keyExtractor) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Comparator<Dependency> thenComparingLong(
+      ToLongFunction<? super Dependency> keyExtractor) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Comparator<Dependency> thenComparingDouble(
+      ToDoubleFunction<? super Dependency> keyExtractor) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+    DependentTarget centre;
+    boolean in;
+
+    public LayoutComparer(DependentTarget centre, boolean in)
+    {
+        this.centre = centre;
+        this.in = in;
+    }
+
+    /**
+     * Order <a> and <b> depending on their relative positions
+     * and their positions relative to the centre
+     *
+     * Note: this is designed to reduce intersections when drawing lines.
+     */
+    public int compare(Dependency a, Dependency b)
+    {
+        DependentTarget ta = in ? a.getFrom() : a.getTo();
+        DependentTarget tb = in ? b.getFrom() : b.getTo();
+
+        int ax = ta.getX() + ta.getWidth()/2;
+        int ay = ta.getY() + ta.getHeight()/2;
+        int bx = tb.getX() + tb.getWidth()/2;
+        int by = tb.getY() + tb.getHeight()/2;
+
+        if((ax == bx) && (ay == by))
+            return 0;
+
+        int cx = centre.getX() + centre.getWidth()/2;
+        int cy = centre.getY() + centre.getHeight()/2;
+
+        boolean a_above = (ay < cy);
+        boolean a_left = (ax < cx);
+        int a_quad = (a_above ? 0 : 2) + (a_left ? 0 : 1);
+        boolean b_above = (by < cy);
+        boolean b_left = (bx < cx);
+        int b_quad = (b_above ? 0 : 2) + (b_left ? 0 : 1);
+
+        if(a_quad != b_quad) // different quadrants
+            return (a_quad > b_quad) ? 1 : -1;
+        // otherwise, we're in the same quadrant
+        int result = in ? ((ax < bx) ? -1 : 1) : ((ay < by) ? -1 : 1);
+        return (a_above == a_left) ? -result : result;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MIDletDeployer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MIDletDeployer.java
new file mode 100644
index 0000000000000000000000000000000000000000..86ea76ed38df9fbd4709344f62b52ec5caf79008
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MIDletDeployer.java
@@ -0,0 +1,251 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.File;
+import java.io.BufferedReader;
+import java.io.FilenameFilter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import bluej.Config;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.role.MIDletClassRole;
+import bluej.utility.FileUtility;
+
+/**
+ * Deploy MIDlet suite, the entire project contents.
+ * @author Cecilia Vargas
+ */
+final class MIDletDeployer
+{
+    static final String ICONS_DIR           = "res" + File.separator + "icons" ;     
+    static final String DEFAULT_MIDLET_ICON = "default.gif"; //default in project
+    static final String DEFAULT_LIB_ME_ICON = "images" + File.separator +
+                                              "me-default-icon.gif"; 
+    private String      toolkitBinDir; //Wireless toolkit's bin subdirectory.
+    private File        verified;      //Destination directory of preverify command.   
+    private List<String> args;          //To pass arguments to commands.    
+    private PkgMgrFrame frame;    
+    private Project     proj;
+    private List<String> midlets;      //Midlets to pass to the dialog for display.   
+    
+    public MIDletDeployer( PkgMgrFrame pmf )
+    {
+        frame = pmf;    
+        proj = frame.getProject();
+        verified = new File( proj.getProjectDir( ), "+tmpclasses" ); 
+        
+        //We invoke the preverify and emulator commands with their absolute path
+        //names, so we build that here using the location of the Wireless Toolkit.  
+        toolkitBinDir = Config.getPropString( "bluej.javame.toolkit.dir" ) + 
+                        File.separator + "bin" + File.separator;
+     }    
+    
+    /***************************************************************************
+     * Deploy the midlet suite. First preverify, then display a dialog where the
+     * user enters information for the .jar and .jad files, then launch emulator.
+     */
+    void deploy( )
+    {
+        if ( ! buildPreverifyCommand( ) ) 
+            return;  
+
+        FileUtility.deleteDir( verified );        
+        if ( ! verified.mkdir() ) 
+            Debug.reportError( "Could not create preverify output directory" );       
+     
+        startProcess( ); 
+             
+        final MIDletDeploymentDialog dialog = 
+                         new MIDletDeploymentDialog( frame, verified, midlets );
+        
+        if ( dialog.runEmulator( ) ) {
+            new Thread( ) {
+                public void run( ) {
+                    launchEmulator( dialog.getJadFile( ) );
+                }
+            }.start( );
+        }
+        frame.setStatus( Config.getString( "pkgmgr.midlet.deployed" ) );
+    }
+
+    /***************************************************************************
+     * Start a process builder to invoke whatever command is in args.
+     * The busyRunning flag detects when the process has finished starting up,
+     * which in the emulator happens once it spits out its first output line.
+     * This flag is mainly used for the emulator which takes quite a while to
+     * get juiced up. While flag is true the frame's progress bar is on.
+     */
+    private void startProcess( )
+    {
+        frame.startProgress( );  //Turn on the frame's progress bar.
+        boolean busyRunning = true;
+        ProcessBuilder pb = new ProcessBuilder( args );
+        pb.directory( proj.getProjectDir( ) );
+        pb.redirectErrorStream( true );
+        try {
+            Process process = pb.start();
+            //Read and print process output
+            InputStream is = process.getInputStream();
+            BufferedReader br = new BufferedReader( new InputStreamReader( is ) );            
+            String line;            
+            while ( ( line = br.readLine() )  != null ) {
+                if( busyRunning ) {
+                    frame.stopProgress( ); 
+                    busyRunning = false;
+                } 
+                Debug.message( line );
+            }
+         } catch ( IOException ioe ) {
+             Debug.reportError( "Had trouble invoking commmand" + pb.command( ) );
+             ioe.printStackTrace();
+         } finally {
+             if( busyRunning ) {
+                 frame.stopProgress( );
+                 busyRunning = false;
+            }
+         }
+    }
+    
+    /***************************************************************************
+     * Set up in the args List the preverify command with its options.
+     */         
+    private boolean buildPreverifyCommand( )
+    {
+        args = new ArrayList<String>();        
+        args.add( toolkitBinDir + "preverify" );     
+        args.add( "-classpath" );
+        args.add( proj.getClassLoader( ).getJavaMElibsAsPath( ) );
+        args.add( "-d" );    //destination directory
+        args.add( verified.getAbsolutePath() );  
+        
+        getUserSpecifiedOptions( "bluej.javame.preverify.options" );  
+        
+        //Get all the classes to preverify, but if while doing this we find a 
+        //class that has not been compiled then there is no point in deploying.
+        if ( getAndCheckClassTargets( ) )
+            return true;
+        else
+            return false;
+    }
+
+     /***************************************************************************
+      * This method goes through all packages in the project to accomplish 3 tasks:
+      * 1. Call getClassFiles to put into args the list of all class files 
+      *    in each package. This list is the input to preverify. 
+      * 2. Put into midlets the list of all MIDlets in the project. This list is
+      *    displayed in the deployment dialog in a table.
+      * 3. Check that every class target is compiled, and upon finding the
+      *    first not-compiled class the method returns false immediately. If the
+      *    project is all compiled then the method return true.   
+      */      
+     private boolean getAndCheckClassTargets( )
+     {
+         midlets = new ArrayList<String>();
+         List<String> packageNames = proj.getPackageNames();
+         String dot = ""; //first package is the unnamed one, so no dot
+         
+         for ( Object pkgName : packageNames ) {             
+             Package pkg = proj.getPackage( (String) pkgName ); 
+             List<ClassTarget> classTargets = pkg.getClassTargets();   
+             
+             for ( ClassTarget target : classTargets ) {
+                  if ( ! target.upToDate( ) ) {
+                      DialogManager.showMessage( frame, "not-all-compiled" );
+                      return false;
+                  }                    
+                  if ( target.getRole( ) instanceof  MIDletClassRole ) {
+                      midlets.add( (String) pkgName + dot + target );
+                  }
+             }
+             dot = ".";
+             getClassFiles( pkg );  //put all .class files in package into args
+         }
+         return true;
+     }
+     
+    /***************************************************************************
+     * Add to args the filenames of all the .class files--without the .class
+     * extension--in the pkg parameter. Method getClassTargets ignores
+     * inner classes, so we have to get all the class files in a package using 
+     * this method instead. The filenames added include the qualified package name,
+     * something like pkg.subpkg.myclass
+     */         
+    private void getClassFiles( Package pkg )
+    {      
+        String[ ] classFiles = pkg.getPath( ).list( new ClassFilesFilter( ) );
+        //The following should rarely be true; we're just being healthily paranoid.
+        if ( ( classFiles == null )  ||  ( classFiles.length == 0 ) ) 
+            return; 
+        String dot = "";
+        String pkgName = pkg.getQualifiedName( );
+        if ( ! pkgName.equals("") )
+            dot = ".";
+      
+        for ( int i = 0; i < classFiles.length; i++ ) {
+            int index = classFiles[ i ].lastIndexOf( ".class" );
+            String s = classFiles[ i ].substring( 0, index );
+            args.add( pkgName + dot + s );
+        }  
+    }        
+     
+    /***************************************************************************
+     * Launch the emulator.
+     */         
+    private void launchEmulator( File jadFile )
+    {
+        args = new ArrayList<String>( );
+        args.add( toolkitBinDir + "emulator" );
+        args.add( "-Xdescriptor:" + jadFile.getName() );
+        getUserSpecifiedOptions( "bluej.javame.emulator.options" );
+        startProcess( );
+    }
+
+    /***************************************************************************
+     * Put into args whatever options are in the configuration files.
+     */         
+    private void getUserSpecifiedOptions( String userOptions)
+    {
+        String options = Config.getPropString( userOptions, null );
+        if ( options != null ) {
+            StringTokenizer st = new StringTokenizer( options);
+            while ( st.hasMoreTokens() ) 
+                args.add( st.nextToken()  );
+        }               
+    } 
+
+    /***************************************************************************
+     * A filter to accept only .class files. 
+     */    
+    private class ClassFilesFilter implements FilenameFilter
+    {
+	public boolean accept( File f, String name ) {
+		return ( name.toLowerCase( ).endsWith( ".class" ) );                
+	}	         
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MIDletDeploymentDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MIDletDeploymentDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..07c39dc7b1614fad7dba9d735bc9d7303f559dfc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MIDletDeploymentDialog.java
@@ -0,0 +1,738 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import bluej.Config;
+import bluej.BlueJTheme;
+import bluej.utility.Debug;
+import bluej.utility.FileUtility;
+import bluej.utility.EscapeDialog;
+import bluej.utility.DialogManager;
+import bluej.utility.MiksGridLayout;
+import bluej.utility.SortedProperties;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.io.IOException;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+import javax.swing.JPanel;
+import javax.swing.JButton;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.BorderFactory;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.ButtonGroup;
+import javax.swing.ImageIcon;
+import javax.swing.JRadioButton;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.Border;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableColumnModel;
+import javax.swing.filechooser.FileFilter;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.URL;
+import java.util.List;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+/**
+ * Dialog for deploying a MIDlet suite. 
+ * User specifies attributes needed for the jad and jar files.
+ * 
+ * @author Cecilia Vargas
+ */
+public class MIDletDeploymentDialog extends EscapeDialog implements ListSelectionListener 
+{
+    private static final String MIDLET_FILE = "midlet.defs";
+    private static final String EXCLUDE_LABEL = Config.getString( "midlet.deployment.midlets.exclude" );
+    private static final String INCLUDE_LABEL = Config.getString( "midlet.deployment.midlets.include" );    
+    
+    private MIDletDeploymentTableModel tableModel;  
+    
+    private JTable       table; 
+    private JTextField   suiteName, suiteVendor, suiteVersion, suiteDescription;
+    private JButton      changeButton, inOutButton, upButton, downButton;
+    private JRadioButton runToolkit, createFiles;     
+ 
+    private File verified;  //Directory with preverified files to be put in jar file.
+    private File projectDir;
+    private File jadFile;
+    private File jarFile;
+    private File midletsFile;  //The midlet.defs file.    
+    private List<String> midlets; //List of midlets in project to display in this dialog.
+    
+    private Manifest          manifest;    
+    private PkgMgrFrame       frame;
+    private boolean           ok;   
+    private SortedProperties  props;   //Properties of the midlets in the midlet suite.
+    private boolean[ ]        exclude; //Whether to exclude a midlet from the midlet
+                                       //suite being deployed. This array is initialized
+                                       //by the model and manipulated in this dialog.
+    /***************************************************************************
+     * Constructor.
+     * 
+     * @param parent     The parent frame of this dialog.
+     * @param verified   The directory with the output files of the preverify 
+     *                   command. These files will go into the jar file.
+     * @param midlets    The current list of midlets in the project. 
+     *                   These midlets appear in the dialog table.
+     */
+    public MIDletDeploymentDialog( PkgMgrFrame parent, File verified, List<String> midlets )
+    {      
+        super( parent, Config.getString( "midlet.deployment.title" ), true );
+        frame = parent;
+        projectDir = parent.getProject( ).getProjectDir( );
+        this.verified = verified;
+        this.midlets = midlets;
+        manifest = new Manifest( );
+        midletsFile = new File( projectDir, MIDLET_FILE ); 
+        loadMidletFile( );
+        makeDialog( );
+    }
+
+    /***************************************************************************
+     * If the midlet.defs file exists, loads it into a Properties object. 
+     * This file has info for the dialog and the table model.
+     */
+    private void loadMidletFile( )
+    {
+        FileInputStream fis = null;
+        props = new SortedProperties( );
+
+        if ( midletsFile.exists( ) ) {
+            try {
+                fis = new FileInputStream( midletsFile );
+                props.load( fis );
+                fis.close();
+            }
+            catch( IOException e ) {
+                Debug.reportError( "Problem reading midlets file in root package"); 
+                e.printStackTrace();
+            }
+        }
+    }              
+         
+    /***************************************************************************
+     * Builds the main panel that contains the dialog.
+     */    
+    private void makeDialog( )
+    {   
+        JPanel panel = new JPanel( new BorderLayout( ) );
+        panel.setBorder( BlueJTheme.dialogBorder );        
+        panel.add( makeMIDletSuitePanel( ),    BorderLayout.PAGE_START );
+        panel.add( makeMIDletsBox( ),          BorderLayout.CENTER     ); 
+        panel.add( makeOkCancelButtonPanel( ), BorderLayout.PAGE_END   );
+        
+        JPanel mainPanel = new JPanel( new BorderLayout( ) );
+        mainPanel.setBorder( BlueJTheme.dialogBorder );  
+        mainPanel.add( makeRadioPanel( ), BorderLayout.PAGE_START );
+        mainPanel.add( panel,             BorderLayout.CENTER     );
+     
+        getContentPane( ).add( mainPanel );
+        pack( );
+        DialogManager.centreDialog( this );    
+    }
+
+    /***************************************************************************
+     * Make the radio button panel for the execution options.
+     */    
+    private JPanel makeRadioPanel( )            
+    {     
+        String toolkitText  = Config.getString( "midlet.deployment.runWTK"        );
+        String genFilesText = Config.getString( "midlet.deployment.generateFiles" );
+        
+        runToolkit  = new JRadioButton( toolkitText ,  true );
+        createFiles = new JRadioButton( genFilesText , false );       
+        
+        JPanel radioPanel = new JPanel( new GridLayout( 2, 1 ) ); 
+        radioPanel.setBorder( BorderFactory.createEmptyBorder( 0, 10, 0, 10 ) );
+        radioPanel.add( runToolkit  );
+        radioPanel.add( createFiles );        
+
+        ButtonGroup bGroup = new ButtonGroup( );
+        bGroup.add( runToolkit  );
+        bGroup.add( createFiles ); 
+        
+        return radioPanel;
+    }     
+
+    /***************************************************************************
+     * Builds the panel box for the MIDlet suite fields. This box is made up of 
+     * a box for labels and another box for the textfields. The textfields are
+     * initialized with the properties that were loaded from the midlet.defs file,
+     * of with default values if this file does not exist.
+     */    
+    private JPanel makeMIDletSuitePanel( )            
+    {     
+        JPanel panel = new JPanel( new MiksGridLayout( 4, 2, 10, 5) );
+        panel.setAlignmentX( LEFT_ALIGNMENT );
+        
+        String title = Config.getString( "midlet.deployment.suite.title"       ); 
+        String name  = Config.getString( "midlet.deployment.suite.name"        );
+        String vers  = Config.getString( "midlet.deployment.suite.version"     );        
+        String vend  = Config.getString( "midlet.deployment.suite.vendor"      ); 
+        String desc  = Config.getString( "midlet.deployment.suite.description" );   
+        
+        panel.setBorder( BorderFactory.createCompoundBorder(
+                             BorderFactory.createTitledBorder( title ),
+                             BlueJTheme.generalBorder  ) ); 
+        
+        JLabel suiteNameLabel        = new JLabel( name );
+        JLabel suiteVersionLabel     = new JLabel( vers );       
+        JLabel suiteVendorLabel      = new JLabel( vend );       
+        JLabel suiteDescriptionLabel = new JLabel( desc );          
+        
+        //reuse String fields to get info from the midlet.defs file
+        name = props.getProperty( "midlet.suite.name", projectDir.getName() );
+        vers = props.getProperty( "midlet.suite.version", "1.0" );
+        vend = props.getProperty( "midlet.suite.vendor", "BlueJ ME" ); 
+        desc = props.getProperty( "midlet.suite.description", "" );       
+
+        panel.add( suiteNameLabel                            );
+        panel.add( suiteName = new JTextField( name )        ); 
+        panel.add( suiteVersionLabel                         );
+        panel.add( suiteVersion = new JTextField( vers )     );
+        panel.add( suiteVendorLabel                          );
+        panel.add( suiteVendor = new JTextField( vend )      );
+        panel.add( suiteDescriptionLabel                     );
+        panel.add( suiteDescription = new JTextField( desc ) );    
+
+        return panel;
+    }
+    
+   /***************************************************************************
+    * Builds panel with the table of midlets and the buttons to manipulate the
+    * individual table entries.
+    */
+    private Box makeMIDletsBox( )
+    {
+        tableModel = new MIDletDeploymentTableModel( midlets, projectDir, props ); 
+        exclude = tableModel.getExcluded( );
+        
+        table = new JTable( tableModel );
+        table.setRowHeight(25);        
+        table.setShowGrid( false );
+        table.setOpaque( true );
+        table.setDragEnabled( false );
+        table.setRowSelectionAllowed( true );
+        table.setColumnSelectionAllowed( false );
+        table.setBackground( getBackground( ) );        
+        table.setIntercellSpacing( new Dimension( ) );
+        table.getTableHeader().setReorderingAllowed( false );
+        table.getSelectionModel().addListSelectionListener( this );        
+        table.setAutoResizeMode( JTable.AUTO_RESIZE_ALL_COLUMNS );        
+        table.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
+        
+        TableColumnModel colModel = table.getColumnModel( );
+        colModel.getColumn( 2 ).setCellRenderer( new IconColumnRenderer( ) );
+        table.getTableHeader( ).setDefaultRenderer( new HeaderRenderer( ) );
+        table.setDefaultRenderer( String.class, new MidletTableRenderer( ) );
+
+        colModel.getColumn( 0 ).setPreferredWidth( 90 );
+        colModel.getColumn( 1 ).setPreferredWidth( 55 );
+        colModel.getColumn( 2 ).setPreferredWidth( 30 );         
+
+        Dimension prefSize       = table.getMaximumSize( );
+        Dimension scrollPrefSize = table.getPreferredScrollableViewportSize( );
+        JScrollPane scroller = new JScrollPane( table );
+        scroller.setPreferredSize( new Dimension (scrollPrefSize.width,
+                                                  prefSize.height + 50 ) ); 
+        scroller.setBorder( BlueJTheme.generalBorder );
+        
+        String title = Config.getString( "midlet.deployment.midlets.title" );         
+        Box box = new Box( BoxLayout.PAGE_AXIS );
+        box.setBorder( BorderFactory.createTitledBorder( title ) );
+        box.add( scroller );  
+        
+        box.add( makeButtonPanel( ) );        
+        table.setRowSelectionInterval( 0, 0 );        
+        return box;
+    }
+
+    /***************************************************************************
+     * Builds the panel with the move up, move down, and exclude/include buttons.
+     */        
+    private JPanel makeButtonPanel( )
+    {        
+        changeButton = new JButton( Config.getString( "midlet.deployment.midlets.changeicon" ) ); 
+        upButton     = new JButton( Config.getString( "midlet.deployment.midlets.moveup"     ) );
+        downButton   = new JButton( Config.getString( "midlet.deployment.midlets.movedown"   ) );
+        inOutButton  = new JButton( );
+
+        changeButton.addActionListener( new ChangeIconListener( ) );
+
+        inOutButton.addActionListener( new ActionListener( ) {            
+		public void actionPerformed( ActionEvent evt ) { 
+                     int row = table.getSelectedRow( );
+                     exclude[ row ]  = ! exclude[ row ];
+                     tableModel.fireTableRowsUpdated( row, row );
+                     if ( exclude[ row ] )
+                         inOutButton.setText( INCLUDE_LABEL );
+                     else
+                         inOutButton.setText( EXCLUDE_LABEL );                   
+                }        		
+	} );                
+        upButton.addActionListener( new ActionListener( ) {            
+		public void actionPerformed( ActionEvent evt ) { 
+                     int row = table.getSelectedRow( );
+                     if ( row > 0 ) {
+                         tableModel.moveRowUp( row );
+                         swapExcluded( row, row - 1 );
+                         table.setRowSelectionInterval( row - 1, row - 1 );
+                     }
+                }        		
+	} );
+        downButton.addActionListener( new ActionListener( ) {            
+		public void actionPerformed( ActionEvent evt ) { 
+                     int row = table.getSelectedRow( );
+                     if ( row <  ( tableModel.getRowCount( ) - 1 ) ) {
+                         tableModel.moveRowDown( row );
+                         swapExcluded( row, row + 1 );                         
+                         table.setRowSelectionInterval( row + 1, row + 1 );
+                     } 
+                }        		
+	} );                
+        JPanel buttonPanel = new JPanel( new FlowLayout( FlowLayout.RIGHT ) );
+        buttonPanel.add( changeButton );        
+        buttonPanel.add( inOutButton  );
+        buttonPanel.add( upButton     );   
+        buttonPanel.add( downButton   );  
+        return buttonPanel;
+    }
+
+    /***************************************************************************
+     * Swaps two entries, i and j, in the exclude array.
+     */    
+    private void swapExcluded( int i, int j )  
+    {
+        boolean temp = exclude[ j ];
+        exclude[ j ] = exclude[ i ];
+        exclude[ i ] = temp;
+    }
+    
+    /***************************************************************************
+     * Builds the Ok and Cancel button panel.
+     */    
+    private JPanel makeOkCancelButtonPanel( )
+    {        
+        JButton okButton     = BlueJTheme.getOkButton( );
+        JButton cancelButton = BlueJTheme.getCancelButton( );     
+        
+	okButton.addActionListener( new ActionListener( )  {
+		public void actionPerformed( ActionEvent evt ) { doOk(); }        		
+	} );
+        cancelButton.addActionListener( new ActionListener( )  {
+		public void actionPerformed( ActionEvent evt ) { doCancel(); }        		
+	} );
+           
+        JPanel buttonPanel = new JPanel( new FlowLayout( FlowLayout.RIGHT ) );
+        buttonPanel.setBorder( BorderFactory.createEmptyBorder( 10, 0, 0, 0 ) );
+        getRootPane( ).setDefaultButton( okButton );
+        buttonPanel.add( okButton     );
+        buttonPanel.add( cancelButton );   
+        return buttonPanel;
+    }
+
+    /***************************************************************************
+     * Returns true if user pressed Ok button, and there were
+     * no problems in writing the midlet.defs file, and the radio button to run
+     * the toolkit was selected. Returns false if user pressed Cancel button, or
+     * if the create-files-only radio button was selected, or if there was a 
+     * problem in writing the midlet.defs file. See doCancel( ) and doOk( ).
+     */        
+    boolean runEmulator( )
+    {
+        ok = false;
+        setVisible( true );  //returns after Ok or Cancel
+        return ok;
+    }
+
+    /***************************************************************************
+     * Invoked when Cancel button is pressed.
+     */    
+    private void doCancel( ) 
+    {
+        ok = false;
+        setVisible( false );        
+    }
+
+    /***************************************************************************
+     * Invoked when Ok button is pressed.
+     */    
+    private void doOk( )
+    {
+        createJar( );
+        createJad( );        
+        ok = false;
+        if ( saveMIDletSuite( ) && runToolkit.isSelected( ) )
+            ok = true;
+        setVisible( false );
+        frame.setStatus( Config.getString( "pkgmgr.midlet.deploying" ) );           
+    }
+
+    /***************************************************************************
+     * Saves into a brand new midlet.defs file the midlets info in the table. Also
+     * save the midlet suite info, like name and version, contained in the JTextFields.
+     * Returns true if there were no IO exceptions, otherwise it returns false.
+     */    
+    private boolean saveMIDletSuite( )
+    {
+        props = new SortedProperties( );
+        
+        props.setProperty( "midlet.suite.name",        suiteName.getText().trim() );
+        props.setProperty( "midlet.suite.version",     suiteVersion.getText().trim() );        
+        props.setProperty( "midlet.suite.vendor",      suiteVendor.getText().trim() );
+        props.setProperty( "midlet.suite.description", suiteDescription.getText().trim() );      
+
+        tableModel.saveTableToProps( props );
+  
+        midletsFile.delete();                     
+        try {
+            midletsFile.createNewFile( );   
+            FileOutputStream output = new FileOutputStream( midletsFile );
+            props.store(output, "MIDlet suite file");
+            output.close();
+        }
+        catch (IOException e) {
+            Debug.reportError("Error saving MIDlet suite file " + midletsFile + ": " + e);
+            return false;
+        }
+        return true;
+    }
+    
+    /***************************************************************************
+     * Jars the preverified files, and the resources directoy if there is one.
+     */
+    private void createJar( )
+    {   
+        OutputStream    oStream = null;
+        JarOutputStream jStream = null; 
+        verifySuiteTextFields( );    
+        jarFile = new File( projectDir, projectDir.getName( ) + ".jar" );                 
+        try { 
+            // Create the manifest 
+            Attributes attr = manifest.getMainAttributes();   
+            attr.put( Attributes.Name.MANIFEST_VERSION, "1.0" );
+            attr.putValue( "MIDlet-Name",    suiteName.getText( )    );   
+            attr.putValue( "MIDlet-Version", suiteVersion.getText( ) );
+            attr.putValue( "MIDlet-Vendor",  suiteVendor.getText( )  ); 
+            // Create the jar file with the manifest.
+            oStream = new FileOutputStream( jarFile );
+            jStream = new JarOutputStream( oStream, manifest );
+
+            writeDirToJar( verified,  "", jStream, jarFile.getCanonicalFile( ) );
+            File resources = new File( projectDir, "res" );
+            if ( resources.exists( ) ) 
+                writeDirToJar( resources, "", jStream, jarFile.getCanonicalFile( ) );
+
+        }
+        catch( IOException e ) {
+            DialogManager.showError( frame, "error-writing-jar" );
+            Debug.reportError( "Problem writing jar file: " + e );            
+        } finally {
+            try {
+                if( jStream != null )
+                    jStream.close();
+            } catch ( IOException e ) {}
+        }
+    }
+
+    /***************************************************************************
+     * Write the contents of a directory to a jar stream. 
+     * Recursively called for subdirectories.
+     */
+    private void writeDirToJar(File sourceDir,          String pathPrefix,
+                               JarOutputStream jStream, File outputFile   )
+                               throws IOException {
+        File[] dir = sourceDir.listFiles();        
+        for( int i = 0; i < dir.length; i++ ) {            
+            if( dir[i].isDirectory( ) ) 
+                
+                writeDirToJar( dir[i],  pathPrefix + dir[i].getName( ) + "/",
+                               jStream, outputFile                             ); 
+            else
+                writeJarEntry( dir[i], jStream, pathPrefix + dir[i].getName( ) );          
+        }
+    }
+
+    /***************************************************************************
+     * Writes a jar file entry to the jar output stream. The entryName should always
+     * be a path with / separators, not the platform-dependent File.separator.
+     */
+    private void writeJarEntry( File file, JarOutputStream jStream, String entryName )
+                                throws IOException {
+        InputStream in = null;        
+        try {            
+            jStream.putNextEntry( new ZipEntry( entryName ) );
+            in = new FileInputStream( file );            
+            FileUtility.copyStream( in, jStream );
+        }
+        catch( ZipException ze ) {
+            Debug.message( "Problem writing zipentry to jarfile " + ze );
+        }
+        finally {
+            if( in != null )
+                in.close( );
+        }
+    }    
+    
+    /***************************************************************************
+     * Creates the application descriptor file. Unlike the jar's manifest
+     * atttributes, jad attributes cannot have continuation lines. In the jad, 
+     * each attribute name and its value have to be in one line. (Cecilia could 
+     * not find a line length limit in the specs. In testing, she tried very 
+     * long lines which did not break anything.)
+     */         
+    private void createJad( )
+    {
+        jadFile = new File( projectDir, projectDir.getName( ) + ".jad" );   
+        PrintWriter pw = null;       
+        try {     
+            pw = new PrintWriter( new FileOutputStream( jadFile ) );
+            pw.println( "MIDlet-Name: "    + suiteName.getText( )    );
+            pw.println( "MIDlet-Version: " + suiteVersion.getText( ) );
+            pw.println( "MIDlet-Vendor: "  + suiteVendor.getText( )  );             
+            String description = suiteDescription.getText().trim();
+            if ( ! description.equals( "" ) )
+                pw.println( "MIDlet-Description: " + description ); 
+            pw.println( "MicroEdition-Profile: MIDP-2.0" );
+            pw.println( "MicroEdition-Configuration: CLDC-1.1" );
+            pw.println( "MIDlet-Jar-URL: "  + jarFile.getName() );
+            pw.println( "MIDlet-Jar-Size: " + jarFile.length()  );
+            tableModel.writeTableToPrintWriter( pw );
+        }
+        catch ( IOException ioe ) {
+            Debug.message( "Problem writing jad file" );
+            ioe.printStackTrace();
+        }
+        finally {
+            if( pw != null ) {
+                pw.flush( );
+                pw.close( );
+            }   
+        }
+    }
+    
+    /***************************************************************************
+     * Returns the application descriptor file. 
+     */          
+    File getJadFile( ) { return jadFile; }    
+    
+    /***************************************************************************
+     * Sets the midletsuite name, vendor and version to default values if they
+     * are blank. These textfields are used in the jar's manifest and in the
+     * jad, and they cannot be blank, as per the specification.
+     */          
+    private void verifySuiteTextFields( )
+    {
+        String vendor  = suiteVendor.getText().trim();
+        String version = suiteVersion.getText().trim();
+        String name    = suiteName.getText().trim();  
+       
+        if ( vendor.equals( "" )  ) vendor  = "BlueJ ME";
+        if ( version.equals( "" ) ) version = "1.0";
+        if ( name.equals( "" )    ) name    = projectDir.getName( );
+        
+        suiteVendor.setText(  vendor  );
+        suiteVersion.setText( version );
+        suiteName.setText(    name    ); 
+    }    
+       
+    
+    /***************************************************************************
+     * Called when selected row changes.
+     */    
+    public void valueChanged( ListSelectionEvent lse )
+    {        
+        if ( lse.getValueIsAdjusting( ) )  // ignore mouse down, dragging, etc.
+            return;            
+        
+        if ( table.isRowSelected( 0 ) ) 
+            upButton.setEnabled( false ); // The first row can't be moved up.
+        else
+            upButton.setEnabled( true );  
+        
+        if ( table.isRowSelected( tableModel.getRowCount( ) - 1  ) ) 
+            downButton.setEnabled( false ); // The last row can't be moved down.
+        else
+            downButton.setEnabled( true ); 
+
+        if ( exclude[ table.getSelectedRow( ) ] )
+            inOutButton.setText( INCLUDE_LABEL );
+        else
+            inOutButton.setText( EXCLUDE_LABEL );
+     }    
+
+    /***************************************************************************
+     * Renderer for the table header. This class is implemented to disable the
+     * default highlighting of column headers when these are clicked.
+     */       
+    private class HeaderRenderer extends DefaultTableCellRenderer  
+    {
+        public Component getTableCellRendererComponent( JTable t, Object value, 
+                                                        boolean isSelected,
+                                                        boolean f, int r, int c ) { 
+            setText( (String) value ); 
+            setHorizontalAlignment( JLabel.CENTER );            
+            if ( isSelected ) 
+                setBackground( table.getBackground( ) );
+            return this;
+        }        
+    }
+    
+    /***************************************************************************
+     * Renderer to make midlet table look like a list (similar to BlueJ Inspector).
+     * This renderer is used for the name and class columns. 
+     */     
+    private class MidletTableRenderer extends DefaultTableCellRenderer        
+    {
+        public Component getTableCellRendererComponent( JTable table,       Object value, 
+                                                        boolean isSelected, boolean hasFocus, 
+                                                        int row,            int column ) {
+            if ( isSelected )
+                setBackground( table.getSelectionBackground( ) );
+            else 
+                setBackground( table.getBackground( )          );       
+            Border b = BorderFactory.createLineBorder( getBackground( ), 3 );
+            setBorder( b );
+            setText( (String) value );   
+            setHorizontalAlignment( JLabel.LEADING );
+            if ( column == 1 ) {
+                setBackground( Color.white );
+                b = BorderFactory.createLineBorder( Color.gray );
+                b = BorderFactory.createCompoundBorder( getBorder( ), b );
+                setBorder( b );
+            }
+            if ( exclude[ row ] )
+                setEnabled( false );
+            else 
+                setEnabled( true );
+            return this;
+        }
+    }
+    
+    /***************************************************************************
+     * Renderer for the ImageIcon column. It overrides the default renderer to
+     * disable the table cell if the midlet is excluded.
+     */         
+    private class IconColumnRenderer extends DefaultTableCellRenderer        
+    {
+        public Component getTableCellRendererComponent( JTable t, Object value,
+                                                        boolean isSelected, 
+                                                        boolean f, int r, int c ) {
+            setIcon( ( ImageIcon ) value );
+            setText( "" );
+            setHorizontalAlignment( JLabel.CENTER );             
+
+            if ( isSelected )
+                setBackground( table.getSelectionBackground( ) );
+            else 
+                setBackground( table.getBackground( )          );     
+            
+            if ( exclude[ r ] )
+                setEnabled( false );
+            else 
+                setEnabled( true );            
+            return this; 
+        }
+    } 
+
+    /***************************************************************************
+     * Handles the change of the midlet icon file through a file chooser. 
+     * The icon files for a project are in directory res/icons, so if the
+     * chosen file is not in this directory, the file is copied into it.
+     */    
+    private class ChangeIconListener implements ActionListener 
+    {                
+        public void actionPerformed( ActionEvent event )
+        {
+            String iconsDir = projectDir + File.separator + MIDletDeployer.ICONS_DIR;
+            JFileChooser chooser = new JFileChooser( iconsDir );                   
+            chooser.setFileFilter( new IconFileFilter( ) );
+            chooser.setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES );
+            chooser.setDialogTitle( Config.getString( "midlet.deployment.filechooser.title" ) );
+                
+            int returnVal = chooser.showOpenDialog( getParent( ) );                  
+            if ( returnVal == JFileChooser.APPROVE_OPTION )
+            {
+                File chosenFile = chooser.getSelectedFile( );           
+                File fileInProj = new File( iconsDir, chosenFile.getName( ) );
+                
+                if ( ! chosenFile.getParent( ).equals( iconsDir ) ) {//chosen file is not in project
+                    if ( fileInProj.exists( ) ) { //file with same name already in project
+                        if ( DialogManager.askQuestion( frame, "error-midleticon-exists" ) != 0 )
+                            return;    //user does not want to overwrite file                  
+                    }
+                    try {
+                        FileUtility.copyFile( chosenFile, fileInProj );
+                    }
+                    catch (IOException ioe) {
+                        Debug.reportError( "Could not copy chosen icon file into <project dir>/res/icons.");
+                    }
+                } 
+                try {  //update the table with the new icon file
+                    URL url = fileInProj.toURI().toURL();
+                    String selectedFile = url.toString(); 
+                    int row = table.getSelectedRow( );
+                    tableModel.setValueAt( selectedFile, row , 2 );
+                 }
+                catch ( java.net.MalformedURLException mue ) {
+                    Debug.reportError( "Could not create URL from file selected by chooser." );
+                    mue.printStackTrace();
+                }                 
+            }
+         }
+    }
+    
+    /***************************************************************************
+     * A FileFilter to accept only valid midlet icon filetypes.
+     */
+    private class IconFileFilter extends FileFilter
+    {
+	public boolean accept( File f ) {
+		return ( f.getName( ).toLowerCase( ).endsWith( ".png" ) ||
+			 f.getName( ).toLowerCase( ).endsWith( ".gif" ) ||
+                         f.getName( ).toLowerCase( ).endsWith( ".jpg" ) ||
+			 f.getName( ).toLowerCase( ).endsWith( ".jpeg") );                
+	}	 
+	public String getDescription( ) {
+		return Config.getString( "midlet.deployment.filechooser.description" );
+	}
+     }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MIDletDeploymentTableModel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MIDletDeploymentTableModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..2069084f9cca17399cbd61f79d676d036ecfeabd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MIDletDeploymentTableModel.java
@@ -0,0 +1,298 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import bluej.Config;
+import bluej.utility.Debug;
+import bluej.utility.SortedProperties;
+import java.io.File;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.swing.ImageIcon;
+import javax.swing.table.AbstractTableModel;
+
+/**
+ * Table model of midlet entries.
+ * @author Cecilia Vargas
+ */
+public class MIDletDeploymentTableModel extends AbstractTableModel
+{   
+    private List<MIDletTableEntry> midlets;     //List of MIDletTableEntry's to display in table
+    private File       projectDir;
+    private ImageIcon  defaultIcon; //Default icon for midlets
+    private boolean[ ] exclude;     //Whether to exclude a midlet in the dialog.  
+
+    private String[ ] columnNames = {
+            Config.getString( "midlet.deployment.midlets.classname") ,
+            Config.getString( "midlet.deployment.midlets.name"     ) ,
+            Config.getString( "midlet.deployment.midlets.icon"     ) };
+      
+    public MIDletDeploymentTableModel(List<String> currentList, File proj, SortedProperties props)
+    {
+        projectDir = proj;
+        defaultIcon = getDefaultIcon();
+        fillInTable(currentList, props);
+    }
+    
+    public int     getColumnCount( )      { return 3; }
+
+    public int     getRowCount( )         { return midlets.size( );  }
+
+    public String  getColumnName( int c ) { return columnNames[ c ]; }
+    
+    public Class<?>  getColumnClass(int c ) { return getValueAt( 0, c ).getClass( ); }   
+    
+    public boolean isCellEditable( int r, int c ) { return c == 1; } //only name is editable
+
+    public Object getValueAt( int r, int c )
+    { 
+        MIDletTableEntry entry = ( MIDletTableEntry ) midlets.get( r );
+        if ( c == 0 ) 
+            return entry.getClassName( );
+        else if ( c == 1 )
+            return entry.getName( );
+        else if ( c == 2 )         
+            return entry.getIcon( );
+        else
+            return "ERROR in method getValueAt for row,col: " + r + "," + c;
+    }
+    
+    public void setValueAt( Object value, int r, int c )
+    {
+        if ( c == 1 || c == 2 ) {  
+            MIDletTableEntry entry = (MIDletTableEntry) midlets.get( r );    
+            
+            if ( c == 1 ) { 
+                entry.setName( ( String ) value );               
+            } else {
+                 try {
+                    URL url = new URL( ( String ) value );
+                    entry.setIcon( new ImageIcon( url ) );
+                } 
+                catch ( MalformedURLException mue ) {                     
+                    Debug.reportError( "In setValueAt, could not create ImageIcon from value passed in." );
+                }                 
+            }          
+            midlets.set( r, entry ); 
+            fireTableCellUpdated( r, c );
+        }     
+    }
+    
+    boolean[] getExcluded( ) { return exclude; }
+            
+    /***************************************************************************
+     * Fill in the table of midlets. Data comes from merging the Properties and
+     * List passed as arguments. The List is the current list of midlets
+     * in the project. Properties props has the data loaded from the midlet.defs
+     * file. Because midlets.defs has the midlets that were shown in the dialog
+     * the last time the dialog was displayed, we display all the midlet classes
+     * in list current but taking the name and icon from props. If the
+     * midlet class is not in props, we display it with default name and icon.
+     * Midlets in props but not in the list are ignored.    
+     * The method also allocates and fills in the array exclude which indicates
+     * whether a midlet is to be excluded or not in the dialog. Excluded midlets
+     * appear in the dialog as disabled and are excluded from the jad file.
+     * 
+     * <p>Note: icon file names in midlet.defs are in URL format, for example:
+     * file\:/C\:/BlueJProjects/MEprojects/WTKdemo/res/icons/myicon.gif
+     * 
+     * @param current  List of current midlets in the project. 
+     * @param props    Properties that were loaded from the midlet.defs file
+     */ 
+    private void fillInTable(List<String> current, SortedProperties props)
+    {   
+        String    cl;    // Fully qualified name of the MIDlet class.
+        String    icon;  // Name of the icon file.
+        String    name;  // Name of the midlet to be displayed in the emulator.
+        String    excl;  // Whether to exclude the midlet from the deployed suite.
+        ImageIcon image; // ImageIcon object created from the icon file.
+
+        midlets = new ArrayList<MIDletTableEntry>();  //List to fill in.        
+
+        exclude = new boolean[ current.size( ) ];
+        for ( int i = 0; i < exclude.length ; i++ ) {
+            exclude[ i ] = false;
+        }
+                            
+        int j = 0;
+        for ( int i = 1; ( cl = props.getProperty( "midlet" + i + ".class" ) ) != null; i++ )
+        {
+            if ( current.contains( cl ) )
+            {
+                current.remove( cl ); //remove cuz after loop we want only new midlets in current       
+                name = props.getProperty(  "midlet" + i + ".name"    );
+                icon = props.getProperty(  "midlet" + i + ".icon"    ); 
+                excl = props.getProperty(  "midlet" + i + ".exclude" );
+                exclude[ j ] = excl.equals( "true" );
+                j++;
+                image = defaultIcon;
+                try {
+                    image = new ImageIcon( new URL( icon ) );
+                } 
+                catch ( MalformedURLException mue ) {                     
+                    Debug.reportError( 
+                         "Could not create ImageIcon from midlet.defs info for midlet " 
+                          + name + ". The icon String passed to URL constructor was " + icon );
+                }                 
+                midlets.add( new MIDletTableEntry( name, image, cl ) );
+            }
+        }        
+        // Add to the table what is left in the current list. These are new
+        // midlets that were not displayed before in the dialog so we assign
+        // default values to their names and icons.      
+        for ( int i = 0 ; i < current.size( ) ; i++ ) {
+            cl = (String) current.get( i ); //qualified class name            
+            name = cl;       
+            //Strip off class name after the last dot if there are package names
+            int pos = cl.lastIndexOf(".");
+            if ( pos > 0 ) name = cl.substring( pos + 1 );
+            midlets.add( new MIDletTableEntry( name, defaultIcon, cl ) ); 
+        } 
+    }
+
+    /***************************************************************************
+     * Return the default icon, which is in <project dir>/res/icons/default.png.
+     * However, if this file does not exist, we have to fail gracefully. This 
+     * file is created by BlueJ when the ME project is created, so if the file
+     * does not exist it is probably because the user deleted it to not have a
+     * default icon.
+     */     
+    private ImageIcon getDefaultIcon( )
+    {
+        String defaultIconFilename = MIDletDeployer.ICONS_DIR + File.separator + 
+                                     MIDletDeployer.DEFAULT_MIDLET_ICON;
+        File file = new File( projectDir, defaultIconFilename  );
+        if ( file.exists( ) )
+            try {
+                return new ImageIcon( file.toURI( ).toURL( ) );
+            } catch ( java.net.MalformedURLException mue ) {
+                Debug.reportError( "For some strange reason BlueJ could not create a default icon." +
+                                   " This should never happen. Something is goofy.");
+            }
+        return new ImageIcon( );
+    }  
+    
+    /***************************************************************************
+     * Save the table of midlets into a Properties object.
+     * @param props   Properties objects into which to save the table.
+     */    
+    void saveTableToProps( SortedProperties props )
+    {
+        int i = 1;
+        for (Iterator<MIDletTableEntry> iterator = midlets.iterator(); iterator.hasNext();) {
+            MIDletTableEntry entry = ( MIDletTableEntry ) iterator.next();    
+            props.setProperty( "midlet" + i + ".name",  entry.getName() );
+            props.setProperty( "midlet" + i + ".class", entry.getClassName() );
+            String s = entry.getIcon().getDescription( );
+            if ( s == null ) s = " ";
+            props.setProperty( "midlet" + i + ".icon", s  );
+            props.setProperty( "midlet" + i + ".exclude", exclude[ i - 1 ] + "" );
+            i++;
+        }
+    }   
+
+    /***************************************************************************
+     * Write out to a PrintWriter the table of midlets.
+     * @param pw      PrintWriter to which to write the table.
+     */    
+    void writeTableToPrintWriter( PrintWriter pw )
+    {
+        int i = 1; 
+        int j = 0;
+        for (Iterator<MIDletTableEntry> iterator = midlets.iterator(); iterator.hasNext();)
+        {
+            MIDletTableEntry entry = ( MIDletTableEntry ) iterator.next(); 
+            if ( ! exclude[ j ] ) {                
+                String s = entry.getIcon().getDescription( );
+                if ( s == null ) 
+                    s = " ";  
+                else {
+                    int index = s.lastIndexOf( "/icons" );
+                    s = s.substring( index );
+                }
+                pw.println( "MIDlet-" + i + ": " + entry.getName() + ", " + s + ", " 
+                                                 + entry.getClassName() ); 
+                i++;
+            }
+            j++;
+        }
+    }        
+
+    /***************************************************************************
+     * Move up a row in the table.
+     * @param row   Row to move up.
+     */        
+    void moveRowUp( int row )
+    {
+        if ( row > 0 ) {
+            MIDletTableEntry temp = (MIDletTableEntry) midlets.get( row - 1 );
+            midlets.set( row - 1, midlets.get( row ) ); 
+            midlets.set( row, temp );             
+            fireTableRowsUpdated( row - 1, row );
+        }
+    }
+
+    /***************************************************************************
+     * Move down a row in the table.
+     * @param row   Row to move down.
+     */        
+    void moveRowDown( int row )
+    {
+        if ( row <  ( midlets.size() - 1 ) )  {
+            MIDletTableEntry temp = (MIDletTableEntry) midlets.get( row + 1 ); 
+            midlets.set( row + 1, midlets.get( row ) ); 
+            midlets.set( row, temp );                     
+            fireTableRowsUpdated( row, row + 1 );
+        }
+    }    
+
+    /***************************************************************************
+     * The entry of the table of midlets.
+     */        
+    private class MIDletTableEntry 
+    {
+        private ImageIcon icon;        
+        private String    name;
+        private String    className; //the qualified class name
+        
+        public MIDletTableEntry( String name, ImageIcon icon, String className)
+        {
+            this.name      = name;
+            this.icon      = icon;
+            this.className = className;
+        }        
+        public String    getName( )      { return name;      }
+        public String    getClassName( ) { return className; }
+        public ImageIcon getIcon( )      { return icon;      }    
+        
+        public void setName     ( String name )    { this.name = name; }
+        public void setIcon     ( ImageIcon icon ) { this.icon = icon; }   
+        
+        public String toString( ) {
+            return name + " ," + className + " ," + icon.getDescription( );
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MachineIcon.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MachineIcon.java
new file mode 100644
index 0000000000000000000000000000000000000000..565cf7d92869f109aeff6a6481af96b472022ff9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MachineIcon.java
@@ -0,0 +1,98 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.AWTEvent;
+import java.awt.event.MouseEvent;
+
+import javax.swing.*;
+
+import bluej.Config;
+import bluej.pkgmgr.actions.RestartVMAction;
+
+public class MachineIcon extends JLabel
+{
+    private static final Icon workingIcon = Config.getFixedImageAsIcon("working.gif");
+    private static final Icon notWorkingIcon = Config.getFixedImageAsIcon("working-idle.gif");
+    private static final Icon workingIconDisabled = Config.getFixedImageAsIcon("working-disab.gif");
+    private static final Icon stoppedIcon = Config.getFixedImageAsIcon("working-stopped.gif");
+
+    private JPopupMenu popupMenu;
+
+    public MachineIcon()
+    {
+        setIcon(notWorkingIcon);
+        setDisabledIcon(workingIconDisabled);
+        setToolTipText(Config.getString("tooltip.progress"));
+        popupMenu = createMachinePopup();
+        enableEvents(AWTEvent.KEY_EVENT_MASK);
+    }
+
+    /**
+     * Indicate that the machine is idle.
+     */
+    public void setIdle()
+    {
+        setIcon(notWorkingIcon);
+    }
+
+    /**
+     * Indicate that the machine is running.
+     */
+    public void setRunning()
+    {
+        setIcon(workingIcon);
+    }
+
+    /**
+     * Indicate that the machine is stopped.
+     */
+    public void setStopped()
+    {
+        setIcon(stoppedIcon);
+    }
+
+    /**
+     * Process a mouse click into this object. If it was a popup event, show the
+     * object's menu.
+     */
+    protected void processMouseEvent(MouseEvent evt)
+    {
+        if (!isEnabled())
+            return;
+
+        super.processMouseEvent(evt);
+
+        if (evt.isPopupTrigger()) {
+            popupMenu.show(this, 10, 10);
+        }
+    }
+
+    private JPopupMenu createMachinePopup()
+    {
+        JPopupMenu menu = new JPopupMenu();
+        JMenuItem item = new JMenuItem(RestartVMAction.getInstance());
+        menu.add(item);
+        return menu;
+    }
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MethodDocs.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MethodDocs.java
new file mode 100644
index 0000000000000000000000000000000000000000..39936f38a69dc30fa984d45c62cb5ce701159e85
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/MethodDocs.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.util.List;
+
+/**
+ * Simple container class for capturing method documentation - javadoc and parameter names.
+ * 
+ * @author Davin McCall
+ */
+public class MethodDocs
+{
+    private String javaDoc;
+    private List<String> paramNames;
+    
+    public MethodDocs(String javaDoc, List<String> paramNames)
+    {
+        this.javaDoc = javaDoc;
+        this.paramNames = paramNames;
+    }
+    
+    public String getJavaDoc()
+    {
+        return javaDoc;
+    }
+    
+    public List<String> getParamNames()
+    {
+        return paramNames;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/NewClassDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/NewClassDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..bda79a9ffdf86a3038f2619bfb4b3ade5495667e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/NewClassDialog.java
@@ -0,0 +1,317 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+
+import bluej.*;
+import bluej.utility.*;
+
+/**
+ * Dialog for creating a new class
+ *
+ * @author  Justin Tan
+ * @author  Michael Kolling
+ */
+class NewClassDialog extends EscapeDialog
+{
+    private JTextField textFld;
+    ButtonGroup templateButtons;
+
+    private String newClassName = "";
+    private boolean ok;   // result: which button?
+    private static List<String> windowsRestrictedWords;  //stores restricted windows class filenames
+
+    /**
+     * Construct a NewClassDialog
+     */
+    public NewClassDialog(JFrame parent, boolean isJavaMEpackage)
+    {
+        super(parent, Config.getString("pkgmgr.newClass.title"), true);
+        
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent E)
+            {
+                ok = false;
+                setVisible(false);
+            }
+        });
+
+        JPanel mainPanel = new JPanel();
+        {
+            mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+            mainPanel.setBorder(BlueJTheme.dialogBorder);
+
+            JLabel newclassTag = new JLabel(Config.getString("pkgmgr.newClass.label"));
+            {
+                newclassTag.setAlignmentX(LEFT_ALIGNMENT);
+            }
+
+            textFld = new JTextField(24);
+            {
+                textFld.setAlignmentX(LEFT_ALIGNMENT);
+            }
+
+            mainPanel.add(newclassTag);
+            mainPanel.add(textFld);
+            mainPanel.add(Box.createVerticalStrut(5));
+
+            JPanel choicePanel = new JPanel();
+            {
+                choicePanel.setLayout(new BoxLayout(choicePanel, BoxLayout.Y_AXIS));
+                choicePanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                //create compound border empty border outside of a titled border
+                Border b = BorderFactory.createCompoundBorder(
+                        BorderFactory.createTitledBorder(Config.getString("pkgmgr.newClass.classType")),
+                        BorderFactory.createEmptyBorder(0, 10, 0, 10));
+
+                choicePanel.setBorder(b);
+
+                addClassTypeButtons(choicePanel, isJavaMEpackage);
+            }
+
+            choicePanel.setMaximumSize(new Dimension(textFld.getMaximumSize().width,
+                                                     choicePanel.getMaximumSize().height));
+            choicePanel.setPreferredSize(new Dimension(textFld.getPreferredSize().width,
+                                                       choicePanel.getPreferredSize().height));
+
+            mainPanel.add(choicePanel);
+            mainPanel.add(Box.createVerticalStrut(BlueJTheme.dialogCommandButtonsVertical));
+
+            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+            {
+                buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                JButton okButton = BlueJTheme.getOkButton();
+                {
+                    okButton.addActionListener(new ActionListener()
+                    {
+                        public void actionPerformed(ActionEvent evt)
+                        {
+                            doOK();
+                        }
+                    });
+                }
+
+                JButton cancelButton = BlueJTheme.getCancelButton();
+                {
+                    cancelButton.addActionListener(new ActionListener()
+                    {
+                        public void actionPerformed(ActionEvent evt)
+                        {
+                            doCancel();
+                        }
+                    });
+                }
+
+                DialogManager.addOKCancelButtons(buttonPanel, okButton, cancelButton);
+                
+                getRootPane().setDefaultButton(okButton);
+            }
+
+            mainPanel.add(buttonPanel);
+        }
+
+        getContentPane().add(mainPanel);
+        pack();
+
+        DialogManager.centreDialog(this);
+    }
+
+    /**
+     * Add the class type buttons (defining the class template to be used
+     * to the panel. The templates are defined in the "defs" file.
+     */
+    private void addClassTypeButtons(JPanel panel, boolean isJavaMEpackage)
+    {
+        String templateSuffix = ".tmpl";
+        int suffixLength = templateSuffix.length();
+
+        // first, get templates out of defined templates from bluej.defs
+        // (we do this rather than usign the directory only to be able to
+        // force an order on the templates.)
+
+        String templateString = Config.getPropString("bluej.classTemplates");
+
+        StringTokenizer t = new StringTokenizer(templateString);
+        List<String> templates = new ArrayList<String>();
+
+        while (t.hasMoreTokens()) {
+            templates.add(t.nextToken());
+        }
+
+        // next, get templates from files in template directory and
+        // merge them in
+
+        File templateDir = Config.getClassTemplateDir();
+        if(!templateDir.exists()) {
+            DialogManager.showError(this, "error-no-templates");
+        }
+        else {
+            String[] files = templateDir.list();
+            
+            for(int i=0; i < files.length; i++) {
+                if(files[i].endsWith(templateSuffix)) {
+                    String template = files[i].substring(0, files[i].length() - suffixLength);
+                    if(!templates.contains(template))
+                        templates.add(template);
+                }
+            }
+        }        
+       
+        // In Java ME packages disallow the creation of enum, unittest, and applet
+        // classes. In SE packages disallow the creation of midlets.
+        if ( isJavaMEpackage ) {
+            templates.remove( "enum"     );
+            templates.remove( "unittest" );  
+            templates.remove( "appletj"  );            
+         }
+         else {            
+            templates.remove( "midlet" );             
+         }
+       
+        // Create a radio button for each template found
+        JRadioButton button;
+        JRadioButton previousButton = null;
+        templateButtons = new ButtonGroup();
+
+        for(Iterator<String> i=templates.iterator(); i.hasNext(); ) {
+            String template = i.next();
+            String label = Config.getString("pkgmgr.newClass." + template, template);
+            button = new JRadioButton(label, (previousButton==null));  // enable first
+            button.setActionCommand(template);
+            templateButtons.add(button);
+            panel.add(button);
+            previousButton = button;
+        }
+    }
+
+    /**
+     * Show this dialog and return true if "OK" was pressed, false if
+     * cancelled.
+     */
+    public boolean display()
+    {
+        ok = false;
+        textFld.requestFocus();
+        setVisible(true);  // modal - we sit here until closed
+        return ok;
+    }
+
+    public String getClassName()
+    {
+        return newClassName;
+    }
+
+    public String getTemplateName()
+    {
+        return templateButtons.getSelection().getActionCommand();
+    }
+
+    /**
+     * Close action when OK is pressed.
+     */
+    public void doOK()
+    {
+        newClassName = textFld.getText().trim();
+        initialiseRestrictedWordList();
+        if (JavaNames.isIdentifier(newClassName) && 
+                !(isWindowsRestrictedWord(newClassName))) {
+            ok = true;
+            setVisible(false);
+        }
+        else 
+        {
+            if (isWindowsRestrictedWord(newClassName)) {
+                DialogManager.showError((JFrame)this.getParent(), "windows-reserved-class-name");
+            }
+            else {
+                DialogManager.showError((JFrame)this.getParent(), "invalid-class-name");            
+            }
+            textFld.selectAll();
+            textFld.requestFocus();
+        }
+
+    }
+
+    /**
+     * Close action when Cancel is pressed.
+     */
+    public void doCancel()
+    {
+        ok = false;
+        setVisible(false);
+    }
+    
+    /**
+     * Tests for restricted class names (case insensitive)
+     * @param fileName potential class name
+     * @return true if restricted word
+     */
+    private boolean isWindowsRestrictedWord(String fileName)
+    {
+        if (windowsRestrictedWords.contains(fileName.toUpperCase())){
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * Initialises the list of restricted words
+     */
+    private void initialiseRestrictedWordList()
+    {
+        if (windowsRestrictedWords==null){
+            windowsRestrictedWords=new ArrayList<String>();
+            windowsRestrictedWords.add("CON");
+            windowsRestrictedWords.add("PRN");
+            windowsRestrictedWords.add("AUX");
+            windowsRestrictedWords.add("NUL");
+            windowsRestrictedWords.add("COM1");
+            windowsRestrictedWords.add("COM2");
+            windowsRestrictedWords.add("COM3");
+            windowsRestrictedWords.add("COM4");
+            windowsRestrictedWords.add("COM5");
+            windowsRestrictedWords.add("COM6");
+            windowsRestrictedWords.add("COM7");
+            windowsRestrictedWords.add("COM8");
+            windowsRestrictedWords.add("COM9");
+            windowsRestrictedWords.add("LPT1");
+            windowsRestrictedWords.add("LPT2");
+            windowsRestrictedWords.add("LPT3");
+            windowsRestrictedWords.add("LPT4");
+            windowsRestrictedWords.add("LPT5");
+            windowsRestrictedWords.add("LPT6");
+            windowsRestrictedWords.add("LPT7");
+            windowsRestrictedWords.add("LPT8");
+            windowsRestrictedWords.add("LPT9");
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/NewPackageDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/NewPackageDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ef1c8e2adf44401e5507c41401c8d66833e5cfd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/NewPackageDialog.java
@@ -0,0 +1,153 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import bluej.*;
+import bluej.Config;
+import bluej.utility.EscapeDialog;
+import bluej.utility.JavaNames;
+import bluej.utility.DialogManager;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * Dialog for creating a new Package
+ *
+ * @author  Justin Tan
+ * @author  Michael Kolling
+ * @version $Id: NewPackageDialog.java 7055 2010-01-27 13:58:55Z plcs $
+ */
+class NewPackageDialog extends EscapeDialog
+{
+    private String newPackageName = "";
+
+    private JTextField textFld;
+
+    private boolean ok;		// result: which button?
+
+	public NewPackageDialog(JFrame parent)
+	{
+		super(parent, Config.getString("pkgmgr.newPackage.title"), true);
+
+		addWindowListener(new WindowAdapter() {
+			public void windowClosing(WindowEvent E)
+			{
+				ok = false;
+				setVisible(false);
+			}
+		});
+
+		JPanel mainPanel = new JPanel();
+		{
+			mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+			mainPanel.setBorder(BlueJTheme.dialogBorder);
+
+			JLabel newclassTag = new JLabel(Config.getString("pkgmgr.newPackage.label"));
+			{
+				newclassTag.setAlignmentX(LEFT_ALIGNMENT);
+			}
+
+			textFld = new JTextField(24);
+			{
+				textFld.setAlignmentX(LEFT_ALIGNMENT);
+			}
+
+			mainPanel.add(newclassTag);
+			mainPanel.add(textFld);
+			mainPanel.add(Box.createVerticalStrut(5));
+
+			mainPanel.add(Box.createVerticalStrut(BlueJTheme.dialogCommandButtonsVertical));
+
+			JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+			{
+				buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+				JButton okButton = BlueJTheme.getOkButton();
+				okButton.addActionListener(new ActionListener() {
+					public void actionPerformed(ActionEvent evt) { doOK(); }        		
+				});
+
+				JButton cancelButton = BlueJTheme.getCancelButton();
+				cancelButton.addActionListener(new ActionListener() {
+					public void actionPerformed(ActionEvent evt) { doCancel(); }        		
+				});
+
+                                DialogManager.addOKCancelButtons(buttonPanel, okButton, cancelButton);
+
+				getRootPane().setDefaultButton(okButton);
+			}
+
+			mainPanel.add(buttonPanel);
+		}
+
+		getContentPane().add(mainPanel);
+		pack();
+
+		DialogManager.centreDialog(this);
+	}
+
+    /**
+     * Show this dialog and return true if "OK" was pressed, false if
+     * cancelled.
+     */
+    public boolean display()
+    {
+        ok = false;
+        textFld.requestFocus();
+        setVisible(true);
+        return ok;
+    }
+
+    public String getPackageName()
+    {
+        return newPackageName;
+    }
+
+    /**
+     * Close action when OK is pressed.
+     */
+    public void doOK()
+    {
+        newPackageName = textFld.getText().trim();
+
+        if (JavaNames.isQualifiedIdentifier(newPackageName)) {
+            ok = true;
+            setVisible(false);
+        }
+        else {
+            DialogManager.showError((JFrame)this.getParent(), "invalid-package-name");
+            textFld.selectAll();
+            textFld.requestFocus();
+        }
+    }
+
+    /**
+     * Close action when Cancel is pressed.
+     */
+    public void doCancel()
+    {
+        ok = false;
+        setVisible(false);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/Package.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/Package.java
new file mode 100644
index 0000000000000000000000000000000000000000..24722248f4475ef59069966f266127ce75e72ff2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/Package.java
@@ -0,0 +1,2916 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Modifier;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import bluej.Config;
+import bluej.compiler.CompileObserver;
+import bluej.compiler.Diagnostic;
+import bluej.compiler.EventqueueCompileObserver;
+import bluej.compiler.JobQueue;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerThread;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugger.SourceLocation;
+import bluej.debugmgr.CallHistory;
+import bluej.debugmgr.Invoker;
+import bluej.editor.Editor;
+import bluej.extensions.BDependency;
+import bluej.extensions.BPackage;
+import bluej.extensions.ExtensionBridge;
+import bluej.extensions.event.CompileEvent;
+import bluej.extensions.event.DependencyEvent;
+import bluej.extmgr.ExtensionsManager;
+import bluej.graph.Edge;
+import bluej.graph.Graph;
+import bluej.parser.AssistContent;
+import bluej.parser.CodeSuggestions;
+import bluej.parser.ParseUtils;
+import bluej.parser.symtab.ClassInfo;
+import bluej.parser.symtab.Selection;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.dependency.ExtendsDependency;
+import bluej.pkgmgr.dependency.ImplementsDependency;
+import bluej.pkgmgr.dependency.UsesDependency;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.DependentTarget;
+import bluej.pkgmgr.target.EditableTarget;
+import bluej.pkgmgr.target.PackageTarget;
+import bluej.pkgmgr.target.ParentPackageTarget;
+import bluej.pkgmgr.target.ReadmeTarget;
+import bluej.pkgmgr.target.Target;
+import bluej.pkgmgr.target.TargetCollection;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+import bluej.utility.JavaNames;
+import bluej.utility.MultiIterator;
+import bluej.utility.SortedProperties;
+import bluej.utility.filefilter.JavaClassFilter;
+import bluej.utility.filefilter.JavaSourceFilter;
+import bluej.utility.filefilter.SubPackageFilter;
+
+/**
+ * A Java package (collection of Java classes).
+ * 
+ * @author Michael Kolling
+ * @author Axel Schmolitzky
+ * @author Andrew Patterson
+ */
+public final class Package extends Graph
+{
+    /** message to be shown on the status bar */
+    static final String compiling = Config.getString("pkgmgr.compiling");
+    /** message to be shown on the status bar */
+    static final String compileDone = Config.getString("pkgmgr.compileDone");
+    /** message to be shown on the status bar */
+    static final String chooseUsesTo = Config.getString("pkgmgr.chooseUsesTo");
+    /** message to be shown on the status bar */
+    static final String chooseInhTo = Config.getString("pkgmgr.chooseInhTo");
+
+    /**
+     * the name of the package file in a package directory that holds
+     * information about the package and its targets.
+     */
+    private PackageFile packageFile;
+    
+    /** Readme file name */
+    public static final String readmeName = "README.TXT";
+
+    /** error code */
+    public static final int NO_ERROR = 0;
+    /** error code */
+    public static final int FILE_NOT_FOUND = 1;
+    /** error code */
+    public static final int ILLEGAL_FORMAT = 2;
+    /** error code */
+    public static final int COPY_ERROR = 3;
+    /** error code */
+    public static final int CLASS_EXISTS = 4;
+    /** error code */
+    public static final int CREATE_ERROR = 5;
+
+    /**
+     * In the top left corner of each package we have a fixed target - either a
+     * ParentPackageTarget or a ReadmeTarget. These are there locations
+     */
+    public static final int FIXED_TARGET_X = 10;
+    public static final int FIXED_TARGET_Y = 10;
+
+    /** the Project this package is in */
+    private final Project project;
+
+    /**
+     * the parent Package object for this package or null if this is the unnamed
+     * package ie. the root of the package tree
+     */
+    private final Package parentPackage;
+
+    /** base name of package (eg util) ("" for the unnamed package) */
+    private final String baseName;
+
+    /**
+     * this properties object contains the properties loaded off disk for this
+     * package, or the properties which were most recently saved to disk for
+     * this package
+     */
+    private SortedProperties lastSavedProps = new SortedProperties();
+
+    /** all the targets in a package */
+    private TargetCollection targets;
+
+    /** all the uses-arrows in a package */
+    private List<Dependency> usesArrows;
+
+    /** all the extends-arrows in a package */
+    private List<Dependency> extendsArrows;
+
+    /** Holds the choice of "from" target for a new dependency */
+    private DependentTarget fromChoice;
+
+    /** the CallHistory of a package */
+    private CallHistory callHistory;
+
+    /** whether extends-arrows should be shown */
+    private boolean showExtends = true;
+    /** whether uses-arrows should be shown */
+    private boolean showUses = true;
+
+    /**
+     * needed when debugging with breakpoints to see if the editor window needs
+     * to be brought to the front
+     */
+    private String lastSourceName = "";
+
+    /** state constant - normal state */
+    public static final int S_IDLE = 0;
+    /** state constant - choose the "from" target of a "uses" dependency arrow */
+    public static final int S_CHOOSE_USES_FROM = 1;
+    /** state constant - choose the "to" target for a "uses" dependency arrow */
+    public static final int S_CHOOSE_USES_TO = 2;
+    /** state constant - choose the "from" target of an "extends" arrow */
+    public static final int S_CHOOSE_EXT_FROM = 3;
+    /** state constant - choose the "to" target for an "extends" arrow */
+    public static final int S_CHOOSE_EXT_TO = 4;
+
+    /** determines the maximum length of the CallHistory of a package */
+    public static final int HISTORY_LENGTH = 6;
+
+    /** the state a package can be in (one of the S_* values) */
+    private int state = S_IDLE;
+
+    private PackageEditor editor;
+    
+    /** File pointing at the directory for this package */
+    private File dir;
+
+    /* ------------------- end of field declarations ------------------- */
+
+    /**
+     * Create a package of a project with the package name of baseName (ie
+     * reflect) and with a parent package of parent (which may represent
+     * java.lang for instance) If the package file (bluej.pkg) is not found, an
+     * IOException is thrown.
+     */
+    public Package(Project project, String baseName, Package parent)
+        throws IOException
+    {
+        if (parent == null)
+            throw new NullPointerException("Package must have a valid parent package");
+
+        if (baseName.length() == 0)
+            throw new IllegalArgumentException("unnamedPackage must be created using Package(project)");
+
+        if (!JavaNames.isIdentifier(baseName))
+            throw new IllegalArgumentException(baseName + " is not a valid name for a Package");
+
+        this.project = project;
+        this.baseName = baseName;
+        this.parentPackage = parent;
+
+        init();
+    }
+
+    /**
+     * Create the unnamed package of a project If the package file (bluej.pkg)
+     * is not found, an IOException is thrown.
+     */
+    public Package(Project project)
+        throws IOException
+    {
+        this.project = project;
+        this.baseName = "";
+        this.parentPackage = null;
+
+        init();
+    }
+
+    private void init()
+        throws IOException
+    {
+        targets = new TargetCollection();
+        usesArrows = new ArrayList<Dependency>();
+        extendsArrows = new ArrayList<Dependency>();
+        callHistory = new CallHistory(HISTORY_LENGTH);
+        dir = new File(project.getProjectDir(), getRelativePath().getPath());
+        load();
+    }
+
+    public boolean isUnnamedPackage()
+    {
+        return parentPackage == null;
+    }
+
+    /**
+     * Return the project this package belongs to.
+     */
+    public Project getProject()
+    {
+        return project;
+    }
+
+    private BPackage singleBPackage;  // Every Package has none or one BPackage
+    
+    /**
+     * Return the extensions BPackage associated with this Package.
+     * There should be only one BPackage object associated with each Package.
+     * @return the BPackage associated with this Package.
+     */
+    public synchronized final BPackage getBPackage ()
+    {
+        if ( singleBPackage == null )
+          singleBPackage = ExtensionBridge.newBPackage(this);
+          
+        return singleBPackage;
+    }
+
+
+    /**
+     * Get the unique identifier for this package (it's directory name at
+     * present)
+     */
+    public String getId()
+    {
+        return getPath().getPath();
+    }
+
+    /**
+     * Return this package's base name (eg util) ("" for the unnamed package)
+     */
+    public String getBaseName()
+    {
+        return baseName;
+    }
+
+    /**
+     * Return the qualified name of an identifier in this package (eg
+     * java.util.Random if given Random)
+     */
+    public String getQualifiedName(String identifier)
+    {
+        if (isUnnamedPackage())
+            return identifier;
+        else
+            return getQualifiedName() + "." + identifier;
+    }
+
+    /**
+     * Return the qualified name of the package (eg. java.util) ("" for the
+     * unnamed package)
+     */
+    public String getQualifiedName()
+    {
+        Package currentPkg = this;
+        String retName = "";
+
+        while (!currentPkg.isUnnamedPackage()) {
+            if (retName == "")
+                retName = currentPkg.getBaseName();
+            else
+                retName = currentPkg.getBaseName() + "." + retName;
+
+            currentPkg = currentPkg.getParent();
+        }
+
+        return retName;
+    }
+
+    /**
+     * get the readme target for this package
+     *  
+     */
+    public ReadmeTarget getReadmeTarget()
+    {
+        ReadmeTarget readme = (ReadmeTarget) targets.get(ReadmeTarget.README_ID);
+        return readme;
+    }
+
+    /**
+     * Construct a path for this package relative to the project.
+     * 
+     * @return The relative path.
+     */
+    private File getRelativePath()
+    {
+        Package currentPkg = this;
+        File retFile = new File(currentPkg.getBaseName());
+
+        /*
+         * loop through our parent packages constructing a relative path for
+         * this file
+         */
+        while (!currentPkg.isUnnamedPackage()) {
+            currentPkg = currentPkg.getParent();
+
+            retFile = new File(currentPkg.getBaseName(), retFile.getPath());
+        }
+
+        return retFile;
+    }
+
+    /**
+     * Return a file object of the directory location of this package.
+     * 
+     * @return The file object representing the full path to the packages
+     *         directory
+     */
+    public File getPath() 
+    {
+        return dir;
+    }
+
+    /**
+     * Return our parent package or null if we are the unnamed package.
+     */
+    public Package getParent()
+    {
+        return parentPackage;
+    }
+
+    /**
+     * Returns the sub-package if this package is "boring". Our definition of
+     * boring is that the package has no classes in it and only one sub package.
+     * If this package is not boring, this method returns null.
+     */
+    protected Package getBoringSubPackage()
+    {
+        PackageTarget pt = null;
+
+        for (Iterator<Target> e = targets.iterator(); e.hasNext();) {
+            Target target = (Target) e.next();
+
+            if (target instanceof ClassTarget)
+                return null;
+
+            if ((target instanceof PackageTarget) && !(target instanceof ParentPackageTarget)) {
+                // we have found our second sub package
+                // this means this package is not boring
+                if (pt != null)
+                    return null;
+
+                pt = (PackageTarget) target;
+            }
+        }
+
+        if (pt == null)
+            return null;
+
+        return getProject().getPackage(pt.getQualifiedName());
+    }
+
+    /**
+     * Return an array of package objects which are nested one level below us.
+     * 
+     * @param getUncached   should be true if unopened packages should be included
+     */
+    protected List<Package> getChildren(boolean getUncached)
+    {
+        List<Package> children = new ArrayList<Package>();
+
+        for (Iterator<Target> e = targets.iterator(); e.hasNext();) {
+            Target target = e.next();
+
+            if (target instanceof PackageTarget && !(target instanceof ParentPackageTarget)) {
+                PackageTarget pt = (PackageTarget) target;
+
+                Package child;
+                if (getUncached) {
+                    child = getProject().getPackage(pt.getQualifiedName());
+                }
+                else {
+                    child = getProject().getCachedPackage(pt.getQualifiedName());
+                }
+
+                if (child == null)
+                    continue;
+
+                children.add(child);
+            }
+        }
+
+        return children;
+    }
+
+    public void setStatus(String msg)
+    {
+        PkgMgrFrame.displayMessage(this, msg);
+    }
+
+    public void repaint()
+    {
+        if (editor != null) {
+            editor.repaint();
+        }
+    }
+
+    void setEditor(PackageEditor editor)
+    {
+        this.editor = editor;
+    }
+    
+    public PackageEditor getEditor()
+    {
+        return editor;
+    }
+
+    public Properties getLastSavedProperties()
+    {
+        return lastSavedProps;
+    }
+
+    /**
+     * Get the currently selected Targets. It will return an empty array if no
+     * target is selected.
+     * 
+     * @return the currently selected array of Targets.
+     */
+    public Target[] getSelectedTargets()
+    {
+        Target[] targetArray = new Target[0];
+        LinkedList<Target> list = new LinkedList<Target>();
+        for (Iterator<Target> it = getVertices(); it.hasNext();) {
+            Target target = it.next();
+            if (target.isSelected()) {
+                list.add(target);
+            }
+        }
+        return (Target[]) list.toArray(targetArray);
+    }
+
+    /**
+     * Get the selected Dependencies.
+     * 
+     * @return The currently selected dependency or null.
+     */
+    public Dependency getSelectedDependency()
+    {
+        for (Iterator<? extends Edge> it = getEdges(); it.hasNext();) {
+            Edge edge = it.next();
+            if (edge instanceof Dependency && edge.isSelected()) {
+                return (Dependency) edge;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the {@link Dependency} with the specified <code>origin</code>,
+     * <code>target</code> and <code>type</code> or <code>null</code> if there
+     * is no such dependency.
+     * 
+     * @param origin
+     *            The origin of the dependency.
+     * @param target
+     *            The target of the dependency.
+     * @param type
+     *            The type of the dependency (there may be more than one
+     *            dependencies with the same origin and target but different
+     *            types).
+     * @return The {@link Dependency} with the specified <code>origin</code>,
+     *         <code>target</code> and <code>type</code> or <code>null</code> if
+     *         there is no such dependency.
+     */
+    public Dependency getDependency(DependentTarget origin, DependentTarget target, BDependency.Type type)
+    {
+        List<Dependency> dependencies = new ArrayList<Dependency>();
+
+        switch (type) {
+            case USES :
+                dependencies = usesArrows;
+                break;
+            case IMPLEMENTS :
+            case EXTENDS :
+                dependencies = extendsArrows;
+                break;
+            case UNKNOWN :
+                // If the type of the dependency is UNKNOWN, the requested
+                // dependency does not exist anymore. In this case the method
+                // returns null.
+                return null;
+        }
+
+        for (Dependency dependency : dependencies) {
+            DependentTarget from = dependency.getFrom();
+            DependentTarget to = dependency.getTo();
+
+            if (from.equals(origin) && to.equals(target)) {
+                return dependency;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Search a directory for Java source and class files and add their names to
+     * a set which is returned. Will delete any __SHELL files which are found in
+     * the directory and will ignore any single .class files which do not
+     * contain public classes.
+     * 
+     * The returned set is guaranteed to be only valid Java identifiers.
+     */
+    private Set<String> findTargets(File path)
+    {
+        File srcFiles[] = path.listFiles(new JavaSourceFilter());
+        File classFiles[] = path.listFiles(new JavaClassFilter());
+
+        Set<String> interestingSet = new HashSet<String>();
+
+        // process all *.java files
+        for (int i = 0; i < srcFiles.length; i++) {
+            // remove all __SHELL*.java files (temp files created by us)
+            if (srcFiles[i].getName().startsWith(Invoker.SHELLNAME)) {
+                srcFiles[i].delete();
+                continue;
+            }
+            String javaFileName = JavaNames.stripSuffix(srcFiles[i].getName(), ".java");
+
+            // check if the name would be a valid java name
+            if (!JavaNames.isIdentifier(javaFileName))
+                continue;
+
+            // files with a $ in them signify inner classes (which we want to
+            // ignore)
+            if (javaFileName.indexOf('$') == -1)
+                interestingSet.add(javaFileName);
+        }
+
+        // process all *.class files
+        for (int i = 0; i < classFiles.length; i++) {
+            // remove all __SHELL*.class files (temp files created by us)
+            if (classFiles[i].getName().startsWith(Invoker.SHELLNAME)) {
+                classFiles[i].delete();
+                continue;
+            }
+            String classFileName = JavaNames.stripSuffix(classFiles[i].getName(), ".class");
+
+            // check if the name would be a valid java name
+            if (!JavaNames.isIdentifier(classFileName))
+                continue;
+
+            if (classFileName.indexOf('$') == -1) {
+                // add only if there is no corresponding .java file
+                if (!interestingSet.contains(classFileName)) {
+                    try {
+                        Class<?> c = loadClass(getQualifiedName(classFileName));
+
+                        // fix for bug 152
+                        // check that this class is a public class which means
+                        // that private and package .class files generated
+                        // because there are multiple classes defined in a
+                        // single file will not add a target
+                        if (c != null && Modifier.isPublic(c.getModifiers()))
+                            interestingSet.add(classFileName);
+                    }
+                    catch (LinkageError e) {
+                        Debug.message(e.toString());
+                    }
+                }
+            }
+        }
+
+        return interestingSet;
+    }
+
+    /**
+     * Load the elements of a package from a specified directory. If the package
+     * file (bluej.pkg) is not found, an IOException is thrown.
+     * 
+     * <p>This does not cause targets to be loaded. Use refreshPackage() for that.
+     */
+    public void load()
+        throws IOException
+    {
+        // read the package properties
+        
+        packageFile = getPkgFile();
+        
+        // try to load the package file for this package
+        packageFile.load(lastSavedProps);
+    }
+    
+    /**
+     * Refresh the targets and dependency arrows in the package, based on whatever
+     * is actually on disk.
+     */
+    public void refreshPackage()
+    {
+        // read in all the targets contained in this package
+        // into this temporary map
+        Map<String,Target> propTargets = new HashMap<String,Target>();
+
+        int numTargets = 0, numDependencies = 0;
+
+        try {
+            numTargets = Integer.parseInt(lastSavedProps.getProperty("package.numTargets", "0"));
+            numDependencies = Integer.parseInt(lastSavedProps.getProperty("package.numDependencies", "0"));
+        }
+        catch (Exception e) {
+            Debug.reportError("Error loading from package file " + packageFile + ": " + e);
+            e.printStackTrace();
+            return;
+        }
+
+        for (int i = 0; i < numTargets; i++) {
+            Target target;
+            String type = lastSavedProps.getProperty("target" + (i + 1) + ".type");
+            String identifierName = lastSavedProps.getProperty("target" + (i + 1) + ".name");
+
+            if ("PackageTarget".equals(type))
+                target = new PackageTarget(this, identifierName);
+            else {
+                target = new ClassTarget(this, identifierName);
+            }
+
+            target.load(lastSavedProps, "target" + (i + 1));
+            propTargets.put(identifierName, target);
+        }
+
+        addImmovableTargets();
+        List<Target> targetsToPlace = new ArrayList<Target>();
+        
+        // make our Package targets reflect what is actually on disk
+        // note that we consider this on-disk version the master
+        // version so if we have a class target called Foo but we
+        // discover a directory call Foo, a PackageTarget will be
+        // inserted to replace the ClassTarget
+        File subDirs[] = getPath().listFiles(new SubPackageFilter());
+        
+        for (int i = 0; i < subDirs.length; i++) {
+            // first check if the directory name would be a valid package name
+            if (!JavaNames.isIdentifier(subDirs[i].getName()))
+                continue;
+
+            Target target = propTargets.get(subDirs[i].getName());
+
+            if (target == null || !(target instanceof PackageTarget)) {
+                target = new PackageTarget(this, subDirs[i].getName());
+                targetsToPlace.add(target);
+            }
+
+            addTarget(target);
+        }
+
+        // now look for Java source files that may have been
+        // added to the directory
+        Set<String> interestingSet = findTargets(getPath());
+
+        // also we migrate targets from propTargets across
+        // to our real list of targets in this loop.
+        Iterator<String> it = interestingSet.iterator();
+        while (it.hasNext()) {
+            String targetName = it.next();
+
+            Target target = propTargets.get(targetName);
+            if (target == null || !(target instanceof ClassTarget)) {
+                target = new ClassTarget(this, targetName);
+                targetsToPlace.add(target);
+            }
+            addTarget(target);
+        }
+        
+        // Find an empty spot for any targets which didn't already have
+        // a position
+        for (Target t : targetsToPlace) {
+            findSpaceForVertex(t);
+        }
+        
+        // Start with all classes in the normal (compiled) state.
+        Iterator<Target> targetIt = targets.iterator();
+        for ( ; targetIt.hasNext();) {
+            Target target = targetIt.next();
+            if (target instanceof ClassTarget) {
+                ClassTarget ct = (ClassTarget) target;
+                ct.setState(ClassTarget.S_NORMAL);
+            }
+        }
+
+        // Fix up dependency information
+        for (int i = 0; i < numDependencies; i++) {
+            Dependency dep = null;
+            String type = lastSavedProps.getProperty("dependency" + (i + 1) + ".type");
+
+            if ("UsesDependency".equals(type))
+                dep = new UsesDependency(this);
+
+            if (dep != null) {
+                dep.load(lastSavedProps, "dependency" + (i + 1));
+                addDependency(dep, false);
+            }
+        }
+        recalcArrows();
+
+        // Update class states. We do this before updating roles (or anything else
+        // which analyses the source) because the analysis does symbol resolution, and
+        // that depends on having the correct compiled state.
+        LinkedList<ClassTarget> invalidated = new LinkedList<ClassTarget>();
+        targetIt = targets.iterator();
+        for ( ; targetIt.hasNext();) {
+            Target target = targetIt.next();
+
+            if (target instanceof ClassTarget) {
+                ClassTarget ct = (ClassTarget) target;
+                if (ct.isCompiled() && !ct.upToDate()) {
+                    ct.setState(ClassTarget.S_INVALID);
+                    invalidated.add(ct);
+                }
+            }
+        }
+        
+        while (! invalidated.isEmpty()) {
+            ClassTarget ct = invalidated.removeFirst();
+            for (Dependency dependent : ct.dependentsAsList()) {
+                DependentTarget dt = dependent.getFrom();
+                if (dt instanceof ClassTarget) {
+                    ClassTarget dep = (ClassTarget) dt;
+                    if (dep.isCompiled()) {
+                        dep.setState(ClassTarget.S_INVALID);
+                        invalidated.add(dep);
+                    }
+                }
+            }
+        }
+        
+        // Update class roles
+        targetIt = targets.iterator();
+        for ( ; targetIt.hasNext();) {
+            Target target = targetIt.next();
+
+            if (target instanceof ClassTarget) {
+                ClassTarget ct = (ClassTarget) target;
+                if (ct.isCompiled()) {
+                    Class<?> cl = loadClass(ct.getQualifiedName());
+                    ct.determineRole(cl);
+                    ct.analyseDependencies(cl);
+                    if (cl == null) {
+                        ct.setState(ClassTarget.S_INVALID);
+                    }
+                }
+                else {
+                    ct.analyseSource();
+                    try {
+                        ct.enforcePackage(getQualifiedName());
+                    }
+                    catch (IOException ioe) {
+                        Debug.message("Error enforcing class package: " + ioe.getLocalizedMessage());
+                    }
+                }
+            }
+        }
+
+        // our associations are based on name so we mustn't deal with
+        // them until all classes/packages have been loaded
+        for (int i = 0; i < numTargets; i++) {
+            String assoc = lastSavedProps.getProperty("target" + (i + 1) + ".association");
+            String identifierName = lastSavedProps.getProperty("target" + (i + 1) + ".name");
+
+            if (assoc != null) {
+                Target t1 = getTarget(identifierName), t2 = getTarget(assoc);
+
+                if (t1 != null && t2 != null && t1 instanceof DependentTarget) {
+                    DependentTarget dt = (DependentTarget) t1;
+                    dt.setAssociation((DependentTarget)t2);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Returns the file containing information about the package.
+     * For BlueJ this is package.bluej (or for older versions bluej.pkg) 
+     * and for Greenfoot it is greenfoot.project.
+     */
+    private PackageFile getPkgFile()
+    {
+        File dir = getPath();
+        return PackageFileFactory.getPackageFile(dir);
+    }
+
+    /**
+     * Position a target which has been added, based on the layout file
+     * (if an entry exists) or find a suitable position otherwise.
+     * 
+     * @param t  the target to position
+     */
+    public void positionNewTarget(Target t)
+    {
+        String targetName = t.getIdentifierName();
+
+        try {
+            int numTargets = Integer.parseInt(lastSavedProps.getProperty("package.numTargets", "0"));
+            for (int i = 0; i < numTargets; i++) {
+                String identifierName = lastSavedProps.getProperty("target" + (i + 1) + ".name");
+                if (identifierName.equals(targetName)) {
+                    t.load(lastSavedProps, "target" + (i + 1));
+                    return;
+                }
+            }
+        }
+        catch (NumberFormatException e) {}
+
+        // If we get here, then we didn't find a location for the target
+        findSpaceForVertex(t);
+    }
+    
+    /**
+     * Add our immovable targets (the readme file, and possibly a link to the
+     * parent package)
+     */ 
+    private void addImmovableTargets()
+    {
+        // which goes to the parent package)
+        //        if (isUnnamedPackage()) {
+        //            Target t = new ReadmeTarget(this);
+        //            t.setPos(FIXED_TARGET_X,FIXED_TARGET_Y);
+        //            addTarget(t);
+        //        }
+        //        else {
+        //            Target t = new ParentPackageTarget(this);
+        //            t.setPos(FIXED_TARGET_X,FIXED_TARGET_Y);
+        //            addTarget(t);
+        //        }
+        Target t = new ReadmeTarget(this);
+        //Take special care of ReadmeTarget
+        //see ReadmeTarget.isSaveable for explanation
+        t.load(lastSavedProps, "readme");
+        t.setPos(FIXED_TARGET_X, FIXED_TARGET_Y);
+        addTarget(t);
+        if (!isUnnamedPackage()) {
+            t = new ParentPackageTarget(this);
+            findSpaceForVertex(t);
+            addTarget(t);
+        }
+
+    }
+
+    /**
+     * Reload a package.
+     * 
+     * This means we check the existing directory contents and compare it
+     * against the targets we have in the package. Any new directories or java
+     * source is added to the package. This function will not remove targets
+     * that have had their corresponding on disk counterparts removed.
+     * 
+     * Any new source files will have their package lines updated to match the
+     * package we are in.
+     */
+    public void reload()
+    {
+        File subDirs[] = getPath().listFiles(new SubPackageFilter());
+
+        for (int i = 0; i < subDirs.length; i++) {
+            // first check if the directory name would be a valid package name
+            if (!JavaNames.isIdentifier(subDirs[i].getName()))
+                continue;
+
+            Target target = targets.get(subDirs[i].getName());
+
+            if (target == null) {
+                Target newtarget = addPackage(subDirs[i].getName());
+                findSpaceForVertex(newtarget);
+            }
+        }
+
+        Set<String> interestingSet = findTargets(getPath());
+
+        for (Iterator<String> it = interestingSet.iterator(); it.hasNext();) {
+            String targetName = it.next();
+
+            Target target = targets.get(targetName);
+
+            if (target == null) {
+                Target newtarget = addClass(targetName);
+                findSpaceForVertex(newtarget);
+            }
+        }
+
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target target = (Target) it.next();
+
+            if (target instanceof ClassTarget) {
+                ClassTarget ct = (ClassTarget) target;
+                ct.analyseSource();
+            }
+        }
+        
+        //Update class roles, and their state
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target target = (Target) it.next();
+
+            if (target instanceof ClassTarget) {
+                ClassTarget ct = (ClassTarget) target;
+
+                Class<?> cl = loadClass(ct.getQualifiedName());
+                if (cl != null) {
+                    ct.determineRole(cl);
+                    if (ct.upToDate()) {
+                        ct.setState(ClassTarget.S_NORMAL);
+                    }
+                    else {
+                        ct.setState(ClassTarget.S_INVALID);
+                    }
+                }
+            }
+        }
+
+        graphChanged();
+    }
+    
+    /**
+     * ReRead the pkg file and update the position of the targets in the graph
+     * @throws IOException
+     *
+     */
+    public void reReadGraphLayout() throws IOException
+    {
+        // try to load the package file for this package
+        SortedProperties props = new SortedProperties();
+        packageFile.load(props);
+
+        int numTargets = 0;
+
+        try {
+            numTargets = Integer.parseInt(props.getProperty("package.numTargets", "0"));
+        }
+        catch (Exception e) {
+            Debug.reportError("Error loading from bluej package file " + packageFile + ": " + e);
+            e.printStackTrace();
+            return;
+        }
+        
+        for (int i = 0; i < numTargets; i++) {
+            Target target = null;
+            String identifierName = props.getProperty("target" + (i + 1) + ".name");
+            int x = Integer.parseInt(props.getProperty("target" + (i + 1) + ".x"));
+            int y = Integer.parseInt(props.getProperty("target" + (i + 1) + ".y"));
+            int height = Integer.parseInt(props.getProperty("target" + (i + 1) + ".height"));
+            int width = Integer.parseInt(props.getProperty("target" + (i + 1) + ".width"));
+            target = getTarget(identifierName);
+            if (target != null){
+                target.setPos(x, y);
+                target.setSize(width, height);
+            }
+        }
+        repaint();
+    }
+
+    /**
+     * Save this package to disk. The package is saved to the standard package
+     * file.
+     */
+    public void save(Properties frameProperties)
+    {
+        /* create the directory if it doesn't exist */
+        File dir = getPath();
+        if (!dir.exists()) {
+            if (!dir.mkdir()) {
+                Debug.reportError("Error creating directory " + dir);
+                return;
+            }
+        }
+
+        SortedProperties props = new SortedProperties();
+        props.putAll(frameProperties);
+
+        // save targets and dependencies in package
+        props.put("package.numDependencies", String.valueOf(usesArrows.size()));
+
+        int t_count = 0;
+
+        Iterator<Target> t_enum = targets.iterator();
+        while (t_enum.hasNext()) {
+            Target t = t_enum.next();
+            // should we save this target
+            if (t.isSaveable()) {
+                t.save(props, "target" + (t_count + 1));
+                t_count++;
+            }
+        }
+        props.put("package.numTargets", String.valueOf(t_count));
+
+        //Take special care of ReadmeTarget
+        //see ReadmeTarget.isSaveable for explanation
+        Target t = getTarget(ReadmeTarget.README_ID);
+        t.save(props, "readme");
+
+        for (int i = 0; i < usesArrows.size(); i++) { // uses arrows
+            Dependency d = (Dependency) usesArrows.get(i);
+            d.save(props, "dependency" + (i + 1));
+        }
+
+        try {
+            packageFile.save(props);
+        }
+        catch (IOException e) {
+            Debug.reportError("Exception when saving package file : " + e);
+            return;
+        }
+        lastSavedProps = props;
+
+        return;
+    }
+
+    /**
+     * Import a source file into this package as a new class target. Returns an
+     * error code: NO_ERROR - everything is fine FILE_NOT_FOUND - file does not
+     * exist ILLEGAL_FORMAT - the file name does not end in ".java" CLASS_EXISTS -
+     * a class with this name already exists COPY_ERROR - could not copy
+     */
+    public int importFile(File aFile)
+    {
+        // check whether specified class exists and is a java file
+
+        if (!aFile.exists())
+            return FILE_NOT_FOUND;
+        String fileName = aFile.getName();
+
+        String className;
+        if (fileName.endsWith(".java")) // it's a Java source file
+            className = fileName.substring(0, fileName.length() - 5);
+        else
+            return ILLEGAL_FORMAT;
+
+        // check whether name is already used
+        if (getTarget(className) != null)
+            return CLASS_EXISTS;
+
+        // copy class source into package
+
+        File destFile = new File(getPath(), fileName);
+        try {
+            FileUtility.copyFile(aFile, destFile);
+        }
+        catch (IOException ioe) {
+            return COPY_ERROR;
+        }
+
+        ClassTarget t = addClass(className);
+
+        findSpaceForVertex(t);
+        t.analyseSource();
+        
+        return NO_ERROR;
+    }
+
+    public ClassTarget addClass(String className)
+    {
+        // create class icon (ClassTarget) for new class
+        ClassTarget target = new ClassTarget(this, className);
+        addTarget(target);
+
+        // make package line in class source match our package
+        try {
+            target.enforcePackage(getQualifiedName());
+        }
+        catch (IOException ioe) {
+            Debug.message(ioe.getLocalizedMessage());
+        }
+
+        return target;
+    }
+
+    /**
+     * Add a new package target to this package.
+     * 
+     * @param packageName The basename of the package to add
+     */
+    public PackageTarget addPackage(String packageName)
+    {
+        PackageTarget target = new PackageTarget(this, packageName);
+        addTarget(target);
+
+        return target;
+    }
+
+    public Debugger getDebugger()
+    {
+        return getProject().getDebugger();
+    }
+
+    /**
+     * Loads a class using the current project class loader.
+     * Return null if the class cannot be loaded.
+     */
+    public Class<?> loadClass(String className)
+    {
+        return getProject().loadClass(className);
+    }
+
+    public Iterator<Target> getVertices()
+    {
+        return targets.sortediterator();
+    }
+
+    public Iterator<? extends Edge> getEdges()
+    {
+        List<Iterator<? extends Edge>> iterations = new ArrayList<Iterator<? extends Edge>>();
+
+        if (showUses)
+            iterations.add(usesArrows.iterator());
+        if (showExtends)
+            iterations.add(extendsArrows.iterator());
+
+        return new MultiIterator<Edge>(iterations);
+    }
+
+    /**
+     * Return a List of all ClassTargets that have the role of a unit test.
+     */
+    public List<ClassTarget> getTestTargets()
+    {
+        List<ClassTarget> l = new ArrayList<ClassTarget>();
+
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target target = it.next();
+
+            if (target instanceof ClassTarget) {
+                ClassTarget ct = (ClassTarget) target;
+
+                if (ct.isUnitTest())
+                    l.add(ct);
+            }
+        }
+
+        return l;
+    }
+
+    /**
+     * The standard compile user function: Find and compile all uncompiled
+     * classes.
+     */
+    public void compile()
+    {
+        if (!checkCompile()) {
+            return;
+        }
+
+        Set<ClassTarget> toCompile = new HashSet<ClassTarget>();
+
+        try {
+            // build the list of targets that need to be compiled
+            for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+                Target target = it.next();
+
+                if (target instanceof ClassTarget) {
+                    ClassTarget ct = (ClassTarget) target;
+                    if (ct.isInvalidState() && ! ct.isQueued()) {
+                        ct.ensureSaved();
+                        toCompile.add(ct);
+                        ct.setQueued(true);
+                    }
+                }
+            }
+
+            project.removeClassLoader();
+            project.newRemoteClassLoaderLeavingBreakpoints();
+            doCompile(toCompile, new PackageCompileObserver());
+        }
+        catch (IOException ioe) {
+            // Abort compile
+            Debug.log("Error saving class before compile: " + ioe.getLocalizedMessage());
+            for (ClassTarget ct : toCompile) {
+                ct.setQueued(false);
+            }
+        }
+    }
+    
+    /**
+     * Compile a single class.
+     */
+    public void compile(ClassTarget ct)
+    {
+        compile(ct, false);
+    }
+    
+    /**
+     * Compile a single class.
+     */
+    public void compile(ClassTarget ct, boolean forceQuiet)
+    {
+        if (!checkCompile()) {
+            return;
+        }
+
+        ClassTarget assocTarget = (ClassTarget) ct.getAssociation();
+        if (assocTarget != null && ! assocTarget.hasSourceCode()) {
+            assocTarget = null;
+        }
+
+        // we don't want to try and compile if it is a class target without src
+        // it may be better to avoid calling this method on such targets
+        if (ct.hasSourceCode()) {
+            ct.setInvalidState(); // to force compile
+        }
+        else {
+            ct = null;
+        }
+
+        if (assocTarget != null) {
+            assocTarget.setInvalidState();
+        }
+
+        if (ct != null || assocTarget != null) {
+            project.removeClassLoader();
+            project.newRemoteClassLoaderLeavingBreakpoints();
+
+            // Clear-down the compiler Warning dialog box singleton
+            bluej.compiler.CompilerWarningDialog.getDialog().reset();
+
+            if (ct != null) {
+                CompileObserver observer;
+                if (forceQuiet) {
+                    observer = new QuietPackageCompileObserver();
+                } else {
+                    observer = new PackageCompileObserver();
+                }
+                searchCompile(ct, observer);
+            }
+
+            if (assocTarget != null) {
+                searchCompile(assocTarget, new QuietPackageCompileObserver());
+            }
+        }
+    }
+
+    /**
+     * Compile a single class quietly.
+     */
+    public void compileQuiet(ClassTarget ct)
+    {
+        if (!isDebuggerIdle()) {
+            return;
+        }
+
+        ct.setInvalidState(); // to force compile
+        searchCompile(ct, new QuietPackageCompileObserver());
+    }
+
+    /**
+     * Force compile of all classes. Called by user function "rebuild".
+     */
+    public void rebuild()
+    {
+        if (!checkCompile()) {
+            return;
+        }
+
+        // Saving a class target can change its name; we need to copy the set of targets
+        // first, and iterate through the copied list, to avoid "concurrent" modification
+        // problems.
+        List<ClassTarget> compileTargets = new ArrayList<ClassTarget>();
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target target = it.next();
+            if (target instanceof ClassTarget) {
+                compileTargets.add((ClassTarget) target);
+            }
+        }
+
+        try {
+            for (Iterator<ClassTarget> i = compileTargets.iterator(); i.hasNext(); ) {
+                ClassTarget ct = i.next();
+                // we don't want to try and compile if it is a class target without src
+                if (ct.hasSourceCode()) {
+                    ct.ensureSaved();
+                    ct.setState(ClassTarget.S_INVALID);
+                    ct.setQueued(true);
+                }
+                else {
+                    i.remove();
+                }
+            }
+            project.removeClassLoader();
+            project.newRemoteClassLoader();
+            
+            // Clear-down the compiler Warning dialog box singleton
+            bluej.compiler.CompilerWarningDialog.getDialog().reset();
+
+            doCompile(compileTargets, new PackageCompileObserver());
+        }
+        catch (IOException ioe) {
+            showMessageWithText("file-save-error-before-compile", ioe.getLocalizedMessage());
+        }
+    }
+
+    /**
+     * Have all editors in this package save the file the are showing.
+     * Called when doing a cvs operation
+     */
+    public void saveFilesInEditors() throws IOException
+    {
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target target = it.next();
+            if (target instanceof ClassTarget) {
+                ClassTarget ct = (ClassTarget) target;
+                Editor ed = ct.getEditor();
+                // Editor can be null eg. class file and no src file
+                if(ed != null)
+                    ed.save();
+            }
+        }
+    }
+    
+    /**
+     * Compile a class together with its dependencies, as necessary.
+     */
+    private void searchCompile(ClassTarget t, CompileObserver observer)
+    {
+        if (! t.isInvalidState() || t.isQueued()) {
+            return;
+        }
+
+        Set<ClassTarget> toCompile = new HashSet<ClassTarget>();
+        
+        try {
+            List<ClassTarget> queue = new LinkedList<ClassTarget>();
+            toCompile.add(t);
+            t.ensureSaved();
+            queue.add(t);
+            t.setQueued(true);
+
+            while (! queue.isEmpty()) {
+                ClassTarget head = queue.remove(0);
+
+                Iterator<? extends Dependency> dependencies = head.dependencies();
+
+                while (dependencies.hasNext()) {
+                    Dependency d = (Dependency) dependencies.next();
+                    if (!(d.getTo() instanceof ClassTarget)) {
+                        continue;
+                    }
+
+                    ClassTarget to = (ClassTarget) d.getTo();
+                    if (to.isInvalidState() && ! to.isQueued() && toCompile.add(to)) {
+                        to.ensureSaved();
+                        to.setQueued(true);
+                        queue.add(to);
+                    }
+                }
+            }
+
+            doCompile(toCompile, observer);
+        }
+        catch (IOException ioe) {
+            // Failed to save; abort the compile
+            Debug.log("Failed to save source before compile; " + ioe.getLocalizedMessage());
+            for (ClassTarget ct : toCompile) {
+                ct.setQueued(false);
+            }
+        }
+    }
+
+    /**
+     * Compile every Target in 'targetList'. Every compilation goes through this method.
+     * All targets in the list should have been saved beforehand.
+     */
+    private void doCompile(Collection<ClassTarget> targetList, CompileObserver observer)
+    {
+        observer = new EventqueueCompileObserver(observer);
+        if (targetList.isEmpty()) {
+            return;
+        }
+
+        File[] srcFiles = new File[targetList.size()];
+        
+        int i = 0;
+        for (ClassTarget ct : targetList) {
+            srcFiles[i++] = ct.getSourceFile();
+        }
+        
+        JobQueue.getJobQueue().addJob(srcFiles, observer, project.getClassLoader(), project.getProjectDir(),
+                ! PrefMgr.getFlag(PrefMgr.SHOW_UNCHECKED), project.getProjectCharset());
+    }
+
+    /**
+     * Returns true if the debugger is not busy. This is true if it is either
+     * IDLE, or has not been completely constructed (NOTREADY).
+     */
+    public boolean isDebuggerIdle()
+    {
+        int status = getDebugger().getStatus();
+        return (status == Debugger.IDLE) || (status == Debugger.NOTREADY);
+    }
+
+    /**
+     * Check whether it's okay to compile and display a message about it.
+     */
+    private boolean checkCompile()
+    {
+        if (isDebuggerIdle())
+            return true;
+
+        // The debugger is NOT idle, show a message about it.
+        showMessage("compile-while-executing");
+        return false;
+    }
+
+    /**
+     * Generate documentation for this package.
+     * 
+     * @return "" if everything was alright, an error message otherwise.
+     */
+    public String generateDocumentation()
+    {
+        // This implementation currently just delegates the generation to
+        // the project this package is part of.
+        return project.generateDocumentation();
+    }
+
+    /**
+     * Generate documentation for class in this ClassTarget.
+     * 
+     * @param ct
+     *            the class to generate docs for
+     */
+    public void generateDocumentation(ClassTarget ct)
+    {
+        // editor file is already saved: no need to save it here
+        String filename = ct.getSourceFile().getPath();
+        project.generateDocumentation(filename);
+    }
+
+    /**
+     * Re-initialize breakpoints, necessary after a new class loader is
+     * installed.
+     */
+    public void reInitBreakpoints()
+    {
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target target = it.next();
+
+            if (target instanceof ClassTarget) {
+                ((ClassTarget) target).reInitBreakpoints();
+            }
+        }
+    }
+
+    /**
+     * Remove all step marks in all classes.
+     */
+    public void removeStepMarks()
+    {
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target target = (Target) it.next();
+
+            if (target instanceof ClassTarget)
+                ((ClassTarget) target).removeStepMark();
+        }
+    }
+
+    public void addTarget(Target t)
+    {
+        if (t.getPackage() != this)
+            throw new IllegalArgumentException();
+
+        targets.add(t.getIdentifierName(), t);
+        graphChanged();
+    }
+
+    public void removeTarget(Target t)
+    {
+        targets.remove(t.getIdentifierName());
+        removedSelectableElement(t);
+        t.setRemoved();
+        graphChanged();
+    }
+
+    /**
+     * Changes the Target identifier. Targets are stored in a hashtable with
+     * their name as the key. If class name changes we need to remove the target
+     * and add again with the new key.
+     */
+    public void updateTargetIdentifier(Target t, String oldIdentifier, String newIdentifier)
+    {
+        if (t == null || newIdentifier == null) {
+            Debug.reportError("cannot properly update target name...");
+            return;
+        }
+        targets.remove(oldIdentifier);
+        targets.add(newIdentifier, t);
+    }
+
+    /**
+     * remove the arrow representing the given dependency
+     * 
+     * @param d  the dependency to remove
+     */
+    public void removeArrow(Dependency d)
+    {
+        if (!(d instanceof UsesDependency)) {
+            userRemoveDependency(d);
+        }
+        removeDependency(d, true);
+        graphChanged();
+    }
+
+    /**
+     * Add a dependancy in this package. The dependency is also added to the
+     * individual targets involved.
+     */
+    public void addDependency(Dependency d, boolean recalc)
+    {
+        DependentTarget from = d.getFrom();
+        DependentTarget to = d.getTo();
+
+        if (from == null || to == null) {
+            // Debug.reportError("Found invalid dependency - ignored.");
+            return;
+        }
+
+        if (d instanceof UsesDependency) {
+            int index = usesArrows.indexOf(d);
+            if (index != -1) {
+                ((UsesDependency) usesArrows.get(index)).setFlag(true);
+                return;
+            }
+            else
+                usesArrows.add(d);
+        }
+        else {
+            if (extendsArrows.contains(d))
+                return;
+            else
+                extendsArrows.add(d);
+        }
+
+        from.addDependencyOut(d, recalc);
+        to.addDependencyIn(d, recalc);
+
+        // Inform all listeners about the added dependency
+        DependencyEvent event = new DependencyEvent(d, this, DependencyEvent.Type.DEPENDENCY_ADDED);
+        ExtensionsManager.getInstance().delegateEvent(event);
+    }
+
+    /**
+     * A user initiated addition of an "implements" clause from a class to
+     * an interface
+     *
+     * @pre d.getFrom() and d.getTo() are both instances of ClassTarget
+     */
+    public void userAddImplementsClassDependency(Dependency d)
+    {
+        ClassTarget from = (ClassTarget) d.getFrom(); // a class
+        ClassTarget to = (ClassTarget) d.getTo(); // an interface
+        Editor ed = from.getEditor();
+        try {
+            ed.save();
+            
+            ClassInfo info = from.getSourceInfo().getInfo(from.getSourceFile(), this);
+            if (info != null) {
+                
+                Selection s1 = info.getImplementsInsertSelection();
+                ed.setSelection(s1.getLine(), s1.getColumn(), s1.getEndLine(), s1.getEndColumn());
+                
+                if (info.hasInterfaceSelections()) {
+                    // if we already have an implements clause then we need to put a
+                    // comma and the interface name but not before checking that we
+                    // don't already have it
+                    
+                    List<String> exists = getInterfaceTexts(ed, info.getInterfaceSelections());
+                    
+                    // XXX make this equality check against full package name
+                    if (!exists.contains(to.getBaseName()))
+                        ed.insertText(", " + to.getBaseName(), false);
+                }
+                else {
+                    // otherwise we need to put the actual "implements" word
+                    // and the interface name
+                    ed.insertText(" implements " + to.getBaseName(), false);
+                }
+                ed.save();
+            }
+        }
+        catch (IOException ioe) {
+            showMessageWithText("generic-file-save-error", ioe.getLocalizedMessage());
+        }
+    }
+
+    /**
+     * A user initiated addition of an "extends" clause from an interface to
+     * an interface
+     *
+     * @pre d.getFrom() and d.getTo() are both instances of ClassTarget
+     */
+    public void userAddImplementsInterfaceDependency(Dependency d)
+    {
+        ClassTarget from = (ClassTarget) d.getFrom(); // an interface
+        ClassTarget to = (ClassTarget) d.getTo(); // an interface
+        Editor ed = from.getEditor();
+        try {
+            ed.save();
+
+            ClassInfo info = from.getSourceInfo().getInfo(from.getSourceFile(), this);
+
+            if (info != null) {
+                Selection s1 = info.getExtendsInsertSelection();
+                ed.setSelection(s1.getLine(), s1.getColumn(), s1.getEndLine(), s1.getEndColumn());
+                
+                if (info.hasInterfaceSelections()) {
+                    // if we already have an extends clause then we need to put a
+                    // comma and the interface name but not before checking that we
+                    // don't
+                    // already have it
+                    
+                    List<String> exists = getInterfaceTexts(ed, info.getInterfaceSelections());
+                    
+                    // XXX make this equality check against full package name
+                    if (!exists.contains(to.getBaseName()))
+                        ed.insertText(", " + to.getBaseName(), false);
+                }
+                else {
+                    // otherwise we need to put the actual "extends" word
+                    // and the interface name
+                    ed.insertText(" extends " + to.getBaseName(), false);
+                }
+                ed.save();
+            }
+        }
+        catch (IOException ioe) {
+            showMessageWithText("generic-file-save-error", ioe.getLocalizedMessage());
+        }
+    }
+
+    /**
+     * A user initiated addition of an "extends" clause from a class to
+     * a class
+     *
+     * @pre d.getFrom() and d.getTo() are both instances of ClassTarget
+     */
+    public void userAddExtendsClassDependency(Dependency d)
+    {
+        ClassTarget from = (ClassTarget) d.getFrom();
+        ClassTarget to = (ClassTarget) d.getTo();
+        Editor ed = from.getEditor();
+        try {
+            ed.save();
+
+            ClassInfo info = from.getSourceInfo().getInfo(from.getSourceFile(), this);
+
+            if (info != null) {
+                if (info.getSuperclass() == null) {
+                    Selection s1 = info.getExtendsInsertSelection();
+                    
+                    ed.setSelection(s1.getLine(), s1.getColumn(), s1.getEndLine(), s1.getEndColumn());
+                    ed.insertText(" extends " + to.getBaseName(), false);
+                }
+                else {
+                    Selection s1 = info.getSuperReplaceSelection();
+                    
+                    ed.setSelection(s1.getLine(), s1.getColumn(), s1.getEndLine(), s1.getEndColumn());
+                    ed.insertText(to.getBaseName(), false);
+                }
+                ed.save();
+            }
+        }
+        catch (IOException ioe) {
+            showMessageWithText("generic-file-save-error", ioe.getLocalizedMessage());
+        }
+    }
+
+    /**
+     * A user initiated removal of a dependency
+     *
+     * @param d  an instance of an Implements or Extends dependency
+     */
+    public void userRemoveDependency(Dependency d)
+    {
+        // if they are not both classtargets then I don't want to know about it
+        if (!(d.getFrom() instanceof ClassTarget) || !(d.getTo() instanceof ClassTarget))
+            return;
+
+        ClassTarget from = (ClassTarget) d.getFrom();
+        ClassTarget to = (ClassTarget) d.getTo();
+        Editor ed = from.getEditor();
+        try {
+            ed.save();
+
+            ClassInfo info = from.getSourceInfo().getInfo(from.getSourceFile(), this);
+            if (info != null) {
+                Selection s1 = null;
+                
+                if (d instanceof ImplementsDependency) {
+                    List<Selection> vsels;
+                    List<String> vtexts;
+                    
+                    vsels = info.getInterfaceSelections();
+                    vtexts = getInterfaceTexts(ed, vsels);
+                    int where = vtexts.indexOf(to.getBaseName());
+                    
+                    // we have a special case if we deleted the first bit of an
+                    // "implements" clause, yet there are still clauses left.. we have
+                    // to delete the following "," instead of the preceding one.
+                    if (where == 1 && vsels.size() > 2)
+                        where = 2;
+                    
+                    if (where > 0) { // should always be true
+                        s1 = (Selection) vsels.get(where - 1);
+                        s1.combineWith((Selection) vsels.get(where));
+                    }
+                }
+                else if (d instanceof ExtendsDependency) {
+                    // a class extends
+                    s1 = info.getExtendsReplaceSelection();
+                    s1.combineWith(info.getSuperReplaceSelection());
+                }
+                
+                // delete the text from the end backwards so that our
+                if (s1 != null) {
+                    ed.setSelection(s1.getLine(), s1.getColumn(), s1.getEndLine(), s1.getEndColumn());
+                    ed.insertText("", false);
+                }
+                
+                ed.save();
+            }
+        }
+        catch (IOException ioe) {
+            showMessageWithText("generic-file-save-error", ioe.getLocalizedMessage());
+        }
+    }
+    
+    /**
+     * Using a list of selections, retrieve a list of text strings from the editor which
+     * correspond to those selections.
+     * TODO this is usually used to get the implemented interfaces, but it is a clumsy way
+     *      to do that.
+     */
+    private List<String> getInterfaceTexts(Editor ed, List<Selection> selections)
+    {
+        List<String> r = new ArrayList<String>(selections.size());
+        Iterator<Selection> i = selections.iterator();
+        while (i.hasNext()) {
+            Selection sel = i.next();
+            String text = ed.getText(new bluej.parser.SourceLocation(sel.getLine(), sel.getColumn()),
+                    new bluej.parser.SourceLocation(sel.getEndLine(), sel.getEndColumn()));
+            
+            // check for type arguments: don't include them in the text
+            int taIndex = text.indexOf('<');
+            if (taIndex != -1)
+                text = text.substring(0, taIndex);
+            text = text.trim();
+            
+            r.add(text);
+        }
+        return r;
+    }
+
+    /**
+     * Remove a dependency from this package. The dependency is also removed
+     * from the individual targets involved.
+     */
+    public void removeDependency(Dependency d, boolean recalc)
+    {
+        if (d instanceof UsesDependency)
+            usesArrows.remove(d);
+        else
+            extendsArrows.remove(d);
+
+        DependentTarget from = d.getFrom();
+        from.removeDependencyOut(d, recalc);
+
+        DependentTarget to = d.getTo();
+        to.removeDependencyIn(d, recalc);
+
+        removedSelectableElement(d);
+
+        // Inform all listeners about the removed dependency
+        DependencyEvent event = new DependencyEvent(d, this, DependencyEvent.Type.DEPENDENCY_REMOVED);
+        ExtensionsManager.getInstance().delegateEvent(event);
+    }
+
+    /**
+     * Lay out the arrows between targets.
+     */
+    private void recalcArrows()
+    {
+        Iterator<Target> it = getVertices();
+        while (it.hasNext()) {
+            Target t = it.next();
+
+            if (t instanceof DependentTarget) {
+                DependentTarget dt = (DependentTarget) t;
+
+                dt.recalcInUses();
+                dt.recalcOutUses();
+            }
+        }
+    }
+
+    /**
+     * Return the target with name "identifierName".
+     * 
+     * @param identifierName
+     *            the unique name of a target.
+     * @return the target with name "tname" if existent, null otherwise.
+     */
+    public Target getTarget(String identifierName)
+    {
+        if (identifierName == null)
+            return null;
+        Target t = targets.get(identifierName);
+        return t;
+    }
+
+    /**
+     * Return the dependent target with name "identifierName".
+     * 
+     * @param identifierName
+     *            the unique name of a target.
+     * @return the target with name "tname" if existent and if it is a
+     *         DependentTarget, null otherwise.
+     */
+    public DependentTarget getDependentTarget(String identifierName)
+    {
+        if (identifierName == null)
+            return null;
+        Target t = targets.get(identifierName);
+
+        if (t instanceof DependentTarget)
+            return (DependentTarget) t;
+
+        return null;
+    }
+
+    
+    /**
+     * Returns an ArrayList of ClassTargets holding all targets of this package.
+     * @return a not null but possibly empty array list of ClassTargets for this package.
+     */
+    public final ArrayList<ClassTarget> getClassTargets()
+    {
+        ArrayList<ClassTarget> risul = new ArrayList<ClassTarget>();
+
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target target = (Target) it.next();
+
+            if (target instanceof ClassTarget) {
+                risul.add((ClassTarget) target);
+            }
+        }
+        return risul;
+    }
+
+    /**
+     * Return a List of Strings with names of all classes in this package.
+     */
+    public List<String> getAllClassnames()
+    {
+        List<String> names = new ArrayList<String>();
+        
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target t = it.next();
+
+            if (t instanceof ClassTarget) {
+                ClassTarget ct = (ClassTarget) t;
+                names.add(ct.getBaseName());
+            }
+        }
+        return names;
+    }
+
+    /**
+     * Return a List of Strings with names of all classes in this package that
+     * has accompanying source.
+     */
+    public List<String> getAllClassnamesWithSource()
+    {
+        List<String> names = new ArrayList<String>();
+
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target t = it.next();
+
+            if (t instanceof ClassTarget) {
+                ClassTarget ct = (ClassTarget) t;
+                if (ct.hasSourceCode())
+                    names.add(ct.getBaseName());
+            }
+        }
+        return names;
+    }
+
+    /**
+     * Given a file name, find the target that represents that file.
+     * 
+     * @return The target with the given file name or <null>if not found.
+     */
+    public ClassTarget getTargetFromFilename(String filename)
+    {
+        getProject().convertPathToPackageName(filename);
+
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target t = it.next();
+            if (!(t instanceof ClassTarget)) {
+                continue;
+            }
+
+            ClassTarget ct = (ClassTarget) t;
+
+            if (filename.equals(ct.getSourceFile().getPath())) {
+                return ct;
+            }
+        }
+
+        return null;
+    }
+
+    public void setShowUses(boolean state)
+    {
+        showUses = state;
+    }
+
+    public void setShowExtends(boolean state)
+    {
+        showExtends = state;
+    }
+
+    public void setState(int state)
+    {
+        this.state = state;
+    }
+
+    public int getState()
+    {
+        return state;
+    }
+
+    /**
+     * Test whether a file instance denotes a BlueJ or Greenfoot package directory depending on which mode we are in.
+     * 
+     * @param f
+     *            the file instance that is tested for denoting a BlueJ package.
+     * @return true if f denotes a directory and a BlueJ package.
+     */
+    public static boolean isPackage(File f)
+    {
+        if(Config.isGreenfoot())
+            return GreenfootProjectFile.exists(f);
+        else 
+            return BlueJPackageFile.exists(f);
+    }
+    
+    /**
+     * Test whether this name is the name of a package file.
+     */
+    public static boolean isPackageFileName(String name)
+    {
+        if(Config.isGreenfoot())
+            return GreenfootProjectFile.isProjectFileName(name);
+        else 
+            return BlueJPackageFile.isPackageFileName(name);
+    }
+
+    /**
+     * Called when in an interesting state (e.g. adding a new dependency) and a
+     * target is selected. Calling with 'null' as parameter resets to idle state.
+     */
+    public void targetSelected(Target t)
+    {
+        if(t == null) {
+            if(getState() != S_IDLE) {
+                setState(S_IDLE);
+                setStatus(" ");
+            }
+            return;
+        }
+
+        switch(getState()) {
+            case S_CHOOSE_USES_FROM :
+                if (t instanceof DependentTarget) {
+                    fromChoice = (DependentTarget) t;
+                    setState(S_CHOOSE_USES_TO);
+                    setStatus(chooseUsesTo);
+                }
+                else {
+                    setState(S_IDLE);
+                    setStatus(" ");
+                }
+                break;
+
+            case S_CHOOSE_USES_TO :
+                if (t != fromChoice && t instanceof DependentTarget) {
+                    setState(S_IDLE);
+                    addDependency(new UsesDependency(this, fromChoice, (DependentTarget) t), true);
+                    setStatus(" ");
+                }
+                break;
+
+            case S_CHOOSE_EXT_FROM :
+
+                if (t instanceof DependentTarget) {
+                    fromChoice = (DependentTarget) t;
+                    setState(S_CHOOSE_EXT_TO);
+                    setStatus(chooseInhTo);
+                }
+                else {
+                    setState(S_IDLE);
+                    setStatus(" ");
+                }
+                break;
+
+            case S_CHOOSE_EXT_TO :
+                if (t != fromChoice) {
+                    setState(S_IDLE);
+                    if (t instanceof ClassTarget && fromChoice instanceof ClassTarget) {
+
+                        ClassTarget from = (ClassTarget) fromChoice;
+                        ClassTarget to = (ClassTarget) t;
+
+                        // if the target is an interface then we have an
+                        // implements dependency
+                        if (to.isInterface()) {
+                            Dependency d = new ImplementsDependency(this, from, to);
+
+                            if (from.isInterface()) {
+                                userAddImplementsInterfaceDependency(d);
+                            }
+                            else {
+                                userAddImplementsClassDependency(d);
+                            }
+
+                            addDependency(d, true);
+                        }
+                        else {
+                            // an extends dependency can only be from a class to
+                            // another class
+                            if (!from.isInterface() && !to.isEnum() && !from.isEnum()) {
+                                Dependency d = new ExtendsDependency(this, from, to);
+                                userAddExtendsClassDependency(d);
+                                addDependency(d, true);
+                            }
+                            else {
+                                // TODO display an error dialog or status
+                            }
+                        }
+                    }
+                    setStatus(" ");
+                }
+                break;
+
+            default :
+                // e.g. deleting arrow - selecting target ignored
+                break;
+        }
+    }
+
+    /**
+     * Use the dialog manager to display an error message. The PkgMgrFrame is
+     * used to find a parent window so we can correctly offset the dialog.
+     */
+    public void showError(String msgId)
+    {
+        PkgMgrFrame.showError(this, msgId);
+    }
+
+    /**
+     * Use the dialog manager to display a message. The PkgMgrFrame is used to
+     * find a parent window so we can correctly offset the dialog.
+     */
+    public void showMessage(String msgId)
+    {
+        PkgMgrFrame.showMessage(this, msgId);
+    }
+
+    /**
+     * Use the dialog manager to display a message with text. The PkgMgrFrame is
+     * used to find a parent window so we can correctly offset the dialog.
+     */
+    public void showMessageWithText(String msgId, String text)
+    {
+        PkgMgrFrame.showMessageWithText(this, msgId, text);
+    }
+
+    /**
+     * Don't remember the last shown source anymore.
+     */
+    public void forgetLastSource()
+    {
+        lastSourceName = "";
+    }
+
+    /**
+     * A thread has hit a breakpoint or done a step. Organise display (highlight
+     * line in source, pop up exec controls).
+     */
+    public boolean showSource(String sourcename, int lineNo, String threadName, boolean breakpoint)
+    {
+        String msg = " ";
+
+        if (breakpoint)
+            msg = "Thread \"" + threadName + "\" stopped at breakpoint.";
+
+        boolean bringToFront = !sourcename.equals(lastSourceName);
+        lastSourceName = sourcename;
+
+        if (!showEditorMessage(new File(getPath(), sourcename).getPath(), lineNo, msg, false, bringToFront,
+                true, null) && !breakpoint) {
+            showMessageWithText("break-no-source", sourcename);
+        }
+
+        return bringToFront;
+    }
+    
+    public static interface MessageCalculator
+    {
+        // This should produce something half-way helpful if null is passed:
+        public String calculateMessage(Editor e);
+    }
+    
+    /**
+     * Display an error message associated with a specific line in a class. This
+     * is done by opening the class's source, highlighting the line and showing
+     * the message in the editor's information area.
+     */
+    private boolean showEditorMessage(String filename, int lineNo, final String message, boolean beep,
+            boolean bringToFront, boolean setStepMark, String help)
+    {
+        return showEditorMessage(filename, lineNo, new MessageCalculator() {
+            public String calculateMessage(Editor e) { return message; }
+          }, beep, bringToFront, setStepMark, help);
+    }
+
+    /**
+     * Display an enhanced error message associated with a specific line in a
+     * class. This is done by opening the class's source, highlighting the line
+     * and showing the message in the editor's information area.
+     */
+    private boolean showEditorMessage(String filename, int lineNo, MessageCalculator messageCalc, boolean beep,
+            boolean bringToFront, boolean setStepMark, String help)
+    {
+        String fullName = getProject().convertPathToPackageName(filename);
+        if (fullName == null) {
+            return false;
+        }
+        
+        String packageName = JavaNames.getPrefix(fullName);
+        String className = JavaNames.getBase(fullName);
+
+        ClassTarget t = null;
+
+        // check if the error is from a file belonging to another package
+        if (packageName != getQualifiedName()) {
+
+            Package pkg = getProject().getPackage(packageName);
+            
+            if (pkg != null) {
+                PkgMgrFrame pmf = PkgMgrFrame.findFrame(pkg);
+
+                if ((pmf = PkgMgrFrame.findFrame(pkg)) == null) {
+                    pmf = PkgMgrFrame.createFrame(pkg);
+                }
+
+                pmf.setVisible(true);
+
+                t = (ClassTarget) pkg.getTarget(className);
+            }
+        }
+        else {
+            t = (ClassTarget) getTarget(className);
+        }
+
+        if (t == null) {
+            return false;
+        }
+
+        Editor editor = t.getEditor();
+        if (editor != null) {
+            if (bringToFront || !editor.isShowing()) {
+                t.open();
+            }
+            editor.displayMessage(messageCalc.calculateMessage(editor), lineNo, 0, beep, setStepMark, help);
+        }
+        else {
+            Debug.message(t.getDisplayName() + ", line" + lineNo + ": " + messageCalc.calculateMessage(null));
+        }
+        return true;
+    }
+    
+    /**
+     * Display a compiler diagnostic (error or warning) in the appropriate editor window.
+     * 
+     * @param diagnostic   The diagnostic to display
+     * @param messageCalc  The message "calculator", which returns a modified version of the message;
+     *                     may be null, in which case the original message is shown unmodified.
+     */
+    private boolean showEditorDiagnostic(Diagnostic diagnostic, MessageCalculator messageCalc)
+    {
+        String fileName = diagnostic.getFileName();
+        if (fileName == null) {
+            return false;
+        }
+        
+        String fullName = getProject().convertPathToPackageName(diagnostic.getFileName());
+        if (fullName == null) {
+            return false;
+        }
+        
+        String packageName = JavaNames.getPrefix(fullName);
+        String className = JavaNames.getBase(fullName);
+
+        ClassTarget t = null;
+
+        // check if the error is from a file belonging to another package
+        if (packageName != getQualifiedName()) {
+
+            Package pkg = getProject().getPackage(packageName);
+            
+            if (pkg != null) {
+                PkgMgrFrame pmf = PkgMgrFrame.findFrame(pkg);
+
+                if ((pmf = PkgMgrFrame.findFrame(pkg)) == null) {
+                    pmf = PkgMgrFrame.createFrame(pkg);
+                }
+
+                pmf.setVisible(true);
+
+                t = (ClassTarget) pkg.getTarget(className);
+            }
+        }
+        else {
+            t = (ClassTarget) getTarget(className);
+        }
+
+        if (t == null) {
+            return false;
+        }
+
+        Editor editor = t.getEditor();
+        if (editor != null) {
+            editor.setVisible(true);
+            if (messageCalc != null) {
+                diagnostic.setMessage(messageCalc.calculateMessage(editor));
+            }
+            editor.displayDiagnostic(diagnostic);
+        }
+        else {
+            Debug.message(t.getDisplayName() + ", line" + diagnostic.getStartLine() +
+                    ": " + diagnostic.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * A breakpoint in this package was hit.
+     */
+    public void hitBreakpoint(DebuggerThread thread)
+    {
+        showSource(thread.getClassSourceName(0), thread.getLineNumber(0), thread.getName(), true);
+
+        getProject().getExecControls().showHide(true);
+        getProject().getExecControls().makeSureThreadIsSelected(thread);
+    }
+
+    /**
+     * Execution stopped by someone pressing the "halt" button or we have just
+     * done a "step".
+     */
+    public void hitHalt(DebuggerThread thread)
+    {
+        showSourcePosition(thread);
+
+        getProject().getExecControls().showHide(true);
+        getProject().getExecControls().makeSureThreadIsSelected(thread);
+    }
+
+    /**
+     * showSourcePosition - The debugger display needs updating.
+     */
+    public void showSourcePosition(DebuggerThread thread)
+    {
+        int frame = thread.getSelectedFrame();
+        if (showSource(thread.getClassSourceName(frame), thread.getLineNumber(frame), thread.getName(), false)) {
+            getProject().getExecControls().setVisible(true);
+            //getProject().getExecControls().makeSureThreadIsSelected(thread);
+        }
+    }
+
+    /**
+     * Display an exception message. This is almost the same as "errorMessage"
+     * except for different help texts.
+     */
+    public void exceptionMessage(ExceptionDescription exception)
+    {
+        String text = exception.getClassName();
+        if (text == null) {
+            reportException(exception.getText());
+            return;
+        }
+        
+        String message = text + ":\n" + exception.getText();
+        List<SourceLocation> stack = exception.getStack();
+        
+        if ((stack == null) || (stack.size() == 0)) {
+            // Stack empty or missing. This can happen when an exception is
+            // thrown from the code pad for instance.
+            return;
+        }
+
+        // using the stack, try to find the source code
+        boolean done = false;
+        Iterator<SourceLocation> iter = stack.iterator();
+        boolean firstTime = true;
+
+        while (!done && iter.hasNext()) {
+            SourceLocation loc = iter.next();
+            String filename = new File(getPath(), loc.getFileName()).getPath();
+            int lineNo = loc.getLineNumber();
+            done = showEditorMessage(filename, lineNo, message, true, true, false, "exception");
+            if (firstTime && !done) {
+                message += " (in " + loc.getClassName() + ")";
+                firstTime = false;
+            }
+        }
+        if (!done) {
+            SourceLocation loc = (SourceLocation) stack.get(0);
+            showMessageWithText("error-in-file", loc.getClassName() + ":" + loc.getLineNumber() + "\n" + message);
+        }
+    }
+    
+    /**
+     * Displays the given class at the given line number (due to an exception, usually clicked-on stack trace).
+     * 
+     *  Simpler than the other exceptionMessage method because it requires less details 
+     */
+    public void exceptionMessage(String className, int lineNumber)
+    {
+        showEditorMessage(className, lineNumber, "", false, true, false, "exception");
+    }
+
+    /**
+     * Report an execption. Usually, we do this through "errorMessage", but if
+     * we cannot make sense of the message format, and thus cannot figure out
+     * class name and line number, we use this way.
+     */
+    public void reportException(String text)
+    {
+        showMessageWithText("exception-thrown", text);
+    }
+
+    /**
+     * Use the resource name in order to return the classpath of the jar file.
+     * If it is not a jar file it returns the original resource
+     * @param fullName resource (full path of the resource)
+     * @return A string indicating the classpath of the jar file (if applicable
+     * and if not, it returns the original String)
+     */
+    protected static String getResourcePath(Class<?> c)
+    { 
+        URL srcUrl = c.getResource(c.getSimpleName()+".class");
+        try {
+            if (srcUrl!=null){
+                if (srcUrl.getProtocol().equals("file")) {
+                    File srcFile = new File(srcUrl.toURI());
+                    return srcFile.toString();
+                }  
+                if (srcUrl.getProtocol().equals("jar")){
+                    //it should be of this format
+                    //jar:file:/path!/class 
+                    int classIndex = srcUrl.toString().indexOf("!");
+                    String subUrl = srcUrl.toString().substring(4, classIndex);
+                    if (subUrl.startsWith("file:")) {
+                        return new File(new URI(subUrl)).toString();
+                    }
+                    
+                    if (classIndex!=-1){
+                        return srcUrl.toString().substring(4, classIndex);
+                    }
+                }
+            }
+        }
+        catch (URISyntaxException uriSE) {
+            // theoretically we can't get URISyntaxException; the URL should
+            // be valid.
+        }
+        return srcUrl.toString();
+    }
+    
+    /**
+     * Check whether a loaded class was actually loaded from the specified class file
+     * @param c  The loaded class
+     * @param f  The class file to check against (should be a compiled .class file)
+     * @return  True if the class was loaded from the specified file; false otherwise
+     */
+    public static boolean checkClassMatchesFile(Class<?> c, File f)
+    {
+        try {
+            URL srcUrl = c.getResource(c.getSimpleName()+".class");
+            if (srcUrl == null) {
+                // If we weren't able to load the class file at all, it may have been
+                // deleted; this happens when a class is added to a project, then
+                // removed, and then another class is added with the same name.
+                return true;
+            }
+            if (srcUrl != null && srcUrl.getProtocol().equals("file")) {
+                File srcFile = new File(srcUrl.toURI());
+                if (! f.equals(srcFile)) {
+                    return false;
+                }
+            }
+            else {
+                return false;
+            }
+        }
+        catch (URISyntaxException uriSE) {
+            // theoretically we can't get URISyntaxException; the URL should
+            // be valid.
+        }
+        return true;
+    }
+    
+    // ---- bluej.compiler.CompileObserver interfaces ----
+
+    /**
+     * Observe compilation jobs and change the PkgMgr interface elements as
+     * compilation goes through different stages, but don't display the popups
+     * for error/warning messages.
+     * Also relay compilation events to any listening extensions.
+     */
+    private class QuietPackageCompileObserver
+        implements CompileObserver
+    {
+        private void markAsCompiling(File[] sources)
+        {
+            for (int i = 0; i < sources.length; i++) {
+                String fileName = sources[i].getPath();
+                String fullName = getProject().convertPathToPackageName(fileName);
+
+                if (fullName != null) {
+                    Target t = getTarget(JavaNames.getBase(fullName));
+
+                    if (t instanceof ClassTarget) {
+                        ClassTarget ct = (ClassTarget) t;
+                        ct.setState(ClassTarget.S_COMPILING);
+                    }
+                }
+            }
+        }
+
+        private void sendEventToExtensions(String filename, int [] errorPosition, String message, int eventType)
+        {
+            File [] sources;
+            if (filename != null) {
+                sources = new File[1];
+                sources[0] = new File(filename);
+            }
+            else {
+                sources = new File[0];
+            }
+            CompileEvent aCompileEvent = new CompileEvent(eventType, sources);
+            aCompileEvent.setErrorPosition(errorPosition);
+            aCompileEvent.setErrorMessage(message);
+            ExtensionsManager.getInstance().delegateEvent(aCompileEvent);
+        }
+
+        /**
+         * A compilation has been started. Mark the affected classes as being
+         * currently compiled.
+         */
+        @Override
+        public void startCompile(File[] sources)
+        {
+            // Send a compilation starting event to extensions.
+            CompileEvent aCompileEvent = new CompileEvent(CompileEvent.COMPILE_START_EVENT, sources);
+            ExtensionsManager.getInstance().delegateEvent(aCompileEvent);
+
+            // Set BlueJ status bar message
+            setStatus(compiling);
+
+            // Change view of source classes
+            markAsCompiling(sources);
+        }
+
+        @Override
+        public boolean compilerMessage(Diagnostic diagnostic)
+        {
+            int [] errorPosition = new int[4];
+            errorPosition[0] = (int) diagnostic.getStartLine();
+            errorPosition[1] = (int) diagnostic.getStartColumn();
+            errorPosition[2] = (int) diagnostic.getEndLine();
+            errorPosition[3] = (int) diagnostic.getEndColumn();
+            if (diagnostic.getType() == Diagnostic.ERROR) {
+                errorMessage(diagnostic.getFileName(), errorPosition, diagnostic.getMessage());
+            }
+            else {
+                warningMessage(diagnostic.getFileName(), errorPosition, diagnostic.getMessage());
+            }
+            return false;
+        }
+        
+        private void errorMessage(String filename, int [] errorPosition, String message)
+        {
+            // Send a compilation Error event to extensions.
+            sendEventToExtensions(filename, errorPosition, message, CompileEvent.COMPILE_ERROR_EVENT);
+        }
+
+        private void warningMessage(String filename, int [] errorPosition, String message)
+        {
+            // Send a compilation Error event to extensions.
+            sendEventToExtensions(filename, errorPosition, message, CompileEvent.COMPILE_WARNING_EVENT);
+        }
+
+        /**
+         * Compilation has ended. Mark the affected classes as being normal
+         * again.
+         */
+        @Override
+        public void endCompile(File[] sources, boolean successful)
+        {
+            for (int i = 0; i < sources.length; i++) {
+                String filename = sources[i].getPath();
+
+                String fullName = getProject().convertPathToPackageName(filename);
+                if (fullName == null) {
+                    continue;
+                }
+
+                ClassTarget t = (ClassTarget) targets.get(JavaNames.getBase(fullName));
+
+                if (t == null) {
+                    continue;
+                }
+
+                boolean newCompiledState = successful;
+
+                if (successful) {
+                    t.endCompile();
+
+                    //check if there already exists a class in a library with that name 
+                    Class<?> c = loadClass(getQualifiedName(t.getIdentifierName()));
+                    if (c!=null){
+                        if (! checkClassMatchesFile(c, t.getClassFile())) {
+                            String conflict=Package.getResourcePath(c);
+                            DialogManager.showMessageWithPrefixText(null, "compile-class-library-conflict", t.getIdentifierName()+":", conflict);
+                        }
+                    }
+
+                    /*
+                     * compute ctxt files (files with comments and parameters
+                     * names)
+                     */
+                    try {
+                        ClassInfo info = t.getSourceInfo().getInfo(t.getSourceFile(), t.getPackage());
+
+                        if (info != null) {
+                            OutputStream out = new FileOutputStream(t.getContextFile());
+                            info.getComments().store(out, "BlueJ class context");
+                            out.close();
+                        }
+                    }
+                    catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+
+                    // Empty class files should not be marked compiled,
+                    // even though compilation is "successful".
+                    newCompiledState &= t.upToDate();
+                }
+
+                t.setState(newCompiledState ? ClassTarget.S_NORMAL : ClassTarget.S_INVALID);
+                t.setQueued(false);
+                if (successful && t.editorOpen())
+                    t.getEditor().setCompiled(true);
+            }
+            setStatus(compileDone);
+            graphChanged();
+
+            // Send a compilation done event to extensions.
+            int eventId = successful ? CompileEvent.COMPILE_DONE_EVENT : CompileEvent.COMPILE_FAILED_EVENT;
+            CompileEvent aCompileEvent = new CompileEvent(eventId, sources);
+            ExtensionsManager.getInstance().delegateEvent(aCompileEvent);        
+        }
+    }
+    
+    private static class MisspeltMethodChecker implements MessageCalculator
+    {
+        private static final int MAX_EDIT_DISTANCE = 2;
+        private final String message;
+        private int lineNumber;
+        private int column;
+        private Project project;
+
+        public MisspeltMethodChecker(String message, int column, int lineNumber, Project project)
+        {
+            this.message = message;
+            this.column = column;
+            this.lineNumber = lineNumber;
+            this.project = project;
+        }
+        
+        private static String chopAtOpeningBracket(String name)
+        {
+            int openingBracket = name.indexOf('(');
+            if (openingBracket >= 0)
+                return name.substring(0,openingBracket);
+            else
+                return name;
+        }
+
+        private String getLine(Editor e)
+        {
+            return e.getText(new bluej.parser.SourceLocation(lineNumber, 1), new bluej.parser.SourceLocation(lineNumber, e.getLineLength(lineNumber-1)));
+        }
+        
+        private int getLineStart(Editor e)
+        {
+            return e.getOffsetFromLineColumn(new bluej.parser.SourceLocation(lineNumber, 1));
+        }
+        
+        // Levenshtein distance, taken from http://www.merriampark.com/ld.htm
+        private static int editDistance(String s, String t)
+        {
+            int d[][]; // matrix
+            int n; // length of s
+            int m; // length of t
+            int i; // iterates through s
+            int j; // iterates through t
+            char s_i; // ith character of s
+            char t_j; // jth character of t
+            int cost; // cost
+
+            // Step 1
+            n = s.length ();
+            m = t.length ();
+            if (n == 0) {
+                return m;
+            }
+            if (m == 0) {
+                return n;
+            }
+            d = new int[n+1][m+1];
+
+            // Step 2
+            for (i = 0; i <= n; i++) {
+                d[i][0] = i;
+            }
+            for (j = 0; j <= m; j++) {
+                d[0][j] = j;
+            }
+
+            // Step 3
+            for (i = 1; i <= n; i++) {
+                s_i = s.charAt (i - 1);
+
+                // Step 4
+                for (j = 1; j <= m; j++) {
+                    t_j = t.charAt (j - 1);
+
+                    // Step 5
+                    if (s_i == t_j) {
+                        cost = 0;
+                    }
+                    else {
+                        cost = 1;
+                    }
+
+                    // Step 6
+                    d[i][j] = Math.min(Math.min(d[i-1][j]+1, d[i][j-1]+1), d[i-1][j-1] + cost);
+                }
+            }
+
+            // Step 7
+            return d[n][m];
+        }
+        
+        @Override
+        public String calculateMessage(Editor e)
+        {
+            if (e == null) {
+                return message;
+            }
+            
+            String missing = chopAtOpeningBracket(message.substring(message.lastIndexOf(' ') + 1));
+
+            String lineText = getLine(e);
+            
+            // The column from the diagnostic object assumes tabs are 8 spaces; convert to
+            // a line position:
+            int pos = convertColumn(lineText, column) + getLineStart(e);
+            
+            LinkedList<String> maybeTheyMeant = new LinkedList<String>();
+            CodeSuggestions suggests = e.getParsedNode().getExpressionType(pos, e.getSourceDocument());
+            AssistContent[] values = ParseUtils.getPossibleCompletions(suggests, "",
+                    project.getJavadocResolver());
+            if (values != null) {
+                for (AssistContent a : values) {
+                    String name = chopAtOpeningBracket(a.getDisplayName());
+
+                    if (editDistance(name.toLowerCase(), missing.toLowerCase()) <= MAX_EDIT_DISTANCE) {
+                        maybeTheyMeant.addLast(a.getDisplayName());
+                    }
+                }
+            }
+
+            if (maybeTheyMeant.isEmpty()) {
+                return message;
+            } else {
+                String augmentedMessage = message + "; maybe you meant: " + maybeTheyMeant.getFirst();
+                maybeTheyMeant.removeFirst();
+                for (String sugg : maybeTheyMeant) {
+                    augmentedMessage += " or " + sugg;
+                }
+                return augmentedMessage;
+            }
+        }
+        
+        /** 
+         * Convert a column where a tab is counted as 8 to a column where a tab is counted
+         * as 1
+         */
+        private static int convertColumn(String string, int column)
+        {
+            int ccount = 0; // count of characters
+            int lpos = 0;   // count of columns (0 based)
+
+            int tabIndex = string.indexOf('\t');
+            while (tabIndex != -1 && lpos < column - 1) {
+                lpos += tabIndex - ccount;
+                ccount = tabIndex;
+                if (lpos >= column - 1) {
+                    break;
+                }
+                lpos = ((lpos + 8) / 8) * 8;  // tab!
+                ccount += 1;
+                tabIndex = string.indexOf('\t', ccount);
+            }
+
+            ccount += column - lpos;
+            return ccount;
+        }
+    }
+
+    /**
+     * The same, but also display error/warning messages for the user
+     */
+    private class PackageCompileObserver extends QuietPackageCompileObserver
+    {
+        private boolean hadError;
+        
+        @Override
+        public void startCompile(File[] sources)
+        {
+            hadError = false;
+            super.startCompile(sources);
+        }
+        
+        @Override
+        public boolean compilerMessage(Diagnostic diagnostic)
+        {
+            super.compilerMessage(diagnostic);
+            if (diagnostic.getType() == Diagnostic.ERROR) {
+                return errorMessage(diagnostic);
+            }
+            else {
+                return warningMessage(diagnostic.getFileName(), (int) diagnostic.getStartLine(),
+                        diagnostic.getMessage());
+            }
+        }
+        
+        /**
+         * Display an error message associated with a specific line in a class.
+         * This is done by opening the class's source, highlighting the line and
+         * showing the message in the editor's information area.
+         */
+        private boolean errorMessage(Diagnostic diagnostic)
+        {
+            if (! hadError) {
+                hadError = true;
+                boolean messageShown;
+
+                if (diagnostic.getFileName() == null) {
+                    showMessageWithText("compiler-error", diagnostic.getMessage());
+                    return true;
+                }
+                
+                String message = diagnostic.getMessage();
+                // See if we can help the user a bit more if they've mis-spelt a method:
+                if (message.contains("cannot find symbol - method")) {
+                    messageShown = showEditorDiagnostic(diagnostic,
+                            new MisspeltMethodChecker(message,
+                                    (int) diagnostic.getStartColumn(),
+                                    (int) diagnostic.getStartLine(),
+                                    project));
+                } else {
+                    messageShown = showEditorDiagnostic(diagnostic, null);
+                }
+                // Display the error message in the source editor
+                if (!messageShown) {
+                    showMessageWithText("error-in-file", diagnostic.getFileName() + ":" +
+                            diagnostic.getStartLine() + "\n" + message);
+                }
+                
+                return true;
+            }
+            
+            return false;
+        }
+
+        /**
+         * Display a warning message: just a dialog box
+         * The dialog accumulates messages until reset() is called, which is
+         * done in the methods which the user can invoke to cause compilation
+         * Thus all the warnings caused by a "compilation" can be accumulated
+         * into a single dialog.
+         * If searchCompile() built a single list, we wouldn't need to do this
+         */
+        private boolean warningMessage(String filename, int lineNo, String message)
+        {
+            // Add this message-fragment to, and display, the warning dialog
+            bluej.compiler.CompilerWarningDialog.getDialog().addWarningMessage(message);
+            
+            return true;
+        }
+    }
+
+    // ---- end of bluej.compiler.CompileObserver interfaces ----
+
+    /**
+     * closeAllEditors - closes all currently open editors within package Should
+     * be run whenever a package is removed from PkgFrame.
+     */
+    public void closeAllEditors()
+    {
+        for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
+            Target t = it.next();
+            if (t instanceof EditableTarget) {
+                EditableTarget et = (EditableTarget) t;
+                if (et.editorOpen()) {
+                    et.getEditor().close();
+                }
+            }
+        }
+    }
+
+    /**
+     * get history of invocation calls
+     * 
+     * @return CallHistory object
+     */
+    public CallHistory getCallHistory()
+    {
+        return callHistory;
+    }
+
+    /**
+     * String representation for debugging.
+     */
+    public String toString()
+    {
+        return "Package:" + getQualifiedName();
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageEditor.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageEditor.java
new file mode 100644
index 0000000000000000000000000000000000000000..41627ab0690ff6b042e10407546f797848f86fe0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageEditor.java
@@ -0,0 +1,160 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.Component;
+
+import javax.swing.Action;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.extmgr.MenuManager;
+import bluej.extmgr.PackageMenuObject;
+import bluej.graph.GraphEditor;
+import bluej.pkgmgr.actions.NewClassAction;
+import bluej.pkgmgr.actions.NewPackageAction;
+import bluej.pkgmgr.target.Target;
+import bluej.prefmgr.PrefMgr;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.views.CallableView;
+
+/**
+ * Canvas to allow editing of packages
+ *
+ * @author  Andrew Patterson
+ * @version $Id: PackageEditor.java 9624 2012-03-29 17:04:54Z davmac $
+ */
+public final class PackageEditor extends GraphEditor
+{
+    private PackageEditorListener listener;
+    
+    public PackageEditor(Package pkg, PackageEditorListener listener)
+    {
+        super(pkg);
+        this.listener = listener;
+    }
+
+    // notify all listeners that have registered interest for
+    // notification on this event type.
+    protected void fireTargetEvent(PackageEditorEvent e)
+    {
+        if (listener != null) {
+            listener.targetEvent(e);
+        }
+    }
+
+    public void raiseMethodCallEvent(Object src, CallableView cv)
+    {
+        fireTargetEvent(
+            new PackageEditorEvent(src, PackageEditorEvent.TARGET_CALLABLE, cv));
+    }
+
+    public void raiseRemoveTargetEvent(Target t)
+    {
+        fireTargetEvent(
+            new PackageEditorEvent(t, PackageEditorEvent.TARGET_REMOVE));
+    }
+
+    public void raiseBenchToFixtureEvent(Target t)
+    {
+        fireTargetEvent(
+            new PackageEditorEvent(t, PackageEditorEvent.TARGET_BENCHTOFIXTURE));
+    }
+
+    public void raiseFixtureToBenchEvent(Target t)
+    {
+        fireTargetEvent(
+            new PackageEditorEvent(t, PackageEditorEvent.TARGET_FIXTURETOBENCH));
+    }
+
+    public void raiseMakeTestCaseEvent(Target t)
+    {
+        fireTargetEvent(
+            new PackageEditorEvent(t, PackageEditorEvent.TARGET_MAKETESTCASE));
+    }
+
+    public void raiseRunTargetEvent(Target t, String name)
+    {
+        fireTargetEvent(
+            new PackageEditorEvent(t, PackageEditorEvent.TARGET_RUN, name));
+    }
+
+    public void raiseOpenPackageEvent(Target t, String packageName)
+    {
+        fireTargetEvent(
+            new PackageEditorEvent(t, PackageEditorEvent.TARGET_OPEN,
+                                    packageName));
+    }
+
+    /**
+     * Raise an event to notify that an object should be placed on the oject bench.
+     * @param src  The source of the event
+     * @param obj    The object to be put on the event
+     * @param iType  The "interface" type of the object (declared type, used as a
+     *               fallback if the runtime type is not accessible)
+     * @param ir   The invoker record for the invocation used to create this object
+     */
+    public void raisePutOnBenchEvent(Component src, DebuggerObject obj, GenTypeClass iType, InvokerRecord ir)
+    {
+        fireTargetEvent(
+            new PackageEditorEvent(src, PackageEditorEvent.OBJECT_PUTONBENCH, obj, iType, ir));
+    }
+    
+    /**
+     * Notify of some interaction.
+     */
+    public void recordInteraction(InvokerRecord ir)
+    {
+        listener.recordInteraction(ir);
+    }
+    
+    public void popupMenu(int x, int y)
+    {
+        JPopupMenu menu = createMenu();
+        menu.show(this, x, y);
+    }
+
+    private JPopupMenu createMenu()
+    {
+        JPopupMenu menu = new JPopupMenu();
+        Action newClassAction = new NewClassAction();
+        addMenuItem(menu, newClassAction);
+        Action newPackageAction = new NewPackageAction();
+        addMenuItem(menu, newPackageAction);
+
+        Package bluejPackage = (Package) getGraph();
+        MenuManager menuManager = new MenuManager(menu);
+        menuManager.setAttachedObject(new PackageMenuObject(bluejPackage));
+        menuManager.addExtensionMenu(bluejPackage.getProject());
+
+        return menu;
+    }
+    
+    private void addMenuItem(JPopupMenu menu, Action action)
+    {
+        JMenuItem item = menu.add(action);
+        item.setFont(PrefMgr.getPopupMenuFont());
+        item.setForeground(envOpColour);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageEditorEvent.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageEditorEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6c62fd604715a74a3688ad45f5ed601dd9564eb
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageEditorEvent.java
@@ -0,0 +1,134 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.util.EventObject;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.views.CallableView;
+
+/**
+ * The event which occurs while editing a package
+ *
+ * @author  Andrew Patterson
+ */
+public class PackageEditorEvent extends EventObject
+{
+    public final static int TARGET_CALLABLE = 1;
+    public final static int TARGET_REMOVE = 2;
+    public final static int TARGET_OPEN = 3;
+    public final static int TARGET_RUN = 4;
+    public final static int TARGET_BENCHTOFIXTURE = 5; // only for unit tests
+    public final static int TARGET_FIXTURETOBENCH = 6; // only for unit tests
+    public final static int TARGET_MAKETESTCASE = 7;    // only for unit tests
+
+    public final static int OBJECT_PUTONBENCH = 8;
+
+    protected int id;
+    protected CallableView cv;
+    protected DebuggerObject obj;
+    protected InvokerRecord ir;
+    protected GenTypeClass iType;
+    protected String name;
+
+    public PackageEditorEvent(Object source, int id)
+    {
+        super(source);
+        this.id = id;
+    }
+
+    public PackageEditorEvent(Object source, int id, String packageName)
+    {
+        super(source);
+
+        this.id = id;
+        this.name = packageName;
+    }
+
+    public PackageEditorEvent(Object source, int id, CallableView cv)
+    {
+        super(source);
+
+        if (id != TARGET_CALLABLE)
+            throw new IllegalArgumentException();
+
+        this.id = id;
+        this.cv = cv;
+    }
+
+    /**
+     * Construct an event for a "put object on bench" request (OBJECT_PUTONBENCH)
+     * 
+     * @param source  The source of the event
+     * @param id      The event id (OBJECT_PUTONBENCH)
+     * @param obj     The object to put on the bench
+     * @param iType   The publicly-accessible type of the object
+     *       The iType parameter is used to provide an acting type for the object if the
+     *       actual type is inaccessible (is private to another package or class).
+     * @param ir      The record for the invocation used to obtain the object
+     * 
+     */
+    public PackageEditorEvent(Object source, int id, DebuggerObject obj, GenTypeClass iType, InvokerRecord ir)
+    {
+        super(source);
+
+        if (id != OBJECT_PUTONBENCH)
+            throw new IllegalArgumentException();
+
+        this.id = id;
+        this.obj = obj;
+        this.iType = iType;
+	this.ir = ir;
+    }
+
+    public int getID()
+    {
+        return id;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public CallableView getCallable()
+    {
+        return cv;
+    }
+
+    public DebuggerObject getDebuggerObject()
+    {
+        return obj;
+    }
+    
+    public GenTypeClass getIType()
+    {
+        return iType;
+    }
+    
+    public InvokerRecord getInvokerRecord()
+    {
+    	return ir;	
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageEditorListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageEditorListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e92e6a9fae5ba16e8691ca6d4d7e5c12f2cd5f4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageEditorListener.java
@@ -0,0 +1,38 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.util.EventListener;
+
+import bluej.testmgr.record.InvokerRecord;
+
+/**
+ * The listener for PackageEditor events.
+ *
+ * @author  Andrew Patterson
+ */
+public interface PackageEditorListener extends EventListener
+{
+    void targetEvent(PackageEditorEvent e);
+    
+    void recordInteraction(InvokerRecord ir);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageFile.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageFile.java
new file mode 100644
index 0000000000000000000000000000000000000000..15b7704833c57775eff3a2505c41b73327addd45
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageFile.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * Interface to a package file.
+ * 
+ * @author Poul Henriksen
+ */
+public interface PackageFile
+{
+    /**
+     * Create this package.
+     * 
+     * @return true if it was created, false if it was not created (possibly
+     *         because a package already existed here).
+     * @throws IOException If the package file(s) could not be created.
+     * 
+     */
+    public boolean create()
+        throws IOException;
+
+    /**
+     * Load the properties from the file into the given properties.
+     * 
+     * @throws IOException
+     */
+    public void load(Properties p)
+        throws IOException;
+
+    /**
+     * Save the given properties to the file.
+     * 
+     * @return False if it couldn't save it.
+     * @throws IOException
+     * 
+     */
+    public void save(Properties p)
+        throws IOException;
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageFileFactory.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageFileFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b45d749846e900f6318fab9b96c019e29f7c097
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackageFileFactory.java
@@ -0,0 +1,53 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.File;
+
+import bluej.Config;
+
+/**
+ * Factory for creating package files.
+ * 
+ * @author Poul Henriksen
+ */
+public class PackageFileFactory
+{
+
+    /**
+     * Get a packagefile for the given directory. This will be either a
+     * Greenfoot or BlueJ package file, depending on whether we are using this
+     * from Greenfoot or BlueJ.
+     * 
+     * @param dir
+     * @return
+     */
+    public static PackageFile getPackageFile(File dir)
+    {
+        if (Config.isGreenfoot()) {
+            return new GreenfootProjectFile(dir);
+        }
+        else {
+            return new BlueJPackageFile(dir);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackagePrintManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackagePrintManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4ff39bfaa2e2dbd885054d76f4a55146b57e0d2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackagePrintManager.java
@@ -0,0 +1,132 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import bluej.Config;
+
+import bluej.editor.Editor;
+import bluej.pkgmgr.target.*;
+
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterJob;
+
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * Manages the printing of package assets eg. Class Diagram, Readme and Source
+ * files.  All source files are printed as one large batch.  Individual
+ * printing occurs through the source code editor
+ * 
+ * @author Bruce Quig
+ */
+public class PackagePrintManager extends Thread
+{
+    private PageFormat pageFormat;
+    private Package pkg;
+    private ProjectPrintDialog dialog;
+
+    /**
+     * Constructor for PackagePrinter.
+     * 
+     * @param pkg package to be printed
+     * @param pageFormat pageformat of printer job
+     * @param dialog the project print dialog used by user to select which
+     *        assets to print.
+     */
+    public PackagePrintManager(Package pkg, PageFormat pageFormat, 
+                               ProjectPrintDialog dialog)
+    {
+        this.pkg = pkg;
+        this.pageFormat = pageFormat;
+        this.dialog = dialog;
+    }
+
+    /**
+     * Overridden run method called as part of the usage of this class as a
+     * background operation via a thread with lower priority.
+     */
+    public void run()
+    {
+        PrinterJob printer = PrinterJob.getPrinterJob();
+
+        if (printer.printDialog()) {
+            if (dialog.printDiagram()) {
+                printClassDiagram(printer);
+            }
+
+            if (dialog.printSource()) {
+                printSourceCode(printer);
+            }
+
+            if (dialog.printReadme()) {
+                printReadme(printer);
+            }
+        }
+    }
+
+    /**
+     * Prints the graphical representation of classes in the package.
+     * 
+     * @param printJob the printer job to print the diagram to.
+     */
+    public void printClassDiagram(PrinterJob printJob)
+    {
+        ClassDiagramPrinter diagramPrinter = new ClassDiagramPrinter(printJob, 
+                                                                     pkg, 
+                                                                     pageFormat);
+        pkg.setStatus(Config.getString("pkgmgr.info.printing"));
+        diagramPrinter.printPackage();
+    }
+
+    /**
+     * Prints all source code for the package
+     * 
+     * @param printJob the printer job to print the source code to.
+     */
+    public void printSourceCode(PrinterJob printJob)
+    {
+        List<String> classes = pkg.getAllClassnamesWithSource();
+
+        for (Iterator<String> it = classes.iterator(); it.hasNext();) {
+            String className = it.next();
+            ClassTarget target = (ClassTarget) pkg.getTarget(className);
+            Editor editor = target.getEditor();
+            editor.print(printJob);
+        }
+    }
+
+    /**
+     * Prints the project readme file
+     * 
+     * @param printJob the printer job to print the readme text file to.
+     */
+    public void printReadme(PrinterJob printJob)
+    {
+        ReadmeTarget readme = pkg.getReadmeTarget();
+
+        if (readme != null) {
+            readme.getEditor().print(printJob);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackagePrinter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackagePrinter.java
new file mode 100644
index 0000000000000000000000000000000000000000..20ccfe92bf40bc65b698b8d2a25eeb8df4734c29
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PackagePrinter.java
@@ -0,0 +1,204 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.print.*;
+import java.awt.*;
+import java.util.Date;
+import java.text.DateFormat;
+
+import bluej.utility.Utility;
+import bluej.Config;
+
+/**
+ * Provides the ability to print a package as a separate thread 
+ * (typically as a low priority background task)
+ *
+ * @author Bruce Quig
+ */
+public class PackagePrinter extends Thread implements Printable
+{
+
+    private PageFormat pageFormat;
+    private Package pkg;
+
+    private int pageColumns = 0;
+    private int pageRows = 0;
+    private int pages;
+    private int currentPage;
+    private int currentColumn = 0;
+    private int currentRow = 0;
+
+    final static int a4Width = 595;
+    final static int a4Height = 840;
+
+   // Add a title to printouts
+    static final int PRINT_HMARGIN = 6;
+    static final int PRINT_VMARGIN = 24;
+    static final Font printTitleFont = new Font("SansSerif", Font.PLAIN,
+                                                12); //Config.printTitleFontsize);
+    static final Font printInfoFont = new Font("SansSerif", Font.ITALIC,
+                                               10); //Config.printInfoFontsize);
+
+    
+    public PackagePrinter(Package pkg, PageFormat pageFormat)
+    {
+        this.pkg = pkg;
+        this.pageFormat = pageFormat;
+    }
+
+    public void run()
+    {
+        this.printPackage();
+    }
+
+    private void printPackage()
+    {
+        PrinterJob printerJob = PrinterJob.getPrinterJob();
+
+        printerJob.setPrintable(this, pageFormat);
+
+        if (printerJob.printDialog()) {
+            pkg.setStatus(Config.getString("pkgmgr.info.printing"));
+            calculatePages();
+            try {
+                // call the Printable interface to do the actual printing
+                printerJob.print();
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+            pkg.setStatus(Config.getString("pkgmgr.info.printed"));
+        }
+    }
+
+    private void calculatePages()
+    {
+        Dimension graphSize = pkg.getMinimumSize();
+        Rectangle printArea = getPrintArea(pageFormat);
+        
+        pageColumns = (graphSize.width + printArea.width - 1) / printArea.width;
+        pageRows = (graphSize.height + printArea.height - 1) / printArea.height;
+        pages = pageColumns * pageRows;
+        currentColumn = currentRow = 0;
+    }
+
+    /**
+     * Method that implements Printable interface and does that actual printing of
+     * class diagram.
+     */
+    public int print(Graphics g, PageFormat pageFormat, int pageIndex)
+    {
+        if(pageIndex >= pages)
+            return Printable.NO_SUCH_PAGE;
+
+        Rectangle printArea = getPrintArea(pageFormat);
+        
+        if(currentColumn < pageColumns) {
+            if(currentPage < pageIndex)
+                currentColumn++;
+        }
+        else if(currentRow < pageRows) {
+            //if(currentPage < pageIndex)
+            currentRow++;
+            currentColumn = 0;
+        }
+                 
+        printTitle(g, pageFormat, pageIndex + 1);
+
+        g.translate(printArea.x - currentColumn * printArea.width,
+                    printArea.y - currentRow * printArea.height);
+        g.setClip(currentColumn * printArea.width, currentRow * printArea.height,
+                  printArea.width, printArea.height);
+
+        pkg.getEditor().paint(g);
+
+        currentPage = pageIndex;
+        return Printable.PAGE_EXISTS;
+         
+    }
+
+ 
+
+    /**
+     * Return the rectangle on the page in which to draw the class diagram.
+     * The rectangle is the page minus margins minus space for header and
+     * footer text.
+     */
+    private Rectangle getPrintArea(PageFormat pageFormat)
+    {
+        return new Rectangle((int)pageFormat.getImageableX() + PRINT_HMARGIN,
+                             (int)pageFormat.getImageableY() + PRINT_VMARGIN,
+                             (int)pageFormat.getImageableWidth() - (2 * PRINT_HMARGIN),
+                             (int)pageFormat.getImageableHeight() - (2 * PRINT_VMARGIN));
+    }
+
+    /**
+     * Print the page title and other page decorations (frame, footer).
+     */
+    private void printTitle(Graphics g, PageFormat pageFormat, int pageNum)
+    {
+
+        FontMetrics tfm = g.getFontMetrics(printTitleFont);
+        FontMetrics ifm = g.getFontMetrics(printInfoFont);
+        Rectangle printArea = new Rectangle((int)pageFormat.getImageableX(),
+                                            (int)pageFormat.getImageableY(),
+                                            (int)pageFormat.getImageableWidth(),
+                                            (int)pageFormat.getImageableHeight());
+
+        // frame header area
+        g.setColor(Color.lightGray);
+        g.fillRect(printArea.x, printArea.y, printArea.width, PRINT_VMARGIN);
+
+        //    Rectangle titleRectangle = new Rectangle(printArea.x, 
+        //                                                  printArea.y, 
+        //                                                  printArea.width, 
+        //                                                  PRINT_VMARGIN);
+        
+        //         g.fill(titleRectangle);
+
+        // g.setColor(titleCol);
+        g.setColor(Color.black);
+
+        g.drawRect(printArea.x, printArea.y, printArea.width, PRINT_VMARGIN);
+        // g.draw(titleRectangle);
+
+        // frame print area
+        g.drawRect(printArea.x, printArea.y, printArea.width,
+                   printArea.height - PRINT_VMARGIN);
+
+        // write header
+        //String title = (packageName == noPackage) ? dirname : packageName;
+        String title = pkg.getQualifiedName();
+        g.setFont(printTitleFont);
+        Utility.drawCentredText(g, "BlueJ package - " + title,
+                                printArea.x, printArea.y,
+                                printArea.width, tfm.getHeight());
+        // write footer
+        g.setFont(printInfoFont);
+        DateFormat dateFormat = DateFormat.getDateTimeInstance();
+        Utility.drawRightText(g, dateFormat.format(new Date()) + ", Page " + pageNum,
+                              printArea.x, printArea.y + printArea.height - PRINT_VMARGIN,
+                              printArea.width, ifm.getHeight());
+    }
+
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PkgMgrFrame.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PkgMgrFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..cbd87a5098d42998c230ea8b67e635dd18ea181b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/PkgMgrFrame.java
@@ -0,0 +1,3275 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.KeyboardFocusManager;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.print.PageFormat;
+import java.awt.print.Paper;
+import java.awt.print.PrinterJob;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JSplitPane;
+import javax.swing.JToggleButton;
+import javax.swing.KeyStroke;
+import javax.swing.SwingConstants;
+
+import bluej.BlueJEvent;
+import bluej.BlueJEventListener;
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugmgr.ExecutionEvent;
+import bluej.debugmgr.ExpressionInformation;
+import bluej.debugmgr.Invoker;
+import bluej.debugmgr.LibraryCallDialog;
+import bluej.debugmgr.ResultWatcher;
+import bluej.debugmgr.objectbench.ObjectBench;
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.debugmgr.texteval.TextEvalArea;
+import bluej.extmgr.ExtensionsManager;
+import bluej.extmgr.MenuManager;
+import bluej.extmgr.ToolsMenuObject;
+import bluej.extmgr.ViewMenuObject;
+import bluej.groupwork.actions.CheckoutAction;
+import bluej.groupwork.actions.TeamActionGroup;
+import bluej.groupwork.ui.ActivityIndicator;
+import bluej.pkgmgr.actions.AddClassAction;
+import bluej.pkgmgr.actions.CancelTestRecordAction;
+import bluej.pkgmgr.actions.CheckExtensionsAction;
+import bluej.pkgmgr.actions.CheckVersionAction;
+import bluej.pkgmgr.actions.CloseProjectAction;
+import bluej.pkgmgr.actions.CompileAction;
+import bluej.pkgmgr.actions.CompileSelectedAction;
+import bluej.pkgmgr.actions.DeployMIDletAction;
+import bluej.pkgmgr.actions.EndTestRecordAction;
+import bluej.pkgmgr.actions.ExportProjectAction;
+import bluej.pkgmgr.actions.GenerateDocsAction;
+import bluej.pkgmgr.actions.HelpAboutAction;
+import bluej.pkgmgr.actions.ImportProjectAction;
+import bluej.pkgmgr.actions.NewClassAction;
+import bluej.pkgmgr.actions.NewInheritsAction;
+import bluej.pkgmgr.actions.NewMEprojectAction;
+import bluej.pkgmgr.actions.NewPackageAction;
+import bluej.pkgmgr.actions.NewProjectAction;
+import bluej.pkgmgr.actions.NewUsesAction;
+import bluej.pkgmgr.actions.OpenNonBlueJAction;
+import bluej.pkgmgr.actions.OpenProjectAction;
+import bluej.pkgmgr.actions.PageSetupAction;
+import bluej.pkgmgr.actions.PkgMgrAction;
+import bluej.pkgmgr.actions.PreferencesAction;
+import bluej.pkgmgr.actions.PrintAction;
+import bluej.pkgmgr.actions.QuitAction;
+import bluej.pkgmgr.actions.RebuildAction;
+import bluej.pkgmgr.actions.RemoveAction;
+import bluej.pkgmgr.actions.RestartVMAction;
+import bluej.pkgmgr.actions.RunTestsAction;
+import bluej.pkgmgr.actions.SaveProjectAction;
+import bluej.pkgmgr.actions.SaveProjectAsAction;
+import bluej.pkgmgr.actions.ShowCopyrightAction;
+import bluej.pkgmgr.actions.ShowDebuggerAction;
+import bluej.pkgmgr.actions.ShowInheritsAction;
+import bluej.pkgmgr.actions.ShowTerminalAction;
+import bluej.pkgmgr.actions.ShowTestResultsAction;
+import bluej.pkgmgr.actions.ShowTextEvalAction;
+import bluej.pkgmgr.actions.ShowUsesAction;
+import bluej.pkgmgr.actions.StandardAPIHelpAction;
+import bluej.pkgmgr.actions.TutorialAction;
+import bluej.pkgmgr.actions.UseLibraryAction;
+import bluej.pkgmgr.actions.WebsiteAction;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.PackageTarget;
+import bluej.pkgmgr.target.Target;
+import bluej.pkgmgr.target.role.UnitTestClassRole;
+import bluej.prefmgr.PrefMgr;
+import bluej.prefmgr.PrefMgrDialog;
+import bluej.testmgr.TestDisplayFrame;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+import bluej.utility.GradientFillPanel;
+import bluej.utility.JavaNames;
+import bluej.utility.Utility;
+import bluej.views.CallableView;
+import bluej.views.ConstructorView;
+import bluej.views.MethodView;
+
+/**
+ * The main user interface frame which allows editing of packages
+ */
+public class PkgMgrFrame extends JFrame
+    implements BlueJEventListener, MouseListener, PackageEditorListener, FocusListener
+{
+    private static Font pkgMgrFont = PrefMgr.getStandardFont();
+
+    static final int DEFAULT_WIDTH = 560;
+    static final int DEFAULT_HEIGHT = 400;
+
+    private static boolean testToolsShown = wantToSeeTestingTools();
+    private static boolean teamToolsShown = wantToSeeTeamTools();
+    private static boolean javaMEtoolsShown = wantToSeeJavaMEtools();
+
+    // instance fields:
+
+    private JPanel buttonPanel;
+    private JPanel testPanel;
+    private JPanel javaMEPanel;
+    private JPanel teamPanel;
+
+    private JCheckBoxMenuItem showUsesMenuItem;
+    private JCheckBoxMenuItem showExtendsMenuItem;
+
+    private AbstractButton imgExtendsButton;
+    private AbstractButton imgDependsButton;
+    private AbstractButton runButton;
+
+    private JLabel statusbar;
+    private ActivityIndicator progressbar;
+
+    private JLabel testStatusMessage;
+    private JLabel recordingLabel;
+    private AbstractButton endTestButton;
+    private AbstractButton cancelTestButton;
+    private JMenuItem endTestMenuItem;
+    private JMenuItem cancelTestMenuItem;
+
+    private ClassTarget testTarget = null;
+    private String testTargetMethod;
+    private static AtomicInteger nextTestIdentifier = new AtomicInteger(0); 
+    private int testIdentifier = 0;
+
+    private JMenuBar menubar = null;
+    private JMenu recentProjectsMenu;
+    private JMenu testingMenu;
+    private MenuManager toolsMenuManager;
+    private MenuManager viewMenuManager;
+    
+    private JMenu teamMenu;
+    private JMenuItem shareProjectMenuItem;
+    private JMenuItem teamSettingsMenuItem;
+    private JMenuItem showLogMenuItem;
+    private JMenuItem updateMenuItem;
+    private JMenuItem commitMenuItem;
+    private JMenuItem statusMenuItem;
+    private AbstractButton updateButton;
+    private AbstractButton commitButton;
+    private AbstractButton teamStatusButton;
+    private List<JComponent> teamItems;
+    private JMenuItem javaMEnewProjMenuItem;
+    private JMenuItem javaMEdeployMenuItem;
+  
+    private TeamActionGroup teamActions;
+    
+    private JMenuItem showTestResultsItem;
+    private List<JComponent> itemsToDisable;
+    private List<Action> actionsToDisable;
+    private List<JComponent> testItems;
+    private MachineIcon machineIcon;
+    
+    /* UI actions */
+    private Action closeProjectAction = new CloseProjectAction();
+    private Action saveProjectAction = new SaveProjectAction();
+    private Action saveProjectAsAction = new SaveProjectAsAction();
+    private Action importProjectAction = new ImportProjectAction();
+    private Action exportProjectAction = new ExportProjectAction();
+    private Action pageSetupAction = new PageSetupAction();
+    private Action printAction = new PrintAction();
+    private Action newClassAction = new NewClassAction();
+    private Action newPackageAction = new NewPackageAction();
+    private Action addClassAction = new AddClassAction();
+    private Action removeAction = new RemoveAction();
+    private Action newUsesAction = new NewUsesAction();
+    private Action newInheritsAction = new NewInheritsAction();
+    private Action compileAction = new CompileAction();
+    private Action compileSelectedAction = new CompileSelectedAction();
+    private Action rebuildAction = new RebuildAction();
+    private Action restartVMAction = RestartVMAction.getInstance();
+    private Action useLibraryAction = new UseLibraryAction();
+    private Action generateDocsAction = new GenerateDocsAction();
+    private PkgMgrAction showUsesAction = new ShowUsesAction();
+    private PkgMgrAction showInheritsAction = new ShowInheritsAction();
+    private PkgMgrAction showDebuggerAction = new ShowDebuggerAction();
+    private PkgMgrAction showTerminalAction = new ShowTerminalAction();
+    private PkgMgrAction showTextEvalAction = new ShowTextEvalAction();
+    private Action runTestsAction = new RunTestsAction();
+    private Action deployMIDletAction = new DeployMIDletAction();
+
+    /* The scroller which holds the PackageEditor we use to edit packages */
+    private JScrollPane classScroller = null;
+
+    /*
+     * The package that this frame is working on or null for the case where
+     * there is no package currently being edited (check with isEmptyFrame())
+     */
+    private Package pkg = null;
+    
+    /*
+     * The graph editor which works on the package or null for the case where
+     * there is no package current being edited (isEmptyFrame() == true)
+     */
+    private PackageEditor editor = null;
+
+    private ObjectBench objbench;
+    private TextEvalArea textEvaluator;
+    private JSplitPane splitPane;
+    private JSplitPane objectBenchSplitPane;
+    private boolean showingTextEvaluator = false;
+
+    // lazy initialised dialogs
+    private LibraryCallDialog libraryCallDialog = null;
+    private ProjectPrintDialog projectPrintDialog = null;
+
+    // set PageFormat for default page for default printer
+    // this variable is lazy initialised
+    private static PageFormat pageFormat = null;
+
+    // static methods to create and remove frames
+
+    private static List<PkgMgrFrame> frames = new ArrayList<PkgMgrFrame>(); // of PkgMgrFrames
+
+    private static ExtensionsManager extMgr = ExtensionsManager.getInstance();
+
+    private ExportManager exporter;
+
+    /**
+     * Open a PkgMgrFrame with no package. Packages can be installed into this
+     * frame using the methods openPackage/closePackage.
+     */
+    public static PkgMgrFrame createFrame()
+    {
+        PkgMgrFrame frame = new PkgMgrFrame();
+        frames.add(frame);
+        BlueJEvent.addListener(frame);
+        return frame;
+    }
+
+    /**
+     * Open a PkgMgrFrame with a package. This may create a new frame or return
+     * an existing frame if this package is already being edited by a frame. If
+     * an empty frame exists, that frame will be used to show the package.
+     */
+    public static PkgMgrFrame createFrame(Package pkg)
+    {
+        PkgMgrFrame pmf = findFrame(pkg);
+
+        if (pmf == null) {
+            // check whether we've got an empty frame
+
+            if (frames.size() == 1)
+                pmf = frames.get(0);
+
+            if ((pmf == null) || !pmf.isEmptyFrame())
+                pmf = createFrame();
+
+            pmf.openPackage(pkg);
+        }
+
+        return pmf;
+    }
+
+    /**
+     * Remove a frame from the set of currently open PkgMgrFrames. The
+     * PkgMgrFrame must not be editing a package when this function is called.
+     */
+    public static void closeFrame(PkgMgrFrame frame)
+    {
+        if (!frame.isEmptyFrame())
+            throw new IllegalArgumentException();
+
+        frames.remove(frame);
+
+        BlueJEvent.removeListener(frame);
+        PrefMgr.setFlag(PrefMgr.SHOW_TEXT_EVAL, frame.showingTextEvaluator);
+
+        // frame should be garbage collected but we will speed it
+        // on its way
+        frame.dispose();
+    }
+
+    /**
+     * Find a frame which is editing a particular Package and return it or
+     * return null if it is not being edited
+     */
+    public static PkgMgrFrame findFrame(Package pkg)
+    {
+        for (Iterator<PkgMgrFrame> i = frames.iterator(); i.hasNext();) {
+            PkgMgrFrame pmf = i.next();
+
+            if (!pmf.isEmptyFrame() && pmf.getPackage() == pkg)
+                return pmf;
+        }
+        return null;
+    }
+
+    /**
+     * @return the number of currently open top level frames
+     */
+    public static int frameCount()
+    {
+        return frames.size();
+    }
+
+    /**
+     * Returns an array of all PkgMgrFrame objects. It can be an empty array if
+     * none is found.
+     */
+    public static PkgMgrFrame[] getAllFrames()
+    {
+        PkgMgrFrame[] openFrames = new PkgMgrFrame[frames.size()];
+        frames.toArray(openFrames);
+
+        return openFrames;
+    }
+
+    /**
+     * Find all PkgMgrFrames which are currently editing a particular project
+     * 
+     * @param proj
+     *            the project whose packages to look for
+     * 
+     * @return an array of open PkgMgrFrame objects which are currently editing
+     *         a package from this project, or null if none exist
+     */
+    public static PkgMgrFrame[] getAllProjectFrames(Project proj)
+    {
+        return getAllProjectFrames(proj, "");
+    }
+
+    /**
+     * Find all PkgMgrFrames which are currently editing a particular project,
+     * and which are below a certain point in the package heirarchy.
+     * 
+     * @param proj
+     *            the project whose packages to look for
+     * @param pkgPrefix
+     *            the package name of a package to look for it and all its
+     *            children ie if passed java.lang we would return frames for
+     *            java.lang, and java.lang.reflect if they exist
+     * 
+     * @return an array of open PkgMgrFrame objects which are currently editing
+     *         a package from this project and which have the package prefix
+     *         specified, or null if none exist
+     */
+    public static PkgMgrFrame[] getAllProjectFrames(Project proj, String pkgPrefix)
+    {
+        List<PkgMgrFrame> list = new ArrayList<PkgMgrFrame>();
+        String pkgPrefixWithDot = pkgPrefix + ".";
+
+        for (Iterator<PkgMgrFrame> i = frames.iterator(); i.hasNext();) {
+            PkgMgrFrame pmf = i.next();
+
+            if (!pmf.isEmptyFrame() && pmf.getProject() == proj) {
+
+                String fullName = pmf.getPackage().getQualifiedName();
+
+                // we either match against the package prefix with a
+                // dot added (this stops false matches against similarly
+                // named package ie java.lang and java.language) or we
+                // match the full name against the package prefix
+                if (fullName.startsWith(pkgPrefixWithDot))
+                    list.add(pmf);
+                else if (fullName.equals(pkgPrefix) || (pkgPrefix.length() == 0))
+                    list.add(pmf);
+            }
+        }
+
+        if (list.isEmpty())
+            return null;
+
+        return list.toArray(new PkgMgrFrame[list.size()]);
+    }
+
+    /**
+     * Gets the most recently used PkgMgrFrame
+     * 
+     * @return the PkgMgrFrame that currently has the focus
+     */
+    public static PkgMgrFrame getMostRecent()
+    {
+        PkgMgrFrame[] allFrames = getAllFrames();
+
+        // If there are no frames open, yet...
+        if (allFrames.length < 1)
+            return null;
+
+        // Assume that the most recent is the first one. Not really the best
+        // thing to do...
+        PkgMgrFrame mostRecent = allFrames[0];
+
+        for (int i = 0; i < allFrames.length; i++)
+            if (allFrames[i].getFocusOwner() != null)
+                mostRecent = allFrames[i];
+
+        return mostRecent;
+    }
+
+    /**
+     * Handle a "display about dialog" request generated by the OS
+     */
+    public static void handleAbout()
+    {
+        HelpAboutAction.getInstance().actionPerformed(getMostRecent());
+    }
+    
+    /**
+     * Handle a "show preferences" request generated by the OS
+     */
+    public static void handlePreferences()
+    {
+        PreferencesAction.getInstance().actionPerformed(getMostRecent());
+    }
+    
+    /**
+     * Handle a quite request generated by the OS
+     */
+    public static void handleQuit()
+    {
+        QuitAction.getInstance().actionPerformed(getMostRecent());
+    }
+    
+    /**
+     * Check whether the status of the 'Show unit test tools' preference has
+     * changed, and if it has, show or hide them as requested.
+     */
+    public static void updateTestingStatus()
+    {
+        if (testToolsShown != wantToSeeTestingTools()) {
+            for (Iterator<PkgMgrFrame> i = frames.iterator(); i.hasNext();) {
+              
+                PkgMgrFrame pmf = i.next();
+                
+                //Testing tools are always hidden in Java ME packages.  
+                if ( pmf.isJavaMEpackage( ) ) {
+                    pmf.showTestingTools( false );
+                }
+                else {
+                    pmf.showTestingTools(!testToolsShown);               
+                }
+            }
+            testToolsShown = !testToolsShown;
+        }
+    }
+
+    /**
+     * Tell whether unit testing tools should be shown.
+     */
+    private static boolean wantToSeeTestingTools()
+    {
+        return PrefMgr.getFlag(PrefMgr.SHOW_TEST_TOOLS);
+    }
+    
+     /**
+     * Check whether the status of the 'Show teamwork tools' preference has
+     * changed, and if it has, show or hide them as requested.
+     */
+    public static void updateTeamStatus()
+    {
+        if (teamToolsShown != wantToSeeTeamTools()) {
+            for (Iterator<PkgMgrFrame> i = frames.iterator(); i.hasNext();) {
+                i.next().showTeamTools(!teamToolsShown);
+            }
+            teamToolsShown = !teamToolsShown;
+        }
+    }
+
+    /**
+     * Tell whether teamwork tools should be shown.
+     */
+    private static boolean wantToSeeTeamTools()
+    {
+        return PrefMgr.getFlag(PrefMgr.SHOW_TEAM_TOOLS);
+    }
+  
+     /**
+     * Check whether the status of the 'Show Java ME tools' preference has
+     * changed, and if it has, show or hide them as requested.
+     */
+    public static void updateJavaMEstatus()
+    {
+        if ( javaMEtoolsShown != wantToSeeJavaMEtools() )  {
+            for (Iterator<PkgMgrFrame> i = frames.iterator(); i.hasNext();) {
+                i.next().showJavaMEtools( !javaMEtoolsShown );
+            }
+            javaMEtoolsShown = !javaMEtoolsShown;
+        }
+    }
+    /**
+     * Tell whether Java ME tools should be shown.
+     */
+    private static boolean wantToSeeJavaMEtools()
+    {
+        return PrefMgr.getFlag( PrefMgr.SHOW_JAVAME_TOOLS );
+    }
+    
+    /**
+     * Display a short text message to the user. Without specifying a package,
+     * this is done by showing the message in the status bars of all open
+     * package windows.
+     */
+    public static void displayMessage(String message)
+    {
+        for (Iterator<PkgMgrFrame> i = frames.iterator(); i.hasNext();) {
+            PkgMgrFrame frame = i.next();
+            frame.setStatus(message);
+        }
+    }
+
+    /**
+     * Display a short text message in the frame of the specified package.
+     */
+    public static void displayMessage(Package sourcePkg, String message)
+    {
+        PkgMgrFrame pmf = findFrame(sourcePkg);
+
+        if (pmf != null)
+            pmf.setStatus(message);
+    }
+
+    /**
+     * Display a short text message in the frames of the specified project.
+     */
+    public static void displayMessage(Project sourceProj, String message)
+    {
+        PkgMgrFrame pmf[] = getAllProjectFrames(sourceProj);
+
+        if (pmf != null) {
+            for (int i = 0; i < pmf.length; i++) {
+                if (pmf[i] != null)
+                    pmf[i].setStatus(message);
+            }
+        }
+    }
+
+    /**
+     * Display an error message in a dialogue attached to the specified package
+     * frame.
+     */
+    public static void showError(Package sourcePkg, String msgId)
+    {
+        PkgMgrFrame pmf = findFrame(sourcePkg);
+
+        if (pmf != null)
+            DialogManager.showError(pmf, msgId);
+    }
+
+    /**
+     * Display a message in a dialogue attached to the specified package frame.
+     */
+    public static void showMessage(Package sourcePkg, String msgId)
+    {
+        PkgMgrFrame pmf = findFrame(sourcePkg);
+
+        if (pmf != null)
+            DialogManager.showMessage(pmf, msgId);
+    }
+
+    /**
+     * Display a parameterised message in a dialogue attached to the specified
+     * package frame.
+     */
+    public static void showMessageWithText(Package sourcePkg, String msgId, String text)
+    {
+        PkgMgrFrame pmf = findFrame(sourcePkg);
+
+        if (pmf != null)
+            DialogManager.showMessageWithText(pmf, msgId, text);
+    }
+
+
+    /**
+     * Create a new PkgMgrFrame which does not show a package.
+     * 
+     * This constructor can only be called via createFrame().
+     */
+    private PkgMgrFrame()
+    {
+        this.pkg = null;
+        this.editor = null;
+        objbench = new ObjectBench(this);
+        if(!Config.isGreenfoot()) {
+            teamActions = new TeamActionGroup(false);
+            teamActions.setAllDisabled();
+
+            setupActionDisableSet();
+            makeFrame();
+            updateWindowTitle();
+            setStatus(bluej.Boot.BLUEJ_VERSION_TITLE);
+        }
+    }
+
+    /**
+     * Displays the package in the frame for editing
+     */
+    public void openPackage(Package pkg)
+    {
+        if (pkg == null) {
+            throw new NullPointerException();
+        }
+
+        // if we are already editing a package, close it and
+        // open the new one
+        if (this.pkg != null) {
+            closePackage();
+        }
+
+        this.pkg = pkg;
+
+        if(! Config.isGreenfoot()) {
+            this.editor = new PackageEditor(pkg, this);
+            editor.setFocusable(true);
+            editor.setTransferHandler(new FileTransferHandler(this));
+            editor.addMouseListener(this); // This mouse listener MUST be before
+            editor.addFocusListener(this); //  the editor's listener itself!
+            editor.startMouseListening();
+            pkg.setEditor(this.editor);
+            
+            classScroller.setViewportView(editor);
+            
+            // fetch some properties from the package that interest us
+            Properties p = pkg.getLastSavedProperties();
+            
+            try {
+                String width_str = p.getProperty("package.editor.width", Integer.toString(DEFAULT_WIDTH));
+                String height_str = p.getProperty("package.editor.height", Integer.toString(DEFAULT_HEIGHT));
+                
+                classScroller.setPreferredSize(new Dimension(Integer.parseInt(width_str), Integer.parseInt(height_str)));
+                
+                String x_str = p.getProperty("package.editor.x", "30");
+                String y_str = p.getProperty("package.editor.y", "30");
+                
+                int x = Integer.parseInt(x_str);
+                int y = Integer.parseInt(y_str);
+                
+                if (x > (Config.screenBounds.width - 80))
+                    x = Config.screenBounds.width - 80;
+                
+                if (y > (Config.screenBounds.height - 80))
+                    y = Config.screenBounds.height - 80;
+                
+                setLocation(x, y);
+            } catch (NumberFormatException e) {
+                Debug.reportError("Could not read preferred project screen position");
+            }
+            
+            String uses_str = p.getProperty("package.showUses", "true");
+            String extends_str = p.getProperty("package.showExtends", "true");
+            
+            showUsesMenuItem.setSelected(uses_str.equals("true"));
+            showExtendsMenuItem.setSelected(extends_str.equals("true"));
+            
+            updateShowUsesInPackage();
+            updateShowExtendsInPackage();
+            
+            pack();
+            editor.revalidate();
+            editor.requestFocus();
+            
+            enableFunctions(true); // changes menu items
+            updateWindowTitle();
+            setVisible(true);
+            
+            updateTextEvalBackground(isEmptyFrame());
+                    
+            this.toolsMenuManager.setAttachedObject(new ToolsMenuObject(pkg));
+            this.toolsMenuManager.addExtensionMenu(pkg.getProject());
+
+            this.viewMenuManager.setAttachedObject(new ViewMenuObject(pkg));
+            this.viewMenuManager.addExtensionMenu(pkg.getProject());
+        
+            teamActions = pkg.getProject().getTeamActions();
+            resetTeamActions();             
+           
+            // In Java-ME packages, we display Java-ME controls in the
+            // test panel. We are just using the real estate of the test panel.
+            // The rest of the testing tools (menus, etc) are always hidden.
+            if (getProject().isJavaMEProject()) {
+                showJavaMEcontrols(true);
+                showTestingTools(false);
+            }
+            else {
+                showTestingTools(wantToSeeTestingTools());
+            }                
+        }
+        
+        extMgr.packageOpened(pkg);
+    }
+    
+    /**
+     * Show or hide the Java ME controls.
+     */
+    private void showJavaMEcontrols(boolean show )
+    {           
+        javaMEdeployMenuItem.setVisible(show);
+        javaMEPanel.setVisible(show);              
+    }
+    
+    /**
+     * Deploy the MIDlet suite contained in this project.
+     */
+    public void doDeployMIDlet()
+    { 
+        MIDletDeployer deployer = new MIDletDeployer( this );
+        deployer.deploy( );
+    } 
+    
+    /**
+     * Set the team controls to use the team actions for the project.
+     */
+    private void resetTeamActions()
+    {
+        // The reason this is necessary is because team actions are tied to
+        // a project, not to a PkgMgrFrame. However, a PkgMgrFrame may be
+        // empty and not associated with a project - in that case it has its
+        // own TeamActionGroup. When a project is opened, the actions from
+        // the project then need to be associated with the appropriate controls.
+        
+        teamStatusButton.setAction(teamActions.getStatusAction());
+        updateButton.setAction(teamActions.getUpdateAction());
+        teamSettingsMenuItem.setAction(teamActions.getTeamSettingsAction());
+        commitButton.setAction(teamActions.getCommitCommentAction());
+        shareProjectMenuItem.setAction(teamActions.getImportAction());
+        statusMenuItem.setAction(teamActions.getStatusAction());
+        commitMenuItem.setAction(teamActions.getCommitCommentAction());
+        commitMenuItem.setText(Config.getString("team.menu.commit"));
+        updateMenuItem.setAction(teamActions.getUpdateAction());
+        updateMenuItem.setText(Config.getString("team.menu.update"));
+        showLogMenuItem.setAction(teamActions.getShowLogAction());
+    }
+
+    /**
+     * Closes the current package.
+     */
+    public void closePackage()
+    {
+        if (isEmptyFrame()) {
+            return;
+        }
+        
+        extMgr.packageClosing(pkg);
+
+        if(! Config.isGreenfoot()) {
+            classScroller.setViewportView(null);
+            classScroller.setBorder(Config.normalBorder);
+            editor.removeMouseListener(this);
+            editor.removeFocusListener(this);
+            this.toolsMenuManager.setAttachedObject(new ToolsMenuObject(pkg));
+            this.viewMenuManager.setAttachedObject(new ViewMenuObject(pkg));
+            
+            getObjectBench().removeAllObjects(getProject().getUniqueId());
+            clearTextEval();
+            updateTextEvalBackground(true);
+            showJavaMEcontrols(false);
+            showTestingTools(wantToSeeTestingTools());
+        }
+
+        getPackage().closeAllEditors();
+        
+        Project proj = getProject();
+
+        editor = null;
+        pkg = null;
+
+        // if there are no other frames editing this project, we close
+        // the project
+        if (PkgMgrFrame.getAllProjectFrames(proj) == null) {
+            Project.cleanUp(proj);
+        }
+    }
+
+    /**
+     * Override standard show to add de-iconify and bring-to-front.
+     */
+    @Override
+    public void setVisible(boolean visible)
+    {
+        if(!visible) {
+            super.setVisible(false);
+        }
+        else if (!Config.isGreenfoot()) {
+            super.setVisible(true);
+            setState(Frame.NORMAL);
+        }
+    }
+
+    /**
+     * Return the package shown by this frame.
+     * 
+     * This call should be bracketed by a call to isEmptyFrame() before use.
+     */
+    public Package getPackage()
+    {
+        return pkg;
+    }
+
+    /**
+     * Return the project of the package shown by this frame.
+     */
+    public Project getProject()
+    {
+        return pkg == null ? null : pkg.getProject();
+    }
+
+    /**
+     * Return true if this frame is currently editing a package. A call to this
+     * should bracket all uses of getPackage() and editor.
+     */
+    public boolean isEmptyFrame()
+    {
+        return pkg == null;
+    }
+
+    /**
+     * Set the window title to show the current package name.
+     */
+    protected final String updateWindowTitle()
+    {
+        if (isEmptyFrame()) {
+            setTitle("BlueJ");
+            return "BlueJ";
+        }
+        else {
+            String title = Config.getString("pkgmgr.title") + getProject().getProjectName();
+
+            if (!getPackage().isUnnamedPackage())
+                title = title + "  [" + getPackage().getQualifiedName() + "]";
+            
+            if(getProject().isTeamProject())
+                title = title + " (" + Config.getString("team.project.marker") + ")";
+
+            setTitle(title);
+            return title;
+        }
+    }
+
+    /**
+     * Display a message in the status bar of the frame
+     */
+    public final void setStatus(final String status)
+    {
+         EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                if (statusbar != null)
+                    statusbar.setText(status);
+            }
+        });
+        
+    }
+    
+       
+    /**
+     * Start the activity indicator. Call from any thread.
+     */
+    public void startProgress()
+    {
+        progressbar.setRunning(true);
+    }
+
+    /**
+     * Stop the activity indicator. Call from any thread.
+     */
+    public void stopProgress()
+    {
+        progressbar.setRunning(false);
+    }
+
+    /**
+     * Clear status bar of the frame
+     */
+    public void clearStatus()
+    {
+       EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                if (statusbar != null)
+                    statusbar.setText(" ");
+            }
+        });
+    }
+
+    /**
+     * Set the frames cursor to a WAIT_CURSOR while system is busy
+     */
+    public void setWaitCursor(boolean wait)
+    {
+        if (wait)
+            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+        else
+            setCursor(Cursor.getDefaultCursor());
+    }
+
+    /**
+     * Return the object bench.
+     */
+    public ObjectBench getObjectBench()
+    {
+        return objbench;
+    }
+
+    /**
+     * Return the Code Pad component.
+     */
+    public TextEvalArea getCodePad()
+    {
+        return textEvaluator;
+    }
+
+    public void mousePressed(MouseEvent evt)
+    {
+        clearStatus();
+    }
+
+    public void mouseReleased(MouseEvent evt)
+    {}
+
+    public void mouseClicked(MouseEvent evt)
+    {}
+
+    public void mouseEntered(MouseEvent evt)
+    {}
+
+    public void mouseExited(MouseEvent evt)
+    {}
+
+
+    /**
+     * The graph editor received keyboard focus.
+     */
+    public void focusGained(FocusEvent e)
+    {
+        classScroller.setBorder(Config.focusBorder);
+        editor.setHasFocus(true);
+    }
+
+    /**
+     * The graph editor lost keyboard focus.
+     */
+    public void focusLost(FocusEvent e)
+    {
+        if (!e.isTemporary()) {
+            classScroller.setBorder(Config.normalBorder);
+            editor.setHasFocus(false);
+        }
+    }
+
+
+    /**
+     * Deal with an event generated by a target in the package we are currently
+     * editing.
+     */
+    public void targetEvent(PackageEditorEvent e)
+    {
+        int evtId = e.getID();
+
+        switch(evtId) {
+            case PackageEditorEvent.TARGET_CALLABLE :
+                // user has initiated method call or constructor
+                callMethod(e.getCallable());
+                break;
+
+            case PackageEditorEvent.TARGET_REMOVE :
+                // user has initiated target "remove" option
+                ((Target) e.getSource()).remove();
+                break;
+
+            case PackageEditorEvent.TARGET_OPEN :
+                // user has initiated a package open operation
+                openPackageTarget(e.getName());
+                break;
+
+            case PackageEditorEvent.TARGET_RUN :
+                // user has initiated a run operation
+                ClassTarget ct = (ClassTarget) e.getSource();
+                ct.getRole().run(this, ct, e.getName());
+                break;
+
+            case PackageEditorEvent.TARGET_BENCHTOFIXTURE :
+                // put objects on object bench into fixtures
+                objectBenchToTestFixture((ClassTarget) e.getSource());
+                break;
+
+            case PackageEditorEvent.TARGET_FIXTURETOBENCH :
+                // put objects on object bench into fixtures
+                testFixtureToObjectBench((ClassTarget) e.getSource());
+                break;
+
+            case PackageEditorEvent.TARGET_MAKETESTCASE :
+                // start recording a new test case
+                makeTestCase((ClassTarget) e.getSource());
+                break;
+
+            case PackageEditorEvent.OBJECT_PUTONBENCH :
+                // "Get" object from object inspector
+                DebuggerObject gotObj = e.getDebuggerObject();
+
+                boolean tryAgain = true;
+                do {
+                    String newObjectName = DialogManager.askString((Component) e.getSource(), "getobject-new-name",
+                            getProject().getDebugger().guessNewName(gotObj));
+
+                    if (newObjectName == null) {
+                        tryAgain = false; // cancelled
+                    }
+                    else if (JavaNames.isIdentifier(newObjectName)) {
+                        putObjectOnBench(newObjectName, e.getDebuggerObject(), e.getIType(), e.getInvokerRecord());
+                        tryAgain = false;
+                    }
+                    else {
+                        DialogManager.showError((Component) e.getSource(), "must-be-identifier");
+                    }
+                } while (tryAgain);
+                break;
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.pkgmgr.PackageEditorListener#recordInteraction(bluej.testmgr.record.InvokerRecord)
+     */
+    public void recordInteraction(InvokerRecord ir)
+    {
+        getObjectBench().addInteraction(ir);
+    }
+    
+    /**
+     * Gets the current test identifier (used to identify tests during the data recording)
+     */
+    public int getTestIdentifier()
+    {
+        return testIdentifier;
+    }
+
+
+    // --- below are implementations of particular user actions ---
+    // These are broken into "interactive" methods (which can display dialogs
+    // etc) and "non-interactive". In general interactive methods delegate to
+    // the non-interactive variants.
+
+    // --- non-interactive methods ---
+    
+    /**
+     * Create a new project and display it in a frame.
+     * @param dirName           The directory to create the project in
+     * @param isJavaMEproject   Whether to create a Java Micro Edition project
+     * @return     true if successful, false otherwise
+     */
+    public boolean newProject(String dirName, boolean isJavaMEproject )
+    {
+        if (Project.createNewProject(dirName, isJavaMEproject)) {
+            Project proj = Project.openProject(dirName, this);
+            
+            Package unNamedPkg = proj.getPackage("");
+            
+            if (isEmptyFrame()) {
+                openPackage( unNamedPkg );
+            }
+            else {
+                PkgMgrFrame pmf = createFrame( unNamedPkg );
+                DialogManager.tileWindow(pmf, this);
+                pmf.setVisible(true);
+            }    
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * Import a project from a directory into the current package. 
+     * @param dir               The directory to import
+     * @param showFailureDialog True to show a dialog with files which failed
+     *                          to copy
+     * @return An array of Files which failed to copy
+     */
+    public File[] importProjectDir(File dir, boolean showFailureDialog)
+    {
+        // recursively copy files from import directory to package directory
+        File[] fails = FileUtility.recursiveCopyFile(dir, getPackage().getPath());
+
+        // if we have any files which failed the copy, we show them now
+        if (fails != null && showFailureDialog) {
+            JDialog importFailedDlg = new ImportFailedDialog(this, fails);
+            importFailedDlg.setVisible(true);
+        }
+
+        // add bluej.pkg files through the imported directory structure
+        List<File> dirsToConvert = Import.findInterestingDirectories(getPackage().getPath());
+        Import.convertDirectory(dirsToConvert);
+
+        // reload all the packages (which discovers classes which may have
+        // been added by the import)
+        getProject().reloadAll();
+        
+        return fails;
+    }
+    
+    /**
+     * Creates a new class using the given name and template
+     * 
+     * @param name
+     *            is not a fully qualified class name
+     * @param template
+     *            can be null in this case no template will be generated
+     * @param showErr
+     *            true if a "duplicate name" dialog should be shown if
+     *            the named class already exists
+     * @return  true if successful, false is the named class already exists
+     */
+    public boolean createNewClass(String name, String template, boolean showErr)
+    {
+        // check whether name is already used
+        if (pkg.getTarget(name) != null) {
+            DialogManager.showError(this, "duplicate-name");
+            return false;
+        }
+
+        //check if there already exists a class in a library with that name 
+        String[] conflict=new String[1];
+        Class<?> c = pkg.loadClass(pkg.getQualifiedName(name));
+        if (c != null){
+            if (! Package.checkClassMatchesFile(c, new File(getPackage().getPath(), name + ".class"))) {
+                conflict[0]=Package.getResourcePath(c);
+                if (DialogManager.askQuestion(this, "class-library-conflict", conflict) == 0) {
+                    return false;
+                }
+            }
+        }
+
+        ClassTarget target = null;
+        target = new ClassTarget(pkg, name, template);
+
+        if ( template != null ) { 
+            boolean success = target.generateSkeleton(template);
+            if (! success)
+                return false;
+        }
+
+        pkg.findSpaceForVertex(target);
+        pkg.addTarget(target);
+
+        if (editor != null) {
+            editor.revalidate();
+            editor.scrollRectToVisible(target.getRectangle());
+            editor.repaint();
+        }
+
+        if (target.getRole() instanceof UnitTestClassRole) {
+            pkg.compileQuiet(target);
+        }
+        
+        return true;
+    }
+
+    // --- interactive methods ---
+    
+    /**
+     * Allow the user to select a directory into which we create a project.
+     * @param isJavaMEproject   Whether this is a Java Micro Edition project or not.
+     * @return true if the project was successfully created. False otherwise.
+     */
+    public boolean doNewProject( boolean isJavaMEproject )
+    {
+        String title = Config.getString( "pkgmgr.newPkg.title" );
+        if ( isJavaMEproject )
+            title = Config.getString( "pkgmgr.newMEpkg.title" );
+                    
+        File newnameFile = FileUtility.getDirName( this, title,
+                 Config.getString( "pkgmgr.newPkg.buttonLabel" ), false, true );
+
+        if (newnameFile == null)
+            return false;
+
+        if(newnameFile.exists()) {
+            Debug.message("Attempt to create project with existing directory: " + newnameFile.getAbsolutePath());
+            DialogManager.showErrorWithText(null, "directory-exists", newnameFile.getPath());
+            return false;
+        }
+        else if( ! newProject( newnameFile.getAbsolutePath(), isJavaMEproject ) ) {
+            DialogManager.showErrorWithText(null, "cannot-create-directory", newnameFile.getPath());
+            return false;
+        }
+
+        return true;
+    }
+   
+    /**
+     * Opens either a project from a directory or an archive.
+     * 
+     * @param pmf Optional parameter. Used for displaying dialogs and reuse
+     *            if it is the empty frame.
+     */
+    public static boolean doOpen(File projectPath, PkgMgrFrame pmf)
+    {     
+        boolean createdNewFrame = false;
+        if(pmf == null && PkgMgrFrame.frames.size() > 0) {
+            pmf = PkgMgrFrame.frames.get(0);
+        }
+        else if(pmf == null) {
+            pmf = PkgMgrFrame.createFrame();
+            createdNewFrame = true;
+        }
+
+        boolean openedProject = false;
+        if (projectPath != null) {
+            if (projectPath.isDirectory() || Project.isProject(projectPath.toString())) {
+                if(pmf.openProject(projectPath.getAbsolutePath())) {
+                    openedProject = true;
+                }
+            }
+            else {
+                if(pmf.openArchive(projectPath)) {
+                    openedProject = true;
+                }
+            }
+        }
+        if(createdNewFrame && !openedProject) {
+            // Close newly created frame if it was never used.
+            PkgMgrFrame.closeFrame(pmf);
+        }
+        return openedProject;
+    }
+    
+    /**
+     * Open a dialog that lets the user choose a project. The project selected
+     * is opened in a frame.
+     */
+    public void doOpen()
+    {
+        File dirName = FileUtility.getPackageName(this);
+        PkgMgrFrame.doOpen(dirName, this);
+    }
+
+    /**
+     * Open the project specified by 'projectPath'. Return false if not
+     * successful. Displays a warning dialog if the opened project resides in
+     * a read-only directory.
+     */
+    private boolean openProject(String projectPath)
+    {
+        Project openProj = Project.openProject(projectPath, this);
+        if (openProj == null)
+            return false;
+        else {
+            Package initialPkg = openProj.getPackage(openProj.getInitialPackageName());
+
+            PkgMgrFrame pmf = findFrame(initialPkg);
+
+            if (pmf == null) {
+                if (isEmptyFrame()) {
+                    pmf = this;
+                    openPackage(initialPkg);
+                }
+                else {
+                    pmf = createFrame(initialPkg);
+
+                    DialogManager.tileWindow(pmf, this);
+                }
+            }
+
+            pmf.setVisible(true);
+
+            return true;
+        }
+    }
+
+    /**
+     * Open a dialog that lets a user convert existing Java source into a BlueJ
+     * project.
+     * 
+     * The project selected is opened in a frame.
+     */
+    public void doOpenNonBlueJ()
+    {
+        File dirName = FileUtility.getNonBlueJDirectoryName(this);
+
+        if (dirName == null)
+            return;
+
+        File absDirName = dirName.getAbsoluteFile();
+        
+        // First confirm the chosen file exists
+        if (! absDirName.exists()) {
+            // file doesn't exist
+            DialogManager.showError(this, "file-does-not-exist");
+            return;
+        }
+        
+        if (absDirName.isDirectory()) {
+            // Check to make sure it's not already a project
+            if (Project.isProject(absDirName.getPath())) {
+                DialogManager.showError(this, "open-non-bluej-already-bluej");
+                return;
+            }
+            
+            // Try and convert it to a project
+            if (! Import.convertNonBlueJ(this, absDirName))
+                return;
+            
+            // then construct it as a project
+            openProject(absDirName.getPath());
+        }
+        else {
+            // Presumably it's an archive file
+            openArchive(absDirName);
+        }
+    }
+
+    /**
+     * Open an archive file (jar or same contents with other extensions) as a
+     * BlueJ project. The file contents are extracted, the containing directory
+     * is then converted into a BlueJ project if necessary, and opened.
+     */
+    private boolean openArchive(File archive)
+    {
+        // Determine the output path.
+        File oPath = Utility.maybeExtractArchive(archive, this);
+        
+        if (oPath == null)
+            return false;
+        
+        if (Project.isProject(oPath.getPath())) {
+            return openProject(oPath.getPath());
+        }
+        else {
+            // Convert to a BlueJ project
+            if (Import.convertNonBlueJ(this, oPath)) {
+                return openProject(oPath.getPath());
+            }
+            else {
+                return false;
+            }
+        }        
+    }
+
+    /**
+     * Close all frames which show packages from the specified project. This
+     * causes the project itself to close.
+     */
+    public static void closeProject(Project project) 
+    {
+        PkgMgrFrame[] allFrames = getAllProjectFrames(project);
+
+        if (allFrames != null) {
+            for (int i = 0; i < allFrames.length; i++) {
+                allFrames[i].doClose(true, true);
+            }
+        }
+    }
+    
+    /**
+     * Perform a user initiated close of this frame/package.
+     * 
+     * There are two different methods for the user to initiate a close. One is
+     * through the "Close" menu item and the other is with the windows close
+     * button. We want slightly different behaviour for these two cases.
+     */
+    public void doClose(boolean keepLastFrame, boolean doSave)
+    {
+        if (doSave) {
+            doSave();
+        }
+
+        // If only one frame and this was from the menu
+        // "close", close should close existing package rather
+        // than remove frame
+
+        if (frameCount() == 1) {
+            if (keepLastFrame && !Config.isGreenfoot()) { // close package, leave frame, but not for greenfoot
+                testRecordingEnded(); // disable test controls
+                closePackage();
+                
+                updateWindowTitle();
+                updateRecentProjects();
+                enableFunctions(false); // changes menu items
+                updateWindowTitle();
+                toolsMenuManager.addExtensionMenu(null);
+                viewMenuManager.addExtensionMenu(null);
+            }
+            else { // all frames gone, lets quit
+                bluej.Main.doQuit();
+            }
+        }
+        else {
+            closePackage(); // remove package and frame
+            PkgMgrFrame.closeFrame(this);
+        }
+    }
+
+    /**
+     * Save this package. Don't ask questions - just do it.
+     */
+    public void doSave()
+    {
+        if (isEmptyFrame()) {
+            return;
+        }
+        
+        // store the current editor size in the bluej.pkg file
+        Properties p;
+        if (pkg.isUnnamedPackage()) {
+            // The unnamed package also contains project properties
+            p = getProject().getProjectProperties();
+        }
+        else {
+            p = new Properties();
+        }
+        
+        if(!Config.isGreenfoot()) {
+            Dimension d = classScroller.getSize(null);
+    
+            p.put("package.editor.width", Integer.toString(d.width));
+            p.put("package.editor.height", Integer.toString(d.height));
+    
+            Point point = getLocation();
+    
+            p.put("package.editor.x", Integer.toString(point.x));
+            p.put("package.editor.y", Integer.toString(point.y));
+    
+            p.put("package.showUses", Boolean.toString(isShowUses()));
+            p.put("package.showExtends", Boolean.toString(isShowExtends()));
+        }
+        pkg.save(p);
+    }
+
+    /**
+     * Import into a new project or import into the current project.
+     */
+    public void doImport()
+    {
+        // prompt for the directory to import from
+        File importDir = FileUtility.getDirName(this, Config.getString("pkgmgr.importPkg.title"), Config
+                .getString("pkgmgr.importPkg.buttonLabel"), true, false);
+
+        if (importDir == null)
+            return;
+
+        if (!importDir.isDirectory())
+            return;
+
+        // if we are an empty then we shouldn't go on (we shouldn't get
+        // here)
+        if (isEmptyFrame())
+            return;
+
+        // recursively copy files from import directory to package directory
+        importProjectDir(importDir, true);
+    }
+    
+    /**
+     * Implementation of the "Add Class from File" user function
+     */
+    public void doAddFromFile()
+    {
+        // multi selection file dialog that shows .java and .class files
+        File[] classes = FileUtility.getMultipleFiles(this, Config.getString("pkgmgr.addClass.title"), Config
+                .getString("pkgmgr.addClass.buttonLabel"), FileUtility.getJavaSourceFilter());
+
+        if (classes == null)
+            return;
+        importFromFile(classes);
+    }
+        
+    
+    /**
+     * Add a given set of Java source files as classes to this package.
+     */
+    public void addFiles(List<File> classes)
+    {
+        importFromFile(classes.toArray(new File[classes.size()]));
+    }
+    
+    /**
+     * Add the given set of Java source files as classes to this package.
+     */
+    private void importFromFile(File[] classes)
+    {
+        // if there are errors this will potentially bring up multiple error
+        // dialogs
+        // these could be aggregated however the error messages may be different
+        // for each error
+        for (int i = 0; i < classes.length; i++) {
+            int result = pkg.importFile(classes[i]);
+
+            switch(result) {
+                case Package.NO_ERROR :
+                    // Have commented out repaint as it does not seem to be
+                    // needed
+                    //editor.repaint();
+                    break;
+                case Package.FILE_NOT_FOUND :
+                    DialogManager.showErrorWithText(this, "file-does-not-exist", classes[i].getName());
+                    break;
+                case Package.ILLEGAL_FORMAT :
+                    DialogManager.showErrorWithText(this, "cannot-import", classes[i].getName());
+                    break;
+                case Package.CLASS_EXISTS :
+                    DialogManager.showErrorWithText(this, "duplicate-name", classes[i].getName());
+                    break;
+                case Package.COPY_ERROR :
+                    DialogManager.showErrorWithText(this, "error-in-import", classes[i].getName());
+                    break;
+            }
+
+        }
+    }
+
+    /**
+     * Implementation of the "Export" user function
+     */
+    public void doExport()
+    {
+        if (exporter == null) {
+            exporter = new ExportManager(this);
+        }
+        exporter.export();
+    }
+
+    /**
+     * Creates a page setup dialog to alter page dimensions.
+     *  
+     */
+    public void doPageSetup()
+    {
+        PrinterJob job = PrinterJob.getPrinterJob();
+        PageFormat pfmt = job.pageDialog(getPageFormat());
+        setPageFormat(pfmt);
+    }
+
+    /**
+     * accessor method for PageFormat object that can be used by various
+     * printing subsystems eg. source code printing from editor
+     * 
+     * @return common PageFormat object representing page preferences
+     */
+    public static PageFormat getPageFormat()
+    {
+        if (pageFormat == null) {
+            pageFormat = PrinterJob.getPrinterJob().defaultPage();
+
+        }
+        //Important that this is set before the margins:
+        int orientation = Config.getPropInteger("bluej.printer.paper.orientation", pageFormat.getOrientation());
+        pageFormat.setOrientation(orientation);
+        
+        Paper paper = pageFormat.getPaper();
+        int x = Config.getPropInteger("bluej.printer.paper.x", 72);
+        int y = Config.getPropInteger("bluej.printer.paper.y", 72);
+        int width = Config.getPropInteger("bluej.printer.paper.width", (int)paper.getWidth() - 72 - x);
+        int height = Config.getPropInteger("bluej.printer.paper.height", (int)paper.getHeight() - 72 - y);
+        paper.setImageableArea(x, y, width, height);
+        //paper is a copy of pageFormat's paper, so we must use set again to make the changes:
+        pageFormat.setPaper(paper);
+        return pageFormat;
+    }
+
+    /**
+     * set method for printing PageFormat. Called by other elements that may
+     * manipulate pageformat, at this stage the source editor is the only
+     * component that does. The assumption is that the PageFormat should be
+     * uniform between all components that may want to send output to a printer.
+     * 
+     * @param page
+     *            the new PageFormat
+     */
+    public static void setPageFormat(PageFormat page)
+    {
+        pageFormat = page;
+        // We must get the measurements from the paper (which ignores orientation)
+        // rather than page format (which takes it into account) because ultimately
+        // we will use paper.setImageableArea to load the dimensions again
+        Paper paper = pageFormat.getPaper();
+        double x = paper.getImageableX();
+        double y = paper.getImageableY();
+        double width = paper.getImageableWidth();
+        double height = paper.getImageableHeight();
+        //The sizes are in points, so saving them as an integer should be precise enough:
+        Config.putPropInteger("bluej.printer.paper.x", (int)x);
+        Config.putPropInteger("bluej.printer.paper.y", (int)y);
+        Config.putPropInteger("bluej.printer.paper.width", (int)width);
+        Config.putPropInteger("bluej.printer.paper.height", (int)height);
+        int orientation = pageFormat.getOrientation();
+        Config.putPropInteger("bluej.printer.paper.orientation", orientation);
+
+    }
+
+    /**
+     * Implementation of the "print" user function
+     */
+    public void doPrint()
+    {
+        if (projectPrintDialog == null)
+            projectPrintDialog = new ProjectPrintDialog(this);
+
+        if (projectPrintDialog.display()) {
+            PackagePrintManager printManager = new PackagePrintManager(this.getPackage(), getPageFormat(),
+                    projectPrintDialog);
+            printManager.start();
+        }
+    }
+
+    /**
+     * Preferences menu was chosen.
+     */
+    public void showPreferences( )
+    {
+        PrefMgrDialog.showDialog();
+    }
+
+    /**
+     * About menu was chosen.
+     */
+    public void aboutBlueJ()
+    {
+        AboutBlue about = new AboutBlue(this, bluej.Boot.BLUEJ_VERSION);
+        about.setVisible(true);
+    }
+
+    /**
+     * Copyright menu item was chosen.
+     */
+    public void showCopyright()
+    {
+        JOptionPane.showMessageDialog(this, new String[]{
+                "BlueJ \u00a9 2000-2011 Michael K\u00F6lling, John Rosenberg.", " ",
+                Config.getString("menu.help.copyright.line1"), Config.getString("menu.help.copyright.line2"),
+                Config.getString("menu.help.copyright.line3"), Config.getString("menu.help.copyright.line4"),}, Config
+                .getString("menu.help.copyright.title"), JOptionPane.INFORMATION_MESSAGE);
+    }
+
+    /**
+     * Interactively call a class (ie static) method or a class constructor
+     */
+    private void callMethod(final CallableView cv)
+    {
+        ResultWatcher watcher = null;
+
+        if (cv instanceof ConstructorView) {
+            // if we are constructing an object, create a watcher that waits for
+            // completion of the call and then places the object on the object
+            // bench
+            watcher = new ResultWatcher() {
+                public void beginCompile()
+                {
+                    setWaitCursor(true);
+                    setStatus(Config.getString("pkgmgr.creating"));
+                }
+                
+                public void beginExecution(InvokerRecord ir)
+                {
+                    BlueJEvent.raiseEvent(BlueJEvent.METHOD_CALL, ir);
+                    setWaitCursor(false);
+                }
+                
+                public void putResult(DebuggerObject result, String name, InvokerRecord ir)
+                {
+                    ExecutionEvent executionEvent = new ExecutionEvent(pkg, cv.getClassName(), null);
+                    executionEvent.setParameters(cv.getParamTypes(false), ir.getArgumentValues());
+                    executionEvent.setResult(ExecutionEvent.NORMAL_EXIT);
+                    executionEvent.setResultObject(result);
+                    BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+                    
+                    getPackage().getProject().updateInspectors();
+                    setStatus(Config.getString("pkgmgr.createDone"));
+                    
+                    // this shouldn't ever happen!! (ajp 5/12/02)
+                    if ((name == null) || (name.length() == 0))
+                        name = "result";
+
+                    if (result != null) {
+                        ObjectWrapper wrapper = ObjectWrapper.getWrapper(PkgMgrFrame.this, getObjectBench(), result,
+                                result.getGenType(), name);
+                        getObjectBench().addObject(wrapper);
+
+                        getPackage().getDebugger().addObject(pkg.getId(), wrapper.getName(), result);
+
+                        getObjectBench().addInteraction(ir);
+                    }
+                    else {
+                        // This shouldn't happen, but let's play it safe.
+                    }
+                }
+
+                public void putError(String msg, InvokerRecord ir)
+                {
+                    setStatus("");
+                    setWaitCursor(false);
+                }
+                
+                public void putException(ExceptionDescription exception, InvokerRecord ir)
+                {
+                    ExecutionEvent executionEvent = new ExecutionEvent(pkg, cv.getClassName(), null);
+                    executionEvent.setParameters(cv.getParamTypes(false), ir.getArgumentValues());
+                    executionEvent.setResult(ExecutionEvent.EXCEPTION_EXIT);
+                    executionEvent.setException(exception);
+                    BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+                    
+                    setStatus("");
+                    getPackage().exceptionMessage(exception);
+                    getPackage().getProject().updateInspectors();
+                }
+                
+                public void putVMTerminated(InvokerRecord ir)
+                {
+                    ExecutionEvent executionEvent = new ExecutionEvent(pkg, cv.getClassName(), null);
+                    executionEvent.setParameters(cv.getParamTypes(false), ir.getArgumentValues());
+                    executionEvent.setResult(ExecutionEvent.TERMINATED_EXIT);
+                    BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+                    
+                    setStatus("");
+                }
+            };
+        }
+        else if (cv instanceof MethodView) {
+            final MethodView mv = (MethodView) cv;
+
+            // create a watcher
+            // that waits for completion of the call and then displays the
+            // result (or does nothing if void)
+            watcher = new ResultWatcher() {
+                private ExpressionInformation expressionInformation = new ExpressionInformation(mv, getName());
+
+                public void beginCompile()
+                {
+                    setWaitCursor(true);
+                    if (mv.isMain()) {
+                        getProject().removeClassLoader();
+                        getProject().newRemoteClassLoaderLeavingBreakpoints();
+                    }
+                }
+                
+                public void beginExecution(InvokerRecord ir)
+                {
+                    BlueJEvent.raiseEvent(BlueJEvent.METHOD_CALL, ir);
+                    setWaitCursor(false);
+                }
+                
+                public void putResult(DebuggerObject result, String name, InvokerRecord ir)
+                {
+                    ExecutionEvent executionEvent = new ExecutionEvent(pkg, cv.getClassName(), null);
+                    executionEvent.setMethodName(mv.getName());
+                    executionEvent.setParameters(cv.getParamTypes(false), ir.getArgumentValues());
+                    executionEvent.setResult(ExecutionEvent.NORMAL_EXIT);
+                    executionEvent.setResultObject(result);
+                    BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+                    
+                    getPackage().getProject().updateInspectors();
+                    expressionInformation.setArgumentValues(ir.getArgumentValues());
+                    getObjectBench().addInteraction(ir);
+
+                    // a void result returns a name of null
+                    if (name == null)
+                        return;
+
+                    //The result can be null when terminating the program while
+                    // at a breakpoint in a method that has a return value.
+                    if (result == null)
+                        return;
+
+                    getProject().getResultInspectorInstance(result, name, getPackage(), ir,
+                            expressionInformation, PkgMgrFrame.this);
+                }
+
+                public void putError(String msg, InvokerRecord ir)
+                {
+                    setWaitCursor(false);
+                }
+                
+                public void putException(ExceptionDescription exception, InvokerRecord ir)
+                {
+                    ExecutionEvent executionEvent = new ExecutionEvent(pkg, cv.getClassName(), null);
+                    executionEvent.setParameters(cv.getParamTypes(false), ir.getArgumentValues());
+                    executionEvent.setResult(ExecutionEvent.EXCEPTION_EXIT);
+                    executionEvent.setException(exception);
+                    BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+                    
+                    getPackage().getProject().updateInspectors();
+                    getPackage().exceptionMessage(exception);
+                }
+                
+                public void putVMTerminated(InvokerRecord ir)
+                {
+                    ExecutionEvent executionEvent = new ExecutionEvent(pkg, cv.getClassName(), null);
+                    executionEvent.setParameters(cv.getParamTypes(false), ir.getArgumentValues());
+                    executionEvent.setResult(ExecutionEvent.TERMINATED_EXIT);
+                    BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, executionEvent);
+                }
+            };
+        }
+
+        // create an Invoker to handle the actual invocation
+        if (checkDebuggerState()) {
+            new Invoker(this, cv, watcher).invokeInteractive();
+        }
+    }
+
+    /**
+     * Open a package target.
+     */
+    private void openPackageTarget(String newname)
+    {
+        PkgMgrFrame pmf;
+        Package p = getPackage().getProject().getPackage(newname);
+
+        if ((pmf = findFrame(p)) == null) {
+            pmf = createFrame(p);
+            DialogManager.tileWindow(pmf, this);
+        }
+        pmf.setVisible(true);
+    }
+
+    /**
+     * Create the text fixture method in the indicated target on from the
+     * current objects on the object bench.
+     */
+    private void objectBenchToTestFixture(ClassTarget target)
+    {
+        if (target.getRole() instanceof UnitTestClassRole) {
+            UnitTestClassRole utcr = (UnitTestClassRole) target.getRole();
+
+            utcr.doBenchToFixture(this, target);
+        }
+    }
+
+    /**
+     * Build the text fixture specified in the indicated target on the object
+     * bench.
+     */
+    private void testFixtureToObjectBench(ClassTarget target)
+    {
+        if (target.getRole() instanceof UnitTestClassRole) {
+            UnitTestClassRole utcr = (UnitTestClassRole) target.getRole();
+            utcr.doFixtureToBench(this, target);
+        }
+    }
+
+    /**
+     * Create a test method for the indicated target.
+     */
+    private void makeTestCase(ClassTarget target)
+    {
+        if (target.getRole() instanceof UnitTestClassRole) {
+            UnitTestClassRole utcr = (UnitTestClassRole) target.getRole();
+            if (!testToolsShown)
+                showTestingTools(true);
+            utcr.doMakeTestCase(this, target);
+        }
+    }
+
+
+    /**
+     * Place a given object onto the object bench. This is done by creating an object wrapper
+     * for the internal object, which can then be added to the bench.
+     * 
+     * @param newInstanceName  Name for the instance on the bench.
+     * @param object    The internal object to be placed.
+     * @param iType    The "interface type" of the object. This is the type of the object
+     *               for purposes of method calls etc if the actual type is inaccessible
+     *               (private to another package or class).
+     * @param ir    The invoker record (for recording interaction). May be null.
+     * @return The actual instance name (which might be different from parameter, if there was a name clash)
+     */
+    public String putObjectOnBench(String newInstanceName, DebuggerObject object, GenTypeClass iType, InvokerRecord ir)
+    {
+        if (!object.isNullObject()) {
+            ObjectWrapper wrapper = ObjectWrapper.getWrapper(this, getObjectBench(), object, iType, newInstanceName);
+            getObjectBench().addObject(wrapper); // might change name
+            newInstanceName = wrapper.getName();
+
+            // load the object into runtime scope
+            getPackage().getDebugger().addObject(pkg.getId(), newInstanceName, object);
+
+            if (ir != null) {
+                ir.setBenchName(newInstanceName, wrapper.getTypeName());
+            }
+            return newInstanceName;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    /**
+     * Implementation of the "New Class" user function.
+     */
+    public void doCreateNewClass()
+    {
+        NewClassDialog dlg = new NewClassDialog(this, isJavaMEpackage());
+        boolean okay = dlg.display();
+
+        if (okay) {
+            String name = dlg.getClassName();
+            String template = dlg.getTemplateName();
+
+            createNewClass(name, template, true);
+        }
+    }
+
+    /**
+     * Prompts the user with a dialog asking for the name of a package to
+     * create. Package name can be fully qualified in which case all
+     * intermediate packages will also be created as necessary.
+     */
+    public void doCreateNewPackage()
+    {
+        NewPackageDialog dlg = new NewPackageDialog(this);
+        boolean okay = dlg.display();
+        
+        if (!okay)
+            return;
+        
+        String name = dlg.getPackageName();
+
+        if (name.length() == 0)
+            return;
+
+        createNewPackage(name, true);
+    }
+    
+    /**
+     * Create a package. Package name can be fully qualified in which case all
+     * intermediate packages will also be created as necessary.
+     * 
+     * @param name    The name of the package to create
+     * @param showErrDialog   If true, and a duplicate name exists, a dialog
+     *                    will be displayed informing the user of the error.
+     * @return true if successful
+     */
+    public boolean createNewPackage(String name, boolean showErrDialog)
+    {
+        String fullName;
+
+        // if the name is fully qualified then we leave it as is but
+        // if it is not we assume they want to create a package in the
+        // current package
+        if (name.indexOf('.') > -1) {
+            fullName = name;
+        }
+        else {
+            fullName = getPackage().getQualifiedName(name);
+        }
+
+        // check whether name is already used for a class or package
+        // in the parent package
+        String prefix = JavaNames.getPrefix(fullName);
+        String base = JavaNames.getBase(fullName);
+
+        Package basePkg = getProject().getPackage(prefix);
+        if (basePkg != null) {
+            if (basePkg.getTarget(base) != null) {
+                if (showErrDialog)
+                    DialogManager.showError(this, "duplicate-name");
+                return false;
+            }
+        }
+
+        getProject().createPackageDirectory(fullName);
+
+        // check that everything has gone well and instruct all affected
+        // packages to reload (to make them notice the new sub packages)
+        Package newPackage = getProject().getPackage(fullName);
+
+        if (newPackage == null) {
+            Debug.reportError("creation of new package failed unexpectedly");
+            // TODO propagate a more informative exception
+            return false;
+        }
+        
+        newPackage = newPackage.getParent();
+        while (newPackage != null) {
+            newPackage.reload();
+            newPackage = newPackage.getParent();
+        }
+        
+        return true;
+    }
+
+    /**
+     * Remove the selected targets. Ask before deletion. If nothing is selected
+     * display an errormessage.
+     */
+    public void doRemove()
+    {
+        Component permanentFocusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
+        if (permanentFocusOwner == editor) { // focus in diagram
+            if (!(doRemoveTargets() || doRemoveDependency())) {
+                DialogManager.showError(this, "no-class-selected");
+            }
+        }
+        else if (permanentFocusOwner == objbench) { // focus in object bench
+            objbench.removeSelectedObject(pkg.getId());
+        }
+        else {
+            // ignore the command - focus is probably in text eval area
+        }
+    }
+
+    private boolean doRemoveTargets()
+    {
+        Target[] targets = pkg.getSelectedTargets();
+        if (targets.length <= 0) {
+            return false;
+        }
+        if (askRemoveClass()) {
+            for (int i = 0; i < targets.length; i++) {
+                targets[i].remove();
+            }
+        }
+        return true;
+    }
+
+    private boolean doRemoveDependency()
+    {
+        Dependency dependency = pkg.getSelectedDependency();
+        if (dependency == null) {
+            return false;
+        }
+        dependency.remove();
+        return true;
+    }
+
+    /**
+     * The user function to add a uses arrow to the diagram was invoked.
+     */
+    public void doNewUses()
+    {
+        pkg.setState(Package.S_CHOOSE_USES_FROM);
+        setStatus(Config.getString("pkgmgr.chooseUsesFrom"));
+        pkg.getEditor().clearSelection();
+    }
+
+    /**
+     * The user function to add an inherits arrow to the dagram was invoked.
+     */
+    public void doNewInherits()
+    {
+        pkg.setState(Package.S_CHOOSE_EXT_FROM);
+        setStatus(Config.getString("pkgmgr.chooseInhFrom"));
+        editor.clearSelection();
+    }
+
+    /**
+     * The user function to remove an arrow from the dagram was invoked.
+     * 
+     * public void doRemoveArrow() { pkg.setState(Package.S_DELARROW);
+     * setStatus(Config.getString("pkgmgr.chooseArrow")); }
+     */
+
+    /**
+     * The user function to test all classes in a package
+     */
+    public void doTest()
+    {
+        runButton.setEnabled(false);
+
+        List<ClassTarget> l = pkg.getTestTargets();
+
+        // Find the number of tests
+        int numTests = 0;
+        ListIterator<ClassTarget> i = l.listIterator();
+        while (i.hasNext()) {
+            ClassTarget ct = i.next();
+            if (ct.isCompiled() && ! ct.isAbstract()) {
+                UnitTestClassRole utcr = (UnitTestClassRole) ct.getRole();
+                numTests += utcr.getTestCount(ct);
+            }
+            else {
+                i.remove();
+            }
+        }
+        
+        Iterator<ClassTarget> it = l.iterator();
+        TestDisplayFrame.getTestDisplay().startMultipleTests(numTests);
+
+        TestRunnerThread trt = new TestRunnerThread(this, it);
+        trt.start();
+    }
+    
+    /**
+     * Called by the test runner thread when the test run has finished.
+     * Re-enables the "run all tests" button.
+     */
+    public void endTestRun()
+    {
+        TestDisplayFrame.getTestDisplay().endMultipleTests();
+        runButton.setEnabled(true);
+    }
+
+    /**
+     * The 'end test recording' button was clicked - end the recording.
+     */
+    public void doEndTest()
+    {
+        if (testTarget != null) {
+            testRecordingEnded();
+            
+            if (testTarget.getRole() instanceof UnitTestClassRole) {
+                UnitTestClassRole utcr = (UnitTestClassRole) testTarget.getRole();
+                
+                utcr.doEndMakeTestCase(this, testTarget, testTargetMethod);
+            }
+            
+            // try to compile the test class we have just changed. Do this before
+            // installing the new class loader, because that causes a short machine
+            // execution during which compilation fails with an error message
+            getPackage().compileQuiet(testTarget);
+
+            // remove objects from object bench
+            getProject().removeClassLoader();
+            getProject().newRemoteClassLoaderLeavingBreakpoints();
+            
+            testTarget = null;
+        }
+    }
+
+    /**
+     * The 'cancel test recording' button was clicked - cancel the recording.
+     */
+    public void doCancelTest()
+    {
+        testRecordingEnded();
+        
+        // remove objects from object bench (may have been put there
+        // when testing was started)
+        getProject().removeClassLoader();
+        getProject().newRemoteClassLoaderLeavingBreakpoints();
+
+        testTarget = null;
+    }
+
+    /**
+     * Recording of a test case started - set the interface appropriately.
+     */
+    public void testRecordingStarted(String message)
+    {
+        recordingLabel.setEnabled(true);
+        testStatusMessage.setText(message);
+        endTestButton.setEnabled(true);
+        endTestMenuItem.setEnabled(true);
+        cancelTestButton.setEnabled(true);
+        cancelTestMenuItem.setEnabled(true);
+
+        getProject().setTestMode(true);
+    }
+
+    /**
+     * Recording of a test case ended - set the interface appropriately.
+     */
+    private void testRecordingEnded()
+    {
+        recordingLabel.setEnabled(false);
+        testStatusMessage.setText("");
+        endTestButton.setEnabled(false);
+        endTestMenuItem.setEnabled(false);
+        cancelTestButton.setEnabled(false);
+        cancelTestMenuItem.setEnabled(false);
+
+        Project proj = getProject();
+        if (proj != null) {
+            proj.setTestMode(false);
+        }
+    }
+
+    /**
+     * Store information about the currently recorded test method.
+     */
+    public void setTestInfo(String testName, ClassTarget testClass)
+    {
+        this.testTargetMethod = testName;
+        this.testTarget = testClass;
+        this.testIdentifier = nextTestIdentifier.incrementAndGet(); // Allocate next test identifier
+    }
+
+    /**
+     * Ask the user to confirm removal of package.
+     * 
+     * @return zero if the user confirms removal.
+     */
+    public boolean askRemoveClass()
+    {
+        int response = DialogManager.askQuestion(this, "really-remove-class");
+        return response == 0;
+    }
+
+    /**
+     * Ask the system and the user to confirm removal of package. The system
+     * prevent the package from being removed if frames holding classes in the
+     * package is open.
+     * 
+     * @param removableTarget
+     * @return true if the package should be removed.
+     */
+    public boolean askRemovePackage(PackageTarget removableTarget)
+    {
+        String name = removableTarget.getQualifiedName();
+        PkgMgrFrame[] f = getAllProjectFrames(getProject(), name);
+
+        if (f != null) {
+            DialogManager.showError(this, "remove-package-open");
+            return false;
+        }
+
+        // Check they realise that this will delete ALL the files.
+        int response = DialogManager.askQuestion(this, "really-remove-package");
+
+        // if they agree
+        return response == 0;
+    }
+
+    /**
+     * Compile the currently selected class targets.
+     */
+    public void compileSelected()
+    {
+        Target[] targets = pkg.getSelectedTargets();
+        if (targets.length > 0) {
+            for (int i = 0; i < targets.length; i++) {
+                if (targets[i] instanceof ClassTarget) {
+                    ClassTarget t = (ClassTarget) targets[i];
+
+                    if (t.hasSourceCode())
+                        pkg.compile(t);
+                }
+            }
+        }
+        else {
+            DialogManager.showError(this, "no-class-selected-compile");
+        }
+    }
+
+    /**
+     * User function "Use Library Class...". Pop up the dialog that allows users
+     * to invoke library classes.
+     */
+    public void callLibraryClass()
+    {
+        if (libraryCallDialog == null)
+            libraryCallDialog = new LibraryCallDialog(this);
+        libraryCallDialog.setVisible(true);
+    }
+
+    /**
+     * User function "Generate Documentation...".
+     */
+    public void generateProjectDocumentation()
+    {
+        String message = pkg.generateDocumentation();
+        if (message.length() != 0) {
+            DialogManager.showText(this, message);
+        }
+    }
+
+    /**
+     * Check the debugger state is suitable for execution: that is, it is not already
+     * executing anything or stuck at a breakpoint.
+     * 
+     * <P>Returns true if the debugger is currently idle, or false if it is already
+     * executing, in which case an error dialog is also displayed and the debugger
+     * controls window is made visible.
+     */
+    public boolean checkDebuggerState()
+    {
+        Debugger debugger = getProject().getDebugger();
+        if (debugger.getStatus() == Debugger.SUSPENDED) {
+            setVisible(true);
+            DialogManager.showError(this, "stuck-at-breakpoint");
+            return false;
+        }
+        else if (debugger.getStatus() == Debugger.RUNNING) {
+            setVisible(true);
+            DialogManager.showError(this, "already-executing");
+            return false;
+        }
+        
+        return true;
+    }
+
+    /**
+     * Show the debugger controls for the VM associated with this project.
+     */
+    public void showDebugger()
+    {
+        if (!isEmptyFrame())
+            getProject().getExecControls().showHide(true);
+    }
+
+    /**
+     * Restart the debugger VM associated with this project.
+     */
+    public void restartDebugger()
+    {
+        if (!isEmptyFrame())
+        {
+            getProject().restartVM();
+        }
+    }
+
+    /**
+     * Toggle the state of the "show uses arrows" switch.
+     */
+    public void updateShowUsesInPackage()
+    {
+        pkg.setShowUses(isShowUses());
+        editor.repaint();
+    }
+
+    public void updateShowExtendsInPackage()
+    {
+        pkg.setShowExtends(isShowExtends());
+        editor.repaint();
+    }
+    
+    public boolean isShowUses()
+    {
+        return showUsesMenuItem.isSelected();
+    }
+
+    public boolean isShowExtends()
+    {
+        return showExtendsMenuItem.isSelected();
+    }
+    
+    /**
+     * Show or hide the testing tools.
+     */
+    public void showTestingTools(boolean show)
+    {
+        for (Iterator<JComponent> it = testItems.iterator(); it.hasNext();) {
+            JComponent component = it.next();
+            component.setVisible(show);
+        }
+    }
+    
+    /**
+     * Show or hide the teamwork tools.
+     */
+    public void showTeamTools(boolean show)
+    {
+        for (Iterator<JComponent> it = teamItems.iterator(); it.hasNext();) {
+            JComponent component = it.next();
+            component.setVisible(show);
+        }
+    }
+    
+    /**
+     * Show or hide the Java ME tools, which for now is just the
+     * 'New ME Project...' menu item in the Project menu.
+     * Java ME tools show or not in all packages--not only in
+     * Java ME packages--depending on whether the checkbox in 
+     * the Preferences panel is ticked or not.
+     */
+    public void showJavaMEtools( boolean show )
+    {
+        javaMEnewProjMenuItem.setVisible( show );
+    }
+
+    /**
+     * Notify the frame that the "shared" status of the project has changed,
+     * i.e. the project has become shared or unshared.
+     * 
+     * @param shared  The new shared status of the project
+     */
+    public void updateSharedStatus(boolean shared)
+    {
+        updateWindowTitle();
+    }
+    
+    /**
+     * Tell whether we are currently showing the text evaluation pane.
+     * 
+     * @return true if the text eval pane is visible.
+     */
+    public boolean isTextEvalVisible()
+    {
+        return showingTextEvaluator;
+    }
+
+    /**
+     * Show or hide the text evaluation component.
+     */
+    public void showHideTextEval(boolean show)
+    {
+        if (showingTextEvaluator == show) // already showing the right thing?
+            return;
+
+        if (show) {
+            addTextEvaluatorPane();
+            textEvaluator.requestFocus();
+        }
+        else {
+            removeTextEvaluatorPane();
+            editor.requestFocus();
+        }
+        pack();
+        showingTextEvaluator = show;
+    }
+
+    /**
+     * Clear the text evaluation component (if it exists).
+     */
+    public void clearTextEval()
+    {
+        if (textEvaluator != null) {
+            textEvaluator.clear();
+        }
+    }
+    
+    /**
+     * Updates the background of the text evaluation component (if it exists),
+     * when a project is opened/closed
+     */
+    public void updateTextEvalBackground(boolean emptyFrame)
+    {
+        if (textEvaluator != null) {
+            textEvaluator.updateBackground(emptyFrame);
+        }
+    }
+
+    // ---- BlueJEventListener interface ----
+    
+    /**
+     * A BlueJEvent was raised. Check whether it is one that we're interested
+     * in.
+     */
+    public void blueJEvent(int eventId, Object arg)
+    {
+        switch(eventId) {
+            case BlueJEvent.CREATE_VM :
+                setStatus(Config.getString("pkgmgr.creatingVM"));
+                break;
+            case BlueJEvent.CREATE_VM_DONE :
+                setStatus(Config.getString("pkgmgr.creatingVMDone"));
+                break;
+            case BlueJEvent.GENERATING_DOCU :
+                setStatus(Config.getString("pkgmgr.generatingDocu"));
+                break;
+            case BlueJEvent.DOCU_GENERATED :
+                setStatus(Config.getString("pkgmgr.docuGenerated"));
+                break;
+            case BlueJEvent.DOCU_ABORTED :
+                setStatus(Config.getString("pkgmgr.docuAborted"));
+                break;
+            case BlueJEvent.CREATE_VM_FAILED :
+                DialogManager.showError(this, "error-create-vm");
+                break;
+        }
+    }
+
+    // ---- end of BlueJEventListener interface ----
+
+    /**
+     * The debugger state has changed. Indicate the state in our interface and
+     * change the system state accordingly (e.g. enable/disable terminal).
+     * 
+     * NOTE: The current implementation assumes that user VMs DO NOT run
+     * concurrently!
+     */
+    public void setDebuggerState(int state)
+    {
+        switch(state) {
+            case Debugger.NOTREADY :
+            case Debugger.LAUNCH_FAILED:
+                break;
+
+            case Debugger.IDLE :
+                if(machineIcon != null) {
+                    machineIcon.setIdle();
+                }
+                getProject().getTerminal().activate(false);
+                break;
+
+            case Debugger.RUNNING :
+                if(machineIcon != null) {
+                    machineIcon.setRunning();
+                }
+                getProject().getTerminal().activate(true);
+                break;
+
+            case Debugger.SUSPENDED :
+                if(machineIcon != null) {
+                    machineIcon.setStopped();
+                }
+                break;
+        }
+    }
+
+    // --- general support functions for user function implementations ---
+
+    /**
+     * String representation for debugging only.
+     */
+    @Override
+    public String toString()
+    {
+        String str = "PkgMgrFrame(): ";
+
+        if (isEmptyFrame())
+            str += "empty";
+        else
+            str += getPackage().toString() + " " + getProject().toString();
+
+        return str;
+    }
+
+    /**
+     * showWebPage - show a page in a web browser and display a message in the
+     * status bar.
+     */
+    public void showWebPage(String url)
+    {
+        if (Utility.openWebBrowser(url))
+            setStatus(Config.getString("pkgmgr.webBrowserMsg"));
+        else
+            setStatus(Config.getString("pkgmgr.webBrowserError"));
+    }
+
+    // --- the following methods set up the GUI frame ---
+
+    private void makeFrame()
+    {
+        setFont(pkgMgrFont);
+        Image icon = BlueJTheme.getIconImage();
+        if (icon != null) {
+            setIconImage(icon);
+        }
+        testItems = new ArrayList<JComponent>();
+        teamItems = new ArrayList<JComponent>();
+
+        setupMenus();
+        
+        // To get a gradient fill for the frame, we need to override the content pane's
+        // paintComponent method to use a gradient fill (no other way to do it)
+        // Hence this code, that sets the content pane to be a standard JPanel with
+        // the same layout as before, but with paintComponent performing a gradient fill:
+        setContentPane(new GradientFillPanel(getContentPane().getLayout()));
+        // To let that gradient fill show through, all the other panes that sit
+        // on top of the frame must have setOpaque(false) called, hence all the calls
+        // of that type throughout the code below
+
+        Container contentPane = getContentPane();
+        ((JPanel) contentPane).setBorder(BlueJTheme.generalBorderWithStatusBar);
+
+        // create the main panel holding the diagram and toolbar on the left
+
+        JPanel mainPanel = new JPanel(new BorderLayout(5, 5));
+        mainPanel.setOpaque(false);
+
+        // Install keystroke to restart the VM
+        Action action = RestartVMAction.getInstance();
+        mainPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+                (KeyStroke) action.getValue(Action.ACCELERATOR_KEY), "restartVM");
+        mainPanel.getActionMap().put("restartVM", action);
+
+        // create the left hand side toolbar
+        JPanel toolPanel = new JPanel();
+        toolPanel.setOpaque(false);
+        {
+            buttonPanel = new JPanel();
+            buttonPanel.setOpaque(false);
+            {
+                buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
+                buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
+
+                AbstractButton button = createButton(newClassAction, false, false, 4, 4);
+                buttonPanel.add(button);
+                if(!Config.isMacOSLeopard()) buttonPanel.add(Box.createVerticalStrut(3));
+
+                imgDependsButton = createButton(newUsesAction, true, false, 4, 4);
+                buttonPanel.add(imgDependsButton);
+                if(!Config.isMacOSLeopard()) buttonPanel.add(Box.createVerticalStrut(3));
+
+                imgExtendsButton = createButton(newInheritsAction, true, false, 4, 4);
+                buttonPanel.add(imgExtendsButton);
+                if(!Config.isMacOSLeopard()) buttonPanel.add(Box.createVerticalStrut(3));
+
+                button = createButton(compileAction, false, false, 4, 4);
+                buttonPanel.add(button);
+                if(!Config.isMacOSLeopard()) buttonPanel.add(Box.createVerticalStrut(3));
+
+                buttonPanel.setAlignmentX(0.5f);
+            }
+
+            testPanel = new JPanel();
+            testPanel.setOpaque(false);
+            {
+                testPanel.setLayout(new BoxLayout(testPanel, BoxLayout.Y_AXIS));
+
+                testPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 14, 5));
+
+                runButton = createButton(runTestsAction, false, false, 2, 4);
+                runButton.setText(Config.getString("pkgmgr.test.run"));
+                runButton.setAlignmentX(0.15f);
+                testPanel.add(runButton);
+                testPanel.add(Box.createVerticalStrut(8));
+
+                recordingLabel = new JLabel(Config.getString("pkgmgr.test.record"), Config
+                        .getFixedImageAsIcon("record.gif"), SwingConstants.LEADING);
+                recordingLabel.setFont(pkgMgrFont);
+                recordingLabel.setEnabled(false);
+                recordingLabel.setAlignmentX(0.15f);
+                testPanel.add(recordingLabel);
+                testPanel.add(Box.createVerticalStrut(3));
+
+                action = EndTestRecordAction.getInstance();
+                endTestButton = createButton(action, false, false, 2, 4);
+                //make the button use a different label than the one from
+                // action
+                endTestButton.setText(Config.getString("pkgmgr.test.end"));
+                endTestButton.setEnabled(false);
+
+                testPanel.add(endTestButton);
+                if(!Config.isMacOSLeopard()) testPanel.add(Box.createVerticalStrut(3));
+
+                action = CancelTestRecordAction.getInstance();
+                cancelTestButton = createButton(action, false, false, 2, 4);
+                //make the button use a different label than the one from
+                // action
+                cancelTestButton.setText(Config.getString("cancel"));
+                cancelTestButton.setEnabled(false);
+
+                testPanel.add(cancelTestButton);
+
+                testPanel.setAlignmentX(0.5f);
+            }
+            testItems.add(testPanel);
+            
+            teamPanel = new JPanel();
+            teamPanel.setOpaque(false);
+            {
+                teamPanel.setLayout(new BoxLayout(teamPanel, BoxLayout.Y_AXIS));
+
+                teamPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 14, 5));
+                updateButton = createButton(teamActions.getUpdateAction(), false, false, 2, 4);                
+                updateButton.setAlignmentX(0.15f);
+                teamPanel.add(updateButton);
+                if(!Config.isMacOSLeopard()) teamPanel.add(Box.createVerticalStrut(3));
+                
+                commitButton = createButton(teamActions.getCommitCommentAction(), false, false, 2, 4);
+                commitButton.setAlignmentX(0.15f);
+                //make the button use a different label than the one from
+                // action
+                teamPanel.add(commitButton);
+                if(!Config.isMacOSLeopard()) teamPanel.add(Box.createVerticalStrut(3));
+
+                teamStatusButton = createButton(teamActions.getStatusAction(), false, false, 2, 4);
+                teamStatusButton.setAlignmentX(0.15f);
+                teamPanel.add(teamStatusButton);
+                if(!Config.isMacOSLeopard()) teamPanel.add(Box.createVerticalStrut(3));
+                teamPanel.setAlignmentX(0.5f);
+            }
+            teamItems.add(teamPanel);
+
+            javaMEPanel = new JPanel();
+            javaMEPanel.setOpaque(false);
+            {
+                javaMEPanel.setLayout(new BoxLayout(javaMEPanel, BoxLayout.Y_AXIS));
+
+                javaMEPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 14, 5));
+
+                JLabel label = new JLabel( "Java ME" );
+                label.setFont( new Font ("SansSerif", Font.BOLD, 12 ) );
+                label.setHorizontalAlignment( JLabel.CENTER );
+                label.setForeground( label.getBackground( ).darker( ).darker( ) ); 
+                Dimension pref = label.getMinimumSize();
+                pref.width = Integer.MAX_VALUE;
+                label.setMaximumSize(pref);
+                label.setAlignmentX(0.5f);
+                javaMEPanel.add( label );
+                javaMEPanel.add( Box.createVerticalStrut( 4 ) );   
+                
+                AbstractButton button = createButton( deployMIDletAction, false, false, 4, 4 );
+                button.setAlignmentX(0.5f);
+                javaMEPanel.add( button );
+                javaMEPanel.add( Box.createVerticalStrut( 4 ) );   
+                if(!Config.isMacOSLeopard()) javaMEPanel.add(Box.createVerticalStrut(3));
+                teamPanel.setAlignmentX(0.5f);
+            }
+            
+            machineIcon = new MachineIcon();
+            machineIcon.setAlignmentX(0.5f);
+            itemsToDisable.add(machineIcon);
+
+            toolPanel.setLayout(new BoxLayout(toolPanel, BoxLayout.Y_AXIS));
+            toolPanel.add(buttonPanel);
+            toolPanel.add(Box.createVerticalGlue());
+            toolPanel.add(teamPanel);
+            toolPanel.add(javaMEPanel);
+            toolPanel.add(testPanel);
+            toolPanel.add(machineIcon);
+        }
+        mainPanel.add(toolPanel, BorderLayout.WEST);
+
+        classScroller = new JScrollPane();
+        classScroller.setBorder(Config.normalBorder);
+        classScroller.setPreferredSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
+        classScroller.setSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
+        classScroller.setFocusable(false);
+        classScroller.getVerticalScrollBar().setUnitIncrement(10);
+        classScroller.getHorizontalScrollBar().setUnitIncrement(20);
+        classScroller.setOpaque(false);
+        mainPanel.add(classScroller, BorderLayout.CENTER);
+
+        itemsToDisable.add(objbench);
+
+        splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mainPanel, objbench);
+        splitPane.setBorder(null);
+        splitPane.setResizeWeight(1.0);
+        splitPane.setDividerSize(5);
+        splitPane.setOpaque(false);
+        contentPane.add(splitPane, BorderLayout.CENTER);
+
+        // create the bottom status area
+
+        JPanel statusArea = new JPanel(new BorderLayout());
+        statusArea.setOpaque(false);
+        {
+            statusArea.setBorder(BorderFactory.createEmptyBorder(2, 0, 4, 6));
+
+            statusbar = new JLabel(" ");
+            statusbar.setFont(pkgMgrFont);
+            statusArea.add(statusbar, BorderLayout.CENTER);
+
+            testStatusMessage = new JLabel(" ");
+            testStatusMessage.setFont(pkgMgrFont);
+            statusArea.add(testStatusMessage, BorderLayout.WEST);
+            
+            progressbar = new ActivityIndicator();
+            progressbar.setRunning(false);
+            statusArea.add(progressbar, BorderLayout.EAST);
+        }
+        contentPane.add(statusArea, BorderLayout.SOUTH);
+
+        // hide testing tools if not wanted
+        if (!testToolsShown) {
+            showTestingTools(false);
+        }
+
+        // hide team tools if not wanted
+        if (! teamToolsShown) {
+            showTeamTools(false);
+        }
+
+        // hide Java ME tools if not wanted
+        if (! javaMEtoolsShown) {
+            showJavaMEtools(false);
+        }
+        
+        javaMEPanel.setVisible(false);
+        
+        // show the text evaluation pane if needed
+        if (PrefMgr.getFlag(PrefMgr.SHOW_TEXT_EVAL)) {
+            addTextEvaluatorPane();
+        }
+
+        pack();
+
+        addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent E)
+            {
+                PkgMgrFrame pmf = (PkgMgrFrame) E.getWindow();
+                pmf.doClose(false, true);
+            }
+        });
+
+        // grey out certain functions if package not open.
+        if (isEmptyFrame()) {
+            enableFunctions(false);
+        }
+    }
+
+    /**
+     * Add the text evaluation pane in the lower area of the frame.
+     */
+    private void addTextEvaluatorPane()
+    {
+        classScroller.setPreferredSize(classScroller.getSize()); // memorize
+                                                                 // current size
+        if (textEvaluator == null) {
+            textEvaluator = new TextEvalArea(this, pkgMgrFont);
+            objectBenchSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, objbench, textEvaluator);
+            objectBenchSplitPane.setBorder(null);
+            objectBenchSplitPane.setResizeWeight(1.0);
+            objectBenchSplitPane.setDividerSize(5);
+            objectBenchSplitPane.setOpaque(false);
+            itemsToDisable.add(textEvaluator);
+        }
+        else {
+            objectBenchSplitPane.setLeftComponent(objbench);
+        }
+        splitPane.setBottomComponent(objectBenchSplitPane);
+        showingTextEvaluator = true;
+    }
+
+    /**
+     * Remove the text evaluation pane from the frame.
+     */
+    private void removeTextEvaluatorPane()
+    {
+        textEvaluator.setPreferredSize(textEvaluator.getSize()); // memorize
+                                                                 // current
+                                                                 // sizes
+        classScroller.setPreferredSize(classScroller.getSize());
+        splitPane.setBottomComponent(objbench);
+        showingTextEvaluator = false;
+    }
+
+    /**
+     * Create a button for the interface.
+     * 
+     * @param action
+     *            the Action abstraction dictating text, icon, tooltip, action.
+     * @param notext
+     *            set true if the action text should not appear (icon only).
+     * @param toggle
+     *            true if this is a toggle button, false otherwise
+     * @param hSpacing
+     *            horizontal margin (left, right)
+     * @param vSpacing
+     *            vertical margin (top, bottom)
+     * @return the new button
+     */
+    private AbstractButton createButton(Action action, boolean notext, boolean toggle, int hSpacing, int vSpacing)
+    {
+        AbstractButton button;
+        if (toggle) {
+            button = new JToggleButton(action);
+        }
+        else {
+            button = new JButton(action);
+        }
+        button.setFont(pkgMgrFont);
+        Utility.changeToMacButton(button);
+        button.setFocusable(false); // buttons shouldn't get focus
+
+        if (notext)
+            button.setText(null);
+
+        Dimension pref = button.getMinimumSize();
+        pref.width = Integer.MAX_VALUE;
+        button.setMaximumSize(pref);
+        if(!Config.isMacOSLeopard()) {
+            button.setMargin(new Insets(vSpacing, hSpacing, vSpacing, hSpacing));
+        }
+
+        return button;
+    }
+
+    /**
+     * setupMenus - Create the menu bar
+     */
+    private void setupMenus()
+    {
+        menubar = new JMenuBar();
+        itemsToDisable = new ArrayList<JComponent>();
+
+        JMenu menu = new JMenu(Config.getString("menu.package"));
+        int mnemonic = Config.getMnemonicKey("menu.package");
+        menu.setMnemonic(mnemonic);
+        menubar.add(menu);
+        {
+            createMenuItem(NewProjectAction.getInstance(), menu);
+            javaMEnewProjMenuItem = createMenuItem( NewMEprojectAction.getInstance(), menu );            
+            createMenuItem(OpenProjectAction.getInstance(), menu);
+            recentProjectsMenu = new JMenu(Config.getString("menu.package.openRecent"));
+            menu.add(recentProjectsMenu);
+            createMenuItem(OpenNonBlueJAction.getInstance(), menu);
+            createMenuItem(closeProjectAction, menu);
+            createMenuItem(saveProjectAction, menu);
+            createMenuItem(saveProjectAsAction, menu);
+            menu.addSeparator();
+
+            createMenuItem(importProjectAction, menu);
+            createMenuItem(exportProjectAction, menu);
+            javaMEdeployMenuItem = createMenuItem( deployMIDletAction, menu ); 
+            javaMEdeployMenuItem.setVisible( false ); //visible only in Java ME packages
+            menu.addSeparator();
+
+            createMenuItem(pageSetupAction, menu);
+            createMenuItem(printAction, menu);
+
+            if (!Config.usingMacScreenMenubar()) { // no "Quit" here for Mac
+                menu.addSeparator();
+                createMenuItem(QuitAction.getInstance(), menu);
+            }
+        }
+
+        menu = new JMenu(Config.getString("menu.edit"));
+        menu.setMnemonic(Config.getMnemonicKey("menu.edit"));
+        menubar.add(menu);
+        {
+            createMenuItem(newClassAction, menu);
+            createMenuItem(newPackageAction, menu);
+            createMenuItem(addClassAction, menu);
+            createMenuItem(removeAction, menu);
+            menu.addSeparator();
+
+            createMenuItem(newUsesAction, menu);
+            createMenuItem(newInheritsAction, menu);
+        }
+
+        menu = new JMenu(Config.getString("menu.tools"));
+        menu.setMnemonic(Config.getMnemonicKey("menu.tools"));
+        menubar.add(menu);
+        {
+            createMenuItem(compileAction, menu);
+            createMenuItem(compileSelectedAction, menu);
+            createMenuItem(rebuildAction, menu);
+            createMenuItem(restartVMAction, menu);
+            menu.addSeparator();
+
+            createMenuItem(useLibraryAction, menu);
+            createMenuItem(generateDocsAction, menu);
+
+            testingMenu = new JMenu(Config.getString("menu.tools.testing"));
+            testingMenu.setMnemonic(Config.getMnemonicKey("menu.tools"));
+            {
+                createMenuItem(runTestsAction, testingMenu);
+                endTestMenuItem = createMenuItem(EndTestRecordAction.getInstance(), testingMenu);
+                cancelTestMenuItem = createMenuItem(CancelTestRecordAction.getInstance(), testingMenu);
+                endTestMenuItem.setEnabled(false);
+                cancelTestMenuItem.setEnabled(false);
+            }
+            testItems.add(testingMenu);
+            menu.add(testingMenu);
+            
+            //team menu setup
+            teamMenu = new JMenu(Config.getString("menu.tools.teamwork"));
+            teamMenu.setMnemonic(Config.getMnemonicKey("menu.tools"));
+            {
+                Action checkoutAction = CheckoutAction.getInstance();
+                createMenuItem(checkoutAction , teamMenu);
+                shareProjectMenuItem = createMenuItem(teamActions.getImportAction(), teamMenu);               
+                
+                teamMenu.addSeparator();
+                
+                updateMenuItem = createMenuItem(teamActions.getUpdateAction(), teamMenu);
+                updateMenuItem.setText(Config.getString("team.menu.update"));
+                commitMenuItem = createMenuItem(teamActions.getCommitCommentAction(), teamMenu);
+                commitMenuItem.setText(Config.getString("team.menu.commit"));
+                statusMenuItem = createMenuItem(teamActions.getStatusAction(), teamMenu);
+                showLogMenuItem = createMenuItem(teamActions.getShowLogAction(), teamMenu);
+                
+                teamMenu.addSeparator();
+                
+                teamSettingsMenuItem = createMenuItem(teamActions.getTeamSettingsAction(), teamMenu);
+            }
+            teamItems.add(teamMenu);
+            menu.add(teamMenu);
+
+            if (!Config.usingMacScreenMenubar()) { // no "Preferences" here for
+                                                   // Mac
+                menu.addSeparator();
+                createMenuItem(PreferencesAction.getInstance(), menu);
+            }
+
+            // Create the menu manager that looks after extension tools menus
+            toolsMenuManager = new MenuManager(menu.getPopupMenu());
+
+            // If this is the first frame create the extension tools menu now.
+            // (Otherwise, it will be created during project open.)
+            if (frames.size() <= 1)
+                toolsMenuManager.addExtensionMenu(null);
+        }
+
+        menu = new JMenu(Config.getString("menu.view"));
+        menu.setMnemonic(Config.getMnemonicKey("menu.view"));
+        menubar.add(menu);
+        {
+            showUsesMenuItem = createCheckboxMenuItem(showUsesAction, menu, true);
+            showExtendsMenuItem = createCheckboxMenuItem(showInheritsAction, menu, true);
+            menu.addSeparator();
+
+            createCheckboxMenuItem(showDebuggerAction, menu, false);
+            createCheckboxMenuItem(showTerminalAction, menu, false);
+            createCheckboxMenuItem(showTextEvalAction, menu, false);
+            JSeparator testSeparator = new JSeparator();
+            testItems.add(testSeparator);
+            menu.add(testSeparator);
+
+            showTestResultsItem = createCheckboxMenuItem(ShowTestResultsAction.getInstance(), menu, false);
+            testItems.add(showTestResultsItem);
+
+            // Create the menu manager that looks after extension view menus
+            viewMenuManager = new MenuManager(menu.getPopupMenu());
+
+            // If this is the first frame create the extension view menu now.
+            // (Otherwise, it will be created during project open.)
+            if (frames.size() <= 1) {
+                viewMenuManager.addExtensionMenu(null);
+            }
+        }
+
+        menu = new JMenu(Config.getString("menu.help"));
+        menu.setMnemonic(Config.getMnemonicKey("menu.help"));
+        menubar.add(menu);
+        {
+            if (!Config.usingMacScreenMenubar()) { // no "About" here for Mac
+                createMenuItem(HelpAboutAction.getInstance(), menu);
+            }
+            createMenuItem(CheckVersionAction.getInstance(), menu);
+            createMenuItem(CheckExtensionsAction.getInstance(), menu);
+            createMenuItem(ShowCopyrightAction.getInstance(), menu);
+            menu.addSeparator();
+
+            createMenuItem(WebsiteAction.getInstance(), menu);
+            createMenuItem(TutorialAction.getInstance(), menu);
+            createMenuItem(StandardAPIHelpAction.getInstance(), menu);
+        }
+        addUserHelpItems(menu);
+        updateRecentProjects();
+
+        setJMenuBar(menubar);
+    }
+
+    /**
+     * Add a new menu item to a menu.
+     */
+    private JMenuItem createMenuItem(Action action, JMenu menu)
+    {
+        JMenuItem item = menu.add(action);
+        item.setIcon(null);
+        return item;
+    }
+
+    /**
+     * Add a new menu item to a menu.
+     */
+    private JCheckBoxMenuItem createCheckboxMenuItem(PkgMgrAction action, JMenu menu, boolean selected)
+    {
+        ButtonModel bmodel = action.getToggleModel(this);
+
+        JCheckBoxMenuItem item = new JCheckBoxMenuItem(action);
+        if (bmodel != null)
+            item.setModel(action.getToggleModel(this));
+        else
+            item.setState(selected);
+        menu.add(item);
+        return item;
+    }
+
+    /**
+     * Return the menu tool bar.
+     * 
+     * public JMenu getToolsMenu() { return toolsMenu; }
+     * 
+     * /** Add or remove a separator in the tools menu for extensions as needed.
+     * To be deleted, Damiano public void toolsExtensionsCheckSeparator() {
+     * if(extMgr.haveMenuItems( )) { // do we need one? if
+     * (toolsExtensionsSeparatorIndex > 0) // have one already return;
+     * 
+     * toolsExtensionsSeparatorIndex = toolsMenu.getItemCount();
+     * toolsMenu.addSeparator(); } else { // don't need one if
+     * (toolsExtensionsSeparatorIndex <= 0) // don't have one return;
+     * 
+     * toolsMenu.remove(toolsExtensionsSeparatorIndex);
+     * toolsExtensionsSeparatorIndex = 0; } }
+     */
+
+    /**
+     * Called on (almost) every menu invocation to clean up.
+     */
+    public void menuCall()
+    {
+        if (!isEmptyFrame())
+            pkg.setState(Package.S_IDLE);
+        clearStatus();
+    }
+
+    /**
+     * Define which actions are to be disabled when no project is open
+     */
+    private void setupActionDisableSet()
+    {
+        actionsToDisable = new ArrayList<Action>();
+        actionsToDisable.add(closeProjectAction);
+        actionsToDisable.add(saveProjectAction);
+        actionsToDisable.add(saveProjectAsAction);
+        actionsToDisable.add(importProjectAction);
+        actionsToDisable.add(exportProjectAction);
+        actionsToDisable.add(pageSetupAction);
+        actionsToDisable.add(printAction);
+        actionsToDisable.add(newClassAction);
+        actionsToDisable.add(newPackageAction);
+        actionsToDisable.add(addClassAction);
+        actionsToDisable.add(removeAction);
+        actionsToDisable.add(newUsesAction);
+        actionsToDisable.add(newInheritsAction);
+        actionsToDisable.add(compileAction);
+        actionsToDisable.add(compileSelectedAction);
+        actionsToDisable.add(rebuildAction);
+        actionsToDisable.add(restartVMAction);
+        actionsToDisable.add(useLibraryAction);
+        actionsToDisable.add(generateDocsAction);
+        actionsToDisable.add(showUsesAction);
+        actionsToDisable.add(showInheritsAction);
+        actionsToDisable.add(showDebuggerAction);
+        actionsToDisable.add(showTerminalAction);
+        actionsToDisable.add(showTextEvalAction);
+        actionsToDisable.add(runTestsAction);
+    }
+
+    /**
+     * Add user defined help menus. Users can add help menus via the
+     * bluej.help.items property. See comment in bluej.defs.
+     */
+    private void addUserHelpItems(JMenu menu)
+    {
+        String helpItems = Config.getPropString("bluej.help.items", "");
+
+        if (helpItems != null && helpItems.length() > 0) {
+            menu.addSeparator();
+            URLDisplayer urlDisplayer = new URLDisplayer();
+
+            StringTokenizer t = new StringTokenizer(helpItems);
+
+            while (t.hasMoreTokens()) {
+                String itemID = t.nextToken();
+                String itemName = Config.getPropString("bluej.help." + itemID + ".label");
+                String itemURL = Config.getPropString("bluej.help." + itemID + ".url");
+                JMenuItem item = new JMenuItem(itemName);
+                item.setActionCommand(itemURL);
+                item.addActionListener(urlDisplayer);
+                menu.add(item);
+            }
+        }
+    }
+
+    /**
+     * Update the 'Open Recent' menu
+     */
+    private void updateRecentProjects()
+    {
+        ProjectOpener opener = new ProjectOpener();
+        recentProjectsMenu.removeAll();
+
+        List<String> projects = PrefMgr.getRecentProjects();
+        for (Iterator<String> it = projects.iterator(); it.hasNext();) {
+            JMenuItem item = recentProjectsMenu.add(it.next());
+            item.addActionListener(opener);
+        }
+    }
+
+    /**
+     * Enable/disable functionality. Enable or disable all the interface
+     * elements that should change when a project is or is not open.
+     */
+    protected void enableFunctions(boolean enable)
+    {
+        if (! enable) {
+            teamActions.setAllDisabled();
+        }
+        
+        for (Iterator<JComponent> it = itemsToDisable.iterator(); it.hasNext();) {
+            JComponent component = it.next();
+            component.setEnabled(enable);
+        }
+        for (Iterator<Action> it = actionsToDisable.iterator(); it.hasNext();) {
+            Action action = it.next();
+            action.setEnabled(enable);
+        }
+    }
+
+    /**
+     * Return true if this frame is editing a Java Micro Edition package.
+     */
+    public boolean isJavaMEpackage( )
+    {
+        if (pkg == null) return false;
+        return pkg.getProject().isJavaMEProject();
+    }        
+    
+    class URLDisplayer
+        implements ActionListener
+    {
+        public URLDisplayer()
+        {}
+
+        @Override
+        public void actionPerformed(ActionEvent evt)
+        {
+            String url = evt.getActionCommand();
+            showWebPage(url);
+        }
+    }
+
+    class ProjectOpener
+        implements ActionListener
+    {
+        public ProjectOpener()
+        {}
+
+        @Override
+        public void actionPerformed(ActionEvent evt)
+        {
+            String project = evt.getActionCommand();
+            if (!openProject(project))
+                setStatus(Config.getString("pkgmgr.error.open"));
+        }
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/Project.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/Project.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ca808bd20c19b155762ec9e62378c8e08fc34be
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/Project.java
@@ -0,0 +1,2091 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.Component;
+import java.awt.EventQueue;
+import java.awt.Window;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+
+import bluej.BlueJEvent;
+import bluej.Boot;
+import bluej.Config;
+import bluej.classmgr.BPClassLoader;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerEvent;
+import bluej.debugger.DebuggerListener;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.DebuggerThread;
+import bluej.debugmgr.ExecControls;
+import bluej.debugmgr.ExpressionInformation;
+import bluej.debugmgr.inspector.ClassInspector;
+import bluej.debugmgr.inspector.Inspector;
+import bluej.debugmgr.inspector.InspectorManager;
+import bluej.debugmgr.inspector.ObjectInspector;
+import bluej.debugmgr.inspector.ResultInspector;
+import bluej.editor.Editor;
+import bluej.extensions.BProject;
+import bluej.extensions.ExtensionBridge;
+import bluej.extmgr.ExtensionsManager;
+import bluej.groupwork.Repository;
+import bluej.groupwork.TeamSettingsController;
+import bluej.groupwork.actions.TeamActionGroup;
+import bluej.groupwork.ui.CommitCommentsFrame;
+import bluej.groupwork.ui.StatusFrame;
+import bluej.groupwork.ui.TeamSettingsDialog;
+import bluej.groupwork.ui.UpdateFilesFrame;
+import bluej.parser.entity.EntityResolver;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.Target;
+import bluej.prefmgr.PrefMgr;
+import bluej.prefmgr.PrefMgrDialog;
+import bluej.terminal.Terminal;
+import bluej.testmgr.record.ClassInspectInvokerRecord;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+import bluej.utility.FileUtility.WriteCapabilities;
+import bluej.utility.JavaNames;
+import bluej.utility.Utility;
+import bluej.views.View;
+
+
+/**
+ * A BlueJ Project.
+ *
+ * @author  Michael Kolling
+ * @author  Axel Schmolitzky
+ * @author  Andrew Patterson
+ * @author  Bruce Quig
+ */
+public class Project implements DebuggerListener, InspectorManager 
+{
+    /**
+     * Collection of all open projects. The canonical name of the project
+     * directory (as a File object) is used as the key.
+     */
+    private static Map<File,Project> projects = new HashMap<File,Project>();
+    public static final int NEW_PACKAGE_DONE = 0;
+    public static final int NEW_PACKAGE_EXIST = 1;
+    public static final int NEW_PACKAGE_BAD_NAME = 2;
+    public static final int NEW_PACKAGE_NO_PARENT = 3;
+
+    public static final String projectLibDirName = "+libs";
+    
+    /** Property specifying location of JDK source */
+    private static final String JDK_SOURCE_PATH_PROPERTY = "bluej.jdk.source";
+    
+    private static final String PROJECT_CHARSET_PROP = "project.charset";
+    private static final String PROJECT_IS_JAVA_ME_PROP = "package.isJavaMEproject";
+    
+    /* ------------------- end of static declarations ------------------ */
+
+    // instance fields
+
+    /** the path of the project directory. */
+    private File projectDir;
+
+    /** collection of open packages in this project
+      (indexed by the qualifiedName of the package).
+       The unnamed package ie root package of the package tree
+       can be obtained by retrieving "" from this collection */
+    private Map<String, Package> packages;
+
+    /** the debugger for this project */
+    private Debugger debugger;
+
+    /** the ExecControls for this project */
+    private ExecControls execControls = null;
+
+    /** the Terminal for this project */
+    private Terminal terminal = null;
+
+    /** the documentation generator for this project. */
+    private DocuGenerator docuGenerator;
+
+    /** when a project is opened, the user may specify a
+       directory deep into the projects directory structure.
+       BlueJ will correctly find the top of this package
+       heirarchy but the bit of the name left over will be
+       put into this variable
+       ie if opening /home/user/foo/com/sun where
+       /home/user/foo is the project directory, this variable
+       will be set to com.sun */
+    private String initialPackageName = "";
+
+    /** This holds all object inspectors and class inspectors
+        for a project. It should only hold object inspectors that
+        have a wrapper on the object bench. Inspectors of fields of
+        object inspectors should be handled at the object wrapper level */
+    private Map<Object,Inspector> inspectors;
+    
+    private boolean inTestMode = false;
+    private BPClassLoader currentClassLoader;
+    private List<URL> libraryUrls;
+    
+    // the TeamSettingsController for this project
+    private TeamSettingsController teamSettingsController = null;
+    
+    private CommitCommentsFrame commitCommentsFrame = null;
+    private UpdateFilesFrame updateFilesFrame = null;
+    private StatusFrame statusFrame = null;
+    
+    /** If true, this project is connected with a source repository */
+    private boolean isSharedProject;
+
+    // team actions
+    private TeamActionGroup teamActions;  
+    
+    // Flag signalling whether this is a Java Micro Edition project
+    private boolean isJavaMEproject = false;    
+    
+    /** Resolve javadoc for this project */
+    private JavadocResolver javadocResolver;
+    
+    /** Where to find JDK and other library sources (for extracting javadoc) */
+    private List<DocPathEntry> sourcePath;
+    
+    /** Project character set for source files etc */
+    private Charset characterSet;
+
+    /* ------------------- end of field declarations ------------------- */
+
+    /**
+     * Construct a project in the directory projectDir.
+     * This must contain the root bluej.pkg of a nested package
+     * (this should by its nature be the unnamed package).
+     */
+    private Project(File projectDir)
+    {
+        if (projectDir == null) {
+            throw new NullPointerException();
+        }
+
+        Debug.log("Opening project: " + projectDir.toString());
+        
+        // Make JDK's javadoc available, if we can find the source
+        javadocResolver = new ProjectJavadocResolver(this);
+        sourcePath = new ArrayList<DocPathEntry>();
+        File javaHome = Boot.getInstance().getJavaHome();
+        File jdkSourceZip = new File(javaHome, "src.zip");
+        if (jdkSourceZip.isFile()) {
+            sourcePath.add(new DocPathEntry(jdkSourceZip, ""));
+        }
+        else {
+            File javaHomeParent = javaHome.getParentFile();
+            jdkSourceZip = new File(javaHomeParent, "src.zip");
+            if (jdkSourceZip.exists()) {
+                sourcePath.add(new DocPathEntry(jdkSourceZip, ""));
+            }
+            else {
+                // Mac OS X uses "src.jar" with a "src" prefix
+                jdkSourceZip = new File(javaHome, "src.jar");
+                if (jdkSourceZip.exists()) {
+                    sourcePath.add(new DocPathEntry(jdkSourceZip, "src"));
+                }
+            }
+        }
+        
+        String jdkSourcePath = Config.getPropString(JDK_SOURCE_PATH_PROPERTY, null);
+        if (jdkSourcePath != null) {
+            sourcePath.add(new DocPathEntry(new File(jdkSourcePath), ""));
+        }
+        
+        this.projectDir = projectDir;
+        libraryUrls = getLibrariesClasspath();
+        inspectors = new HashMap<Object,Inspector>();
+        packages = new TreeMap<String, Package>();
+        docuGenerator = new DocuGenerator(this);
+
+        try {
+            Package unnamed = new Package(this);
+            Properties props = unnamed.getLastSavedProperties();
+            setProjectProperties(props);
+            packages.put("", unnamed);
+            unnamed.refreshPackage();
+        } catch (IOException exc) {
+            Debug.reportError("could not read package file (unnamed package)");
+        }
+
+        debugger = Debugger.getDebuggerImpl(getProjectDir(), getTerminal());
+        debugger.setUserLibraries(libraryUrls.toArray(new URL[libraryUrls.size()]));
+        debugger.newClassLoader(getClassLoader());
+        debugger.addDebuggerListener(this);
+        debugger.launch();
+
+        // Check whether this is a shared project
+        File ccfFile = new File(projectDir.getAbsoluteFile(), "team.defs");
+        isSharedProject = ccfFile.isFile();
+        teamActions = new TeamActionGroup(isSharedProject);
+    }
+
+    /**
+     * Check if the path given is either a directory with a project file or if
+     * it is the project file itself (project.greenfoot or package.bluej).
+     * 
+     * @param projectPath a string representing the path to check. This can
+     *            either be a directory name or the filename of a project
+     *            file.
+     */
+    public static boolean isProject(String projectPath) 
+    {
+        File startingDir;
+
+        try {
+            startingDir = pathIntoStartingDirectory(projectPath);
+        } catch (IOException ioe) {
+            return false;
+        }
+
+        if (startingDir == null) {
+            return false;
+        }
+
+        return (Package.isPackage(startingDir));
+    }
+
+    /**
+     * Open a BlueJ project.
+     *
+     * @param projectPath
+     *            a string representing the path to open. This can either be a
+     *            directory name or the filename of a bluej.pkg file.
+     * @param parent 
+     *            Component used as parent if we need to show any messages.
+     *            Can be null.
+     * @return the Project representing the BlueJ project that has this
+     *         directory within it or null if there were no bluej.pkg files in
+     *         the specified directory.
+     */
+    public static Project openProject(String projectPath, Component parent) 
+    {
+        String startingPackageName;
+        File projectDir;
+        File startingDir;
+
+        try {
+            startingDir = pathIntoStartingDirectory(projectPath);
+        } catch (IOException ioe) {
+            Debug.message("could not resolve directory " + projectPath);
+
+            //ioe.printStackTrace();
+            return null;
+        }
+
+        if (startingDir == null) {
+            // Debug.message("attempt to open " + projectPath + " as a project failed");
+            return null;
+        }
+
+        // if there is an existing bluej package file here we
+        // need to find the root directory of the project
+        // (and while we are at it we will construct the qualified
+        //  package name that lets us open the PkgMgrFrame at the
+        //  right point)
+        if (Package.isPackage(startingDir)) {
+            File curDir = startingDir;
+            File lastDir = null;
+
+            startingPackageName = "";
+
+            while ((curDir != null) && Package.isPackage(curDir)) {
+                if (lastDir != null) {
+                    String lastdirName = lastDir.getName();
+
+                    if (!JavaNames.isIdentifier(lastdirName)) {
+                        break;
+                    }
+
+                    startingPackageName = "." + lastdirName + startingPackageName;
+                }
+
+                lastDir = curDir;
+                curDir = curDir.getParentFile();
+            }
+
+            if (startingPackageName.length() > 0) {
+                if (startingPackageName.charAt(0) == '.') {
+                    startingPackageName = startingPackageName.substring(1);
+                }
+            }
+
+            // lastDir is now the directory holding the topmost bluej
+            // package file in the directory heirarchy
+            projectDir = lastDir;
+
+            if (projectDir == null) {
+                projectDir = startingDir;
+            }
+        } else {
+            // Debug.message("no BlueJ package file found in directory " + startingDir);
+            return null;
+        }
+        
+        boolean readOnly = false;
+
+        if(Config.isModernWinOS()) {
+            WriteCapabilities capabilities = FileUtility.getVistaWriteCapabilities(projectDir);
+            switch (capabilities) {
+            case VIRTUALIZED_WRITE:
+                Utility.bringToFront(null);
+                DialogManager.showMessage(parent, "project-is-virtualized");
+                break;
+            case READ_ONLY:
+                readOnly = true;
+                break;
+            case NORMAL_WRITE:
+                break;
+            default:
+                break;
+            }
+        }
+        else if (!projectDir.canWrite()) {
+            readOnly = true;
+        }
+        
+        String greenfootStartupProjectDir = new File(Config.getBlueJLibDir(), "greenfoot/startupProject").getAbsolutePath();
+        
+        boolean isGreenfootStartupProject = greenfootStartupProjectDir.equals(projectDir.getAbsolutePath()); 
+        // Suppress the read-only warning if we know they are opening the Greenfoot startup project
+        
+        if (readOnly && !isGreenfootStartupProject) {
+            Utility.bringToFront(null);
+            DialogManager.showMessageWithText(parent, "project-is-readonly", new String [] {projectDir.toString()});
+            
+            // Prompt user to "Save elsewhere"
+
+            boolean done = false;
+
+            while (!done)
+            {
+                // Get a file name to save under
+                File newName = FileUtility.getDirName(null,
+                        Config.getString("pkgmgr.saveAs.title"),
+                        Config.getString("pkgmgr.saveAs.buttonLabel"),
+                        new JFileChooser().getFileSystemView().getDefaultDirectory(),
+                        false, true);
+
+                if (newName != null) {
+                    int result = FileUtility.copyDirectory(projectDir, newName);
+
+                    switch (result) {
+                    case FileUtility.NO_ERROR:
+                        // It worked, use this as the new project:
+                        projectDir = newName;
+                        done = true;
+                        break;
+
+                    case FileUtility.DEST_EXISTS:
+                        DialogManager.showError(null, "directory-exists");
+
+                        break;
+
+                    case FileUtility.SRC_NOT_DIRECTORY:
+                    case FileUtility.COPY_ERROR:
+                        DialogManager.showError(null, "cannot-save-project");
+
+                        break;
+                    }
+                }
+                else {
+                    done = true; // if they pressed cancel, just continue with old project
+                }
+            }
+        }
+
+        // check whether it already exists
+        Project proj = (Project) projects.get(projectDir);
+
+        if (proj == null) {
+            proj = new Project(projectDir);
+            projects.put(projectDir, proj);
+        }
+
+        if (startingPackageName.equals("")) {
+            Package startingPackage = proj.getPackage("");
+
+            while (startingPackage != null) {
+                Package sub = startingPackage.getBoringSubPackage();
+
+                if (sub == null) {
+                    break;
+                }
+
+                startingPackage = sub;
+            }
+
+            proj.initialPackageName = startingPackage.getQualifiedName();
+        }
+        else {
+            proj.initialPackageName = startingPackageName;
+        }
+        
+        ExtensionsManager.getInstance().projectOpening(proj);
+
+        return proj;
+    }
+
+    /**
+     * CleanUp the mess left by a project that has now been closed and
+     * throw it away.
+     */
+    public static void cleanUp(Project project) 
+    {
+        if (project.hasExecControls()) {
+            project.getExecControls().dispose();
+        }
+
+        if (project.terminal != null) {
+            project.terminal.dispose();
+        }
+        
+        if (project.statusFrame != null) {
+            project.statusFrame.dispose();
+        }
+
+        project.removeAllInspectors();
+        project.getDebugger().removeDebuggerListener(project);
+        project.getDebugger().close(false);
+
+        PrefMgr.addRecentProject(project.getProjectDir().getAbsolutePath());
+        projects.remove(project.getProjectDir());
+    }
+
+    /**
+     * Create a new project in the directory specified by projectPath.
+     * This name must be a directory that does not already exist.
+     * For Java ME projects, create directory res/icons in the project folder,
+     * and copy the default icon file for midlets from lib/images into res/icons.
+     *
+     * @param   projectPath     a string representing the path in which
+     *                          to make the new project
+     * @param   isJavaMEproj    whether or not the project is a Java Micro Edition project
+     * @return                  a boolean indicating success or failure
+     */
+    public static boolean createNewProject(String projectPath, boolean isJavaMEproj ) 
+    {
+        if (projectPath != null) {
+            // check whether name is already in use
+            File dir = new File(projectPath);
+
+            if (dir.exists()) {
+                return false;
+            }
+
+            if (dir.mkdir()) {
+                File newreadmeFile = new File(dir, Package.readmeName);
+                
+                if ( isJavaMEproj ) {
+                    File iconsDirectory = new File( dir, MIDletDeployer.ICONS_DIR );   
+                    if ( iconsDirectory.mkdirs( ) ) {                        
+                        File defaultMidletIconFile = new File( iconsDirectory, 
+                                                               MIDletDeployer.DEFAULT_MIDLET_ICON );
+                        File iconDefaultSource     = new File( Config.getBlueJLibDir( ), 
+                                                               MIDletDeployer.DEFAULT_LIB_ME_ICON );
+                        try {
+                            FileUtility.copyFile( iconDefaultSource, defaultMidletIconFile );
+                        }
+                        catch (IOException ioe) {
+                            Debug.reportError( "Could not copy default icon file into Project directory.");
+                        }
+                    } 
+                }
+                PackageFile pkgFile = PackageFileFactory.getPackageFile(dir);
+                try {
+                    if (pkgFile.create()) {
+                        Properties props = new Properties();
+                        props.put(PROJECT_CHARSET_PROP, "UTF-8");
+                        if (isJavaMEproj) {
+                            props.put(PROJECT_IS_JAVA_ME_PROP, "true");
+                        }
+                        try {
+                            pkgFile.save(props);
+                            FileUtility.copyFile(Config.getTemplateFile(
+                                    "readme"), newreadmeFile);
+                            return true;
+                        }
+                        catch (IOException ioe) {
+                            // TODO should propagate this exception
+                            Debug.message("I/O error while creating project.");
+                        }
+                    }
+                } catch (IOException ioe) {
+                    // TODO should propagate this exception
+                }
+            }
+        }
+
+        Debug.message("Unable to create project directory: " + projectPath);
+        return false;
+    }
+
+    /**
+     * Returns the number of open projects
+     */
+    public static int getOpenProjectCount() 
+    {
+        return projects.size();
+    }
+
+    /**
+     * Gets the set of currently open projects. It is an accessor only.
+     * @return a Set containing all open projects.
+     */
+    public static Collection<Project> getProjects() 
+    {
+        return projects.values();
+    }
+
+    /**
+     * Given a Projects key returns the Project objects describing this projects.
+     */
+    public static Project getProject(File projectKey) 
+    {
+        return (Project) projects.get(projectKey);
+    }
+   
+    /**
+     * Check whether the project is a Java Micro Edition project.
+     */
+    public boolean isJavaMEProject()
+    {
+        return isJavaMEproject;
+    }
+    
+    /**
+     * Get the character set that should be used for reading and writing source files
+     * in this project. 
+     */
+    public Charset getProjectCharset()
+    {
+        return characterSet;
+    }
+    
+    /**
+     * Get the project properties to be written to storage when the project is saved.
+     */
+    public Properties getProjectProperties()
+    {
+        Properties p = new Properties();
+        p.put(PROJECT_CHARSET_PROP, characterSet.name());
+        if (isJavaMEproject) {
+            p.put(PROJECT_IS_JAVA_ME_PROP, "true");
+        }
+        return p;
+    }
+    
+    /**
+     * Restore project properties (called just after project is opened). 
+     */
+    private void setProjectProperties(Properties props)
+    {
+        String charsetName = props.getProperty(PROJECT_CHARSET_PROP);
+        if (charsetName != null) {
+            try {
+                characterSet = Charset.forName(charsetName);
+            }
+            catch (IllegalCharsetNameException icne) {
+                Debug.log("Illegal project character set name: " + charsetName);
+            }
+            catch (UnsupportedCharsetException ucse) {
+                Debug.log("Unsupported project character set: " + charsetName);
+            }
+        }
+        if (characterSet == null) {
+            characterSet = Charset.defaultCharset();
+            props.put(PROJECT_CHARSET_PROP, characterSet.name());
+        }
+        
+        String isJavaMe = props.getProperty(PROJECT_IS_JAVA_ME_PROP, "false");
+        isJavaMEproject = isJavaMe.equals("true");
+    }
+    
+    /**
+     * Helper function to take a path (either a directory or a file)
+     * and return either the canonical path to the directory
+     * (in the case of a bluej.pkg file passed in, return the directory containing
+     * the file. Returns null if file is not a bluej.pkg file or if the
+     * directory/file does not exist.
+     */
+    private static File pathIntoStartingDirectory(String projectPath)
+        throws IOException 
+    {
+        File startingDir;
+
+        startingDir = new File(projectPath).getCanonicalFile();
+
+        if (startingDir.isDirectory()) {
+            return startingDir;
+        }
+
+        /* allow a bluej.pkg file to be specified. In this case,
+           we immediately find the parent directory and use that as the
+           starting directory */
+        if (startingDir.isFile()) {
+            if (Package.isPackageFileName(startingDir.getName())) {
+                return startingDir.getParentFile();
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Update an inspector, make sure it's visible, and bring it to
+     * the front.
+     * 
+     * @param inspector  The inspector to update and show
+     */
+    private void updateInspector(final Inspector inspector)
+    {
+        inspector.update();
+        inspector.setVisible(true);
+        inspector.bringToFront();
+    }
+    
+    /**
+     * Return an ObjectInspector for an object.
+     *
+     * @param obj
+     *            The object displayed by this viewer
+     * @param name
+     *            The name of this object or "null" if the name is unobtainable
+     * @param pkg
+     *            The package all this belongs to
+     * @param ir
+     *            the InvokerRecord explaining how we got this result/object if
+     *            null, the "get" button is permanently disabled
+     * @param parent
+     *            The parent frame of this frame
+     * @return The Viewer value
+     */
+    @Override
+    public ObjectInspector getInspectorInstance(DebuggerObject obj,
+        String name, Package pkg, InvokerRecord ir, JFrame parent) 
+    {
+        ObjectInspector inspector = (ObjectInspector) inspectors.get(obj);
+
+        if (inspector == null) {
+            inspector = new ObjectInspector(obj, this, name, pkg, ir, parent);
+            inspectors.put(obj, inspector);
+            inspector.setVisible(true);
+        }
+        else {
+            updateInspector(inspector);
+        }
+        
+        return inspector;
+    }
+    
+    /**
+     * Get the inspector for the given object. Object can be a DebuggerObject, or a
+     * fully-qualified class name.
+     * 
+     * @param obj  The object whose inspector to retrieve
+     * @return the inspector, or null if no inspector is open
+     */
+    public Inspector getInspector(Object obj) 
+    {
+        return (Inspector) inspectors.get(obj);
+    }
+
+    /**
+     * Remove an inspector from the list of inspectors for this project
+     * @param obj the inspector.
+     */
+    public void removeInspector(DebuggerObject obj) 
+    {
+        inspectors.remove(obj);
+    }
+    
+    /**
+     * Remove an inspector from the list of inspectors for this project
+     * @param obj the inspector. 
+     */
+    public void removeInspector(DebuggerClass cls) 
+    {
+        inspectors.remove(cls.getName());
+    }
+
+    /**
+     * Removes an inspector instance from the collection of inspectors
+     * for this project. It firstly retrieves the inspector object and
+     * then calls its doClose method.
+     * @param obj
+     */
+    public void removeInspectorInstance(Object obj) 
+    {
+        Inspector inspect = getInspector(obj);
+
+        if (inspect != null) {
+            inspect.doClose(false);
+        }
+    }
+
+    /**
+     * Removes all inspector instances for this project.
+     * This is used when VM is reset or the project is recompiled.
+     *
+     */
+    public void removeAllInspectors() 
+    {
+        for (Inspector inspector : inspectors.values()) {
+            inspector.setVisible(false);
+            inspector.dispose();
+        }
+
+        inspectors.clear();
+    }
+
+    /**
+     * Return a ClassInspector for a class. The inspector is visible.
+     *
+     * @param clss
+     *            The class displayed by this viewer
+     * @param name
+     *            The name of this object or "null" if it is not on the object
+     *            bench
+     * @param pkg
+     *            The package all this belongs to
+     * @param getEnabled
+     *            if false, the "get" button is permanently disabled
+     * @param parent
+     *            The parent frame of this frame
+     * @return The Viewer value
+     */
+    public ClassInspector getClassInspectorInstance(DebuggerClass clss,
+        Package pkg, JFrame parent) 
+    {
+        ClassInspector inspector = (ClassInspector) inspectors.get(clss.getName());
+
+        if (inspector == null) {
+            ClassInspectInvokerRecord ir = new ClassInspectInvokerRecord(clss.getName());
+            inspector = new ClassInspector(clss, this, pkg, ir, parent);
+            inspectors.put(clss.getName(), inspector);
+            inspector.setVisible(true);
+        }
+        else {
+            updateInspector(inspector);
+        }
+        
+        return inspector;
+    }
+
+    /**
+     * Return an ObjectInspector for an object. The inspector is visible.
+     *
+     * @param obj
+     *            The object displayed by this viewer
+     * @param name
+     *            The name of this object or "null" if the name is unobtainable
+     * @param pkg
+     *            The package all this belongs to
+     * @param ir
+     *            the InvokerRecord explaining how we got this result/object if
+     *            null, the "get" button is permanently disabled
+     * @param info
+     *            The information about the the expression that gave this result
+     * @param parent
+     *            The parent frame of this frame
+     * @return The Viewer value
+     */
+    public ResultInspector getResultInspectorInstance(DebuggerObject obj,
+        String name, Package pkg, InvokerRecord ir, ExpressionInformation info,
+        JFrame parent) 
+    {
+        final ResultInspector inspector = new ResultInspector(obj, this, name, pkg, ir, info);
+        inspectors.put(obj, inspector);
+
+        DialogManager.centreWindow(inspector, parent);
+        inspector.setVisible(true);
+        inspector.bringToFront();
+
+        return inspector;
+    }
+
+    /**
+     * Iterates through all inspectors and updates them
+     *
+     */
+    public void updateInspectors() 
+    {
+        for (Iterator<Inspector> it = inspectors.values().iterator(); it.hasNext();) {
+            Inspector inspector = it.next();
+            inspector.update();
+        }
+    }
+
+    /**
+     * Return the name of the project.
+     */
+    public String getProjectName() 
+    {
+        return projectDir.getName();
+    }
+
+    /**
+     * Return the location of the project.
+     */
+    public File getProjectDir() 
+    {
+        return projectDir;
+    }
+
+    /**
+     * Return the source path for the project. The source path contains the JDK source,
+     * if available, and the source for any other libraries which have been explicitly
+     * added.
+     */
+    public List<DocPathEntry> getSourcePath()
+    {
+        return sourcePath;
+    }
+    
+    /**
+     * Get the project repository. If the user cancels the credentials dialog,
+     * or this is not a team project, returns null.
+     */
+    public Repository getRepository()
+    {
+        if (isSharedProject) {
+            return getTeamSettingsController().getRepository(true);
+        }
+        else {
+            return null;
+        }
+    }      
+        
+    /**
+     * A string which uniquely identifies this project
+     */
+    public String getUniqueId() 
+    {
+        return String.valueOf(new String("BJID" + getProjectDir().getPath()).hashCode());
+    }
+
+    /**
+     * Get the name of the package represented by the directory which was specified
+     * as the directory to open when this project was opened.
+     */
+    public String getInitialPackageName() 
+    {
+        return initialPackageName;
+    }
+
+    /**
+     * Get an existing package from the project. The package is opened (i.e a new
+     * Package object is constructed) if it's not already open. All parent packages on
+     * the way to the root of the package tree will also be constructed.
+     * 
+     * @param qualifiedName package name i.e. java.util or "" for unnamed package
+     * @returns  the package, or null if the package doesn't exist (directory
+     *           doesn't exist, or doesn't contain bluej.pkg file)
+     */
+    public Package getPackage(String qualifiedName)
+    {
+        Package existing = packages.get(qualifiedName);
+
+        if (existing != null) {
+            // The unnamed package is always already open, so that case is
+            // handled here.
+            return existing;
+        }
+
+        if (qualifiedName.length() > 0) {
+            Package pkg;
+
+            try {
+                Package parent = getPackage(JavaNames.getPrefix(qualifiedName));
+
+                if (parent != null) {
+                    // Note, construction of the new package throws IOException if
+                    // the directory or bluej.pkg file doesn't exist
+                    pkg = new Package(this, JavaNames.getBase(qualifiedName),
+                            parent);
+                    packages.put(qualifiedName, pkg);
+                    pkg.refreshPackage();
+                } else { // parent package does not exist. How can it not exist ?
+                    pkg = null;
+                }
+            } catch (IOException exc) {
+                // the package did not exist in this project
+                pkg = null;
+            }
+            
+            return pkg;
+        }
+
+        // Default package is not in the package cache. This should never happen...
+        throw new IllegalStateException("Project.getPackage()");
+    }
+
+
+    private BProject singleBProject;  // Every Project has none or one BProject
+    
+    /**
+     * Return the extensions BProject associated with this Project.
+     * There should be only one BProject object associated with each Project.
+     * @return the BProject associated with this Project.
+     */
+    public synchronized final BProject getBProject ()
+    {
+        if ( singleBProject == null )
+          singleBProject = ExtensionBridge.newBProject(this);
+          
+        return singleBProject;
+    }
+
+
+    /**
+     * Returns a package from the project. The package must have already been
+     * opened.
+     *
+     * @param qualifiedName package name ie java.util or "" for unnamed package
+     * @return null if the named package cannot be found
+     */
+    public Package getCachedPackage(String qualifiedName)
+    {
+        return packages.get(qualifiedName);
+    }
+
+    /**
+     * This creates package directories. For the given package, all
+     * intermediate package directories (which do not already exist)
+     * will be created. A bluej.pkg file will be created for each
+     * directory (if it does not already exist).
+     * 
+     * @param fullName  the fully qualified name of the package to create
+     *                  directories for
+     */
+    public void createPackageDirectory(String fullName)
+    {
+        // construct the directory name for the new package
+        StringTokenizer st = new StringTokenizer(fullName, ".");
+        File newPkgDir = getProjectDir();
+
+        while (st.hasMoreTokens())
+            newPkgDir = new File(newPkgDir, st.nextToken());
+
+        // now actually construct the directories and add the bluej
+        // package marker files
+        if (newPkgDir.isDirectory() || newPkgDir.mkdirs()) {
+            st = new StringTokenizer(fullName, ".");
+            newPkgDir = getProjectDir();
+            PackageFile pkgFile = PackageFileFactory.getPackageFile(newPkgDir);
+            try {
+                pkgFile.create();
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+            }
+
+            while (st.hasMoreTokens()) {
+                newPkgDir = new File(newPkgDir, st.nextToken());
+                prepareCreateDir(newPkgDir);
+
+                pkgFile = PackageFileFactory.getPackageFile(newPkgDir);
+                try {
+                    pkgFile.create();
+                } catch (IOException ioe) {
+                    ioe.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a new package with the given fully qualified name. Once
+     * NEW_PACKAGE_DONE is returned you can use getPackage to get the actual
+     * package.
+     *
+     * @param qualifiedName
+     *            Ex. java.util or "" for unnamed package
+     * @return Project.NEW_PACKAGE_DONE, Project.NEW_PACKAGE_EXIST,
+     *         Project.NEW_PACKAGE_BAD_NAME
+     */
+    public int newPackage(String qualifiedName)
+    {
+        if (qualifiedName == null) {
+            return NEW_PACKAGE_BAD_NAME;
+        }
+
+        Package existing = packages.get(qualifiedName);
+
+        if (existing != null) {
+            return NEW_PACKAGE_EXIST;
+        }
+
+        // The zero len (unqualified) package should always exist.
+        if (qualifiedName.length() < 1) {
+            return NEW_PACKAGE_BAD_NAME;
+        }
+
+        // The above named package does not exist, lets create it.
+        try {
+            Package parent = getPackage(JavaNames.getPrefix(qualifiedName));
+
+            if (parent == null) {
+                return NEW_PACKAGE_NO_PARENT;
+            }
+
+            // Before creating the package you have to create the directory
+            // Maybe it should go into the new Package(...)
+            createPackageDirectory(qualifiedName);
+
+            Package pkg = new Package(this, JavaNames.getBase(qualifiedName),
+                    parent);
+            packages.put(qualifiedName, pkg);
+            pkg.refreshPackage();
+        } catch (IOException exc) {
+            return NEW_PACKAGE_BAD_NAME;
+        }
+
+        return NEW_PACKAGE_DONE;
+    }
+
+    /**
+     * Get the names of all packages in this project consisting of rootPackage
+     * package and all packages nested below it.
+     *
+     * @param rootPackage
+     *            the root package to consider in looking for nested packages
+     * @return a List of String containing the fully qualified names of the
+     *         packages.
+     */
+    private List<String> getPackageNames(Package rootPackage)
+    {
+        List<String> l = new LinkedList<String>();
+        List<Package> children;
+
+        l.add(rootPackage.getQualifiedName());
+
+        children = rootPackage.getChildren(true);
+        Iterator<Package> i = children.iterator();
+        
+        while (i.hasNext()) {
+            Package p = i.next();
+            l.addAll(getPackageNames(p));
+        }
+
+        return l;
+    }
+
+    /**
+     * Get the names of all packages in this project.
+     * 
+     * @return  a List of String containing the fully qualified names
+     *          of the packages in this project.
+     */
+    public List<String> getPackageNames()
+    {
+        return getPackageNames(getPackage(""));
+    }
+
+    /**
+     * Generate documentation for the whole project.
+     * @return "" if everything was alright, an error message otherwise.
+     */
+    public String generateDocumentation()
+    {
+        return docuGenerator.generateProjectDocu();
+    }
+
+    public String getDocumentationFile(String filename)
+    {
+        return docuGenerator.getDocuPath(filename);
+    }
+
+    /**
+    * Generate the documentation for the file in 'filename'
+     * @param filename
+     */
+    public void generateDocumentation(String filename)
+    {
+        docuGenerator.generateClassDocu(filename);
+    }
+
+    /**
+     * Save all open packages of this project. This doesn't save files open
+     * in editor windows - use saveAllEditors() for that.
+     */
+    public void saveAll()
+    {
+        PkgMgrFrame[] frames = PkgMgrFrame.getAllProjectFrames(this);
+
+        if (frames == null) {
+            return;
+        }
+
+        for (int i = 0; i < frames.length; i++) {
+            frames[i].doSave();
+            frames[i].setStatus(Config.getString("pkgmgr.packageSaved"));
+        }
+    }
+
+    /**
+     * Request all open editor windows for the current project to save their
+     * contents (if modified).
+     */
+    public void saveAllEditors() throws IOException
+    {
+        Iterator<Package> i = packages.values().iterator();
+        IOException exception = null;
+
+        while(i.hasNext()) {
+            Package pkg = (Package) i.next();
+            try {
+                pkg.saveFilesInEditors();
+            }
+            catch(IOException ioe) {
+                exception = ioe;
+                Debug.reportError("Error while trying to save editor file:", ioe);
+            }
+        }
+        
+        if (exception != null) {
+            // Propagate the exception - let the caller know that something went wrong.
+            throw exception;
+        }
+    }
+    
+    /**
+     * Reload all constructed packages of this project.
+     *
+     * <p>This function is used after a major change to the contents
+     * of the project directory ie an import.
+     */
+    public void reloadAll()
+    {
+        Iterator<Package> i = packages.values().iterator();
+
+        while (i.hasNext()) {
+            Package pkg = (Package) i.next();
+
+            pkg.reload();
+        }
+    }
+
+    /**
+     * Make all open package editors clear their selection
+     */
+    public void clearAllSelections()
+    {
+        Iterator<Package> i = packages.values().iterator();
+
+        while(i.hasNext()) {
+            Package pkg = (Package) i.next();
+            PackageEditor editor = pkg.getEditor();
+            if (editor != null){
+                editor.clearSelection();
+            }
+        }
+    }
+    
+    /**
+     * Make the grapheditors of this project clear their selection and select
+     * the targets given in the parameter targets.
+     * 
+     * @param targets a list of Targets
+     */
+    public void selectTargetsInGraphs(List<Target> targets)
+    {
+        for (Iterator<Target> i = targets.iterator(); i.hasNext();) {
+            Target target = i.next();
+            if (target != null){
+                PackageEditor packageEditor = target.getPackage().getEditor();
+                packageEditor.addToSelection(target);
+                packageEditor.repaint();
+            }
+        }
+    }
+    
+    /**
+     * Given a fully-qualified target name, return the target or null if the target
+     * doesn't exist.
+     * 
+     * <p>Use ReadmeTarget.README_ID ("@README") as the target base name to get the
+     * readme target for a package.
+     * 
+     * Given the path and name of a target in the project, return the target or
+     * null if the target doesn't exist
+     * @param pathAndName
+     * @return the target
+     */
+    public Target getTarget(String targetId)
+    {
+        String packageName = "";
+        int index = targetId.lastIndexOf('.');
+        if (index > 0) {
+            packageName = targetId.substring(0, index);
+            targetId = targetId.substring(index + 1);
+        }
+        Package p = getPackage(packageName);
+        if (p == null) {
+            return null;
+        }
+        Target target = p.getTarget(targetId);
+        return target;
+    }
+    
+    /**
+     * Open the source editor for each target that is selected in its
+     * package editor
+     */
+    public void openEditorsForSelectedTargets()
+    {
+        List<Target> selectedTargets = getSelectedTargets();
+        for (Iterator<Target> i = selectedTargets.iterator(); i.hasNext(); ){
+            Target target = i.next();
+            if (target instanceof ClassTarget){
+                ClassTarget classTarget = (ClassTarget) target;
+                Editor editor = classTarget.getEditor();
+                if (editor != null) {
+                    editor.setVisible(true);
+                    // TODO: make moe select the ======== part of cvs conflicts
+                }
+            }
+        }
+    }
+    
+    /**
+     * Get a list of selected targets (in all packages)
+     * @return a list of the selected targets
+     */
+    private List<Target> getSelectedTargets()
+    {
+        List<Target> selectedTargets = new LinkedList<Target>();
+        List<String> packageNames = getPackageNames();
+        for (Iterator<String> i = packageNames.iterator(); i.hasNext();) {
+            String packageName = i.next();
+            Package p = getPackage(packageName);
+            selectedTargets.addAll(Arrays.asList(p.getSelectedTargets()));
+        }
+        return selectedTargets;
+    }
+    
+    /**
+     * Explicitly restart the remote debug VM. The VM first gets shut down, and then
+     * restarted.
+     */
+    public void restartVM()
+    {
+        getDebugger().close(true);
+        vmClosed();
+        PkgMgrFrame.displayMessage(this, Config.getString("pkgmgr.creatingVM"));
+    }
+
+    /**
+     * The remote VM for this project has just been initialised and is ready now.
+     */
+    private void vmReady()
+    {
+        BlueJEvent.raiseEvent(BlueJEvent.CREATE_VM_DONE, null);
+        
+        Package pkg = null;
+        Iterator<Package> i = packages.values().iterator();
+        while (i.hasNext()) {
+            pkg = (Package) i.next();
+            pkg.reInitBreakpoints();           
+        }
+        PkgMgrFrame frame = PkgMgrFrame.getMostRecent();
+        if (frame != null) {
+            Utility.bringToFront(frame);
+        }        
+    }
+
+    /**
+     * The remote VM for this project has just been closed. Remove everything in this
+     * project that depended on that VM.
+     */
+    private void vmClosed()
+    {
+        // any calls to the debugger made by removeLocalClassLoader
+        // will silently fail
+        removeClassLoader();
+        
+        // The configured extra libraries may have changed, so
+        // rebuild the class loader (do this now so the new loader
+        // will be installed as soon as the VM has restarted).
+        newRemoteClassLoader();
+        
+        libraryUrls = getLibrariesClasspath();
+        debugger.setUserLibraries(libraryUrls.toArray(new URL[libraryUrls.size()]));
+        
+        // Breakpoints will be re-initialized once the new VM has
+        // actually started.
+    }
+
+    /**
+     * Removes the current classloader, and removes
+     * references to classes loaded by it (this includes removing
+     * the objects from all object benches of this project).
+     */
+    public void removeClassLoader()
+    {
+        // There is nothing to do if the current classloader is null.
+        if (currentClassLoader == null) {
+            return;
+        }
+        
+        clearObjectBenches();
+
+        // get rid of any inspectors that are open that were not cleaned up
+        // as part of removing objects from the bench
+        removeAllInspectors();
+
+        // remove views for classes loaded by this classloader
+        View.removeAll(currentClassLoader);
+
+        if (! Config.isGreenfoot()) {
+            // dispose windows for local classes. Should not run user code
+            // on the event queue, so run it in a separate thread.
+            new Thread() {
+                public void run() {
+                    getDebugger().disposeWindows();
+                }
+            }.start();
+        }
+
+        currentClassLoader = null;
+    }
+
+    /**
+     * Clears the objects from all object benches belonging to this project.
+     */
+    public void clearObjectBenches()
+    {
+        // remove bench objects for all frames in this project
+        PkgMgrFrame[] frames = PkgMgrFrame.getAllProjectFrames(this);
+
+        for (int i = 0; i < frames.length; i++) {
+            frames[i].getObjectBench().removeAllObjects(getUniqueId());
+            frames[i].clearTextEval();
+        }
+    }
+
+    /**
+     * Creates a new debugging VM classloader.
+     * Breakpoints are discarded.
+     */
+    public void newRemoteClassLoader()
+    {
+        getDebugger().newClassLoader(getClassLoader());
+    }
+
+    /**
+     * Creates a new debugging VM classloader, leaving current breakpoints.
+     */
+    public void newRemoteClassLoaderLeavingBreakpoints()
+    {
+        getDebugger().newClassLoader(getClassLoader());
+
+        Iterator<Package> i = packages.values().iterator();
+        while (i.hasNext()) {
+            Package pkg = (Package) i.next();
+            pkg.reInitBreakpoints();
+        }
+    }
+
+    public Debugger getDebugger()
+    {
+        return debugger;
+    }
+
+    public boolean hasExecControls()
+    {
+        return execControls != null;
+    }
+
+    public ExecControls getExecControls()
+    {
+        if (execControls == null) {
+            execControls = new ExecControls(this, getDebugger());
+        }
+
+        return execControls;
+    }
+
+    public boolean hasTerminal()
+    {
+        return terminal != null;
+    }
+
+    public Terminal getTerminal()
+    {
+        if (terminal == null) {
+            terminal = new Terminal(this);
+        }
+
+        return terminal;
+    }
+
+    /**
+     * Loads a class using the current classLoader
+     */
+    public Class<?> loadClass(String className)
+    {
+        try {
+            return getClassLoader().loadClass(className);
+        }
+        catch (ClassNotFoundException e) {
+            return null;
+        }
+        catch (LinkageError le) {
+            return null;
+        }
+    }
+
+    public boolean inTestMode()
+    {
+        return inTestMode;
+    }
+
+    public void setTestMode(boolean mode)
+    {
+        inTestMode = mode;
+    }
+  
+    /**
+     * Return a list of URL of the Java ME libraries specified in the 
+     * configuration files. The libraries are physically located in the 'lib'  
+     * subdirectory of the Wireless Toolkit directory. 
+     * @param type   "optional" or "core", the type of libraries to process
+     * @return a non null but possibly empty list of URL.
+     */
+    protected List<URL> getJavaMELibraries( String type ) 
+    {
+        List<URL> risul = new ArrayList<URL>( );
+        String toolkitDir = Config.getPropString( "bluej.javame.toolkit.dir", null );
+        
+        String libs;   //string of java me libraries to parse
+        if ( type.equals( "core" ) )
+            libs = Config.getPropString( "bluej.javame.corelibraries", null );
+        else if ( type.equals( "optional" ) )
+            libs = Config.getPropString( "bluej.javame.optlibraries", null );
+        else
+            libs = null;
+        
+        if ( toolkitDir != null  &&  libs != null )
+        {            
+            String libDir = toolkitDir + File.separator + "lib" + File.separator;
+            StringTokenizer st = new StringTokenizer( libs );
+            while ( st.hasMoreTokens( ) ) {
+                try {
+                    File file = new File( libDir + st.nextToken( ) );
+                    risul.add( file.toURI( ).toURL( ) );
+                }
+                catch( MalformedURLException mue ) { 
+                    Debug.reportError( st.nextToken( ) + " is a Java ME malformed file." );
+                }
+            }
+        }  
+        return risul;
+    }
+        
+    /**
+     * Returns a list of URL having in it all libraries that are in the +libs directory
+     * of this project.
+     * @return a non null but possibly empty list of URL.
+     */
+    protected ArrayList<URL> getPlusLibsContent () 
+    {
+        ArrayList<URL> risul = new ArrayList<URL>();
+        
+        // the subdirectory of the project which can hold project specific jars and zips
+        File libsDirectory = new File(projectDir, projectLibDirName);
+
+        // If it is not a directory or we cannot read it then there is nothing to do.
+        if ( ! libsDirectory.isDirectory() || ! libsDirectory.canRead() ) 
+          return risul;
+          
+        // the list of jars and zips we find
+        File []libs = libsDirectory.listFiles();
+
+        // If there are no files there then again just return.
+        if ( libs==null || libs.length < 1 ) 
+          return risul;
+
+        // if we found any jar files in the libs directory then add their URLs
+        for(int index=0; index<libs.length; index++) {
+            attemptAddLibrary(risul, libs[index]);
+        }
+        return risul;
+    }
+    
+    /**
+     * Attempts to add a library to the given list of libraries.
+     * A valid library file is one that is a file, readable, ends either with zip or jar.
+     * Before addition the file is transformed to a URL.
+     * @param risul where to add the file
+     * @param aFile the file to be added.
+     */
+    private static final void attemptAddLibrary ( ArrayList<URL> risul, File aFile ) 
+    {
+        if ( aFile == null ) return;
+        
+        // Is this a normal file and is it readable ?
+        if ( ! (aFile.isFile() && aFile.canRead()) ) return;
+        
+        String libname = aFile.getName().toLowerCase();
+        if ( ! (libname.endsWith(".jar") || libname.endsWith(".zip")) ) return;
+        
+        try {
+            risul.add(aFile.toURI().toURL());
+        }
+        catch(MalformedURLException mue) { 
+            Debug.reportError("Project.attemptAddLibrary() malformaed file="+aFile);
+        }
+    }
+      
+
+    /**
+     * Returns an array of URLs for all the JAR files located in the lib/userlib directory.
+     * The result is calculated every time the method is called, in this way it is possible
+     * to capture a change in the library content in a reasonable timing.
+     *
+     * @return  URLs of the discovered JAR files
+     */
+    public static final ArrayList<URL> getUserlibContent() 
+    {
+        ArrayList<URL> risul = new ArrayList<URL>();
+        File userLibDir;
+        
+        // The userlib location may be specified in bluej.defs
+        String userLibSetting = Config.getPropString("bluej.userlibLocation", null);
+        if (userLibSetting == null) {
+            userLibDir = new File(Boot.getBluejLibDir(), "userlib");
+        }
+        else {
+            userLibDir = new File(userLibSetting);
+        }
+
+        File[] files = userLibDir.listFiles();
+        if (files == null) {
+            return risul;
+        }
+        
+        for (int index = 0; index < files.length; index++) {
+            attemptAddLibrary(risul, files[index]);
+        }
+ 
+        return risul;
+    }
+
+    /**
+     * Return a ClassLoader that should be used to load or reflect on the project classes.
+     * The same BClassLoader object is returned until the Project is compiled or the content of the
+     * user class list is changed, this is needed to load "compatible" classes in the same classloader space.
+     *
+     * @return a BClassLoader that provides class loading services for this Project.
+     */
+    public BPClassLoader getClassLoader()
+    {
+        if (currentClassLoader != null)
+            return currentClassLoader;
+       
+        ArrayList<URL> pathList = new ArrayList<URL>();
+        
+        List<URL> coreLibs = new ArrayList<URL>(); //Java ME core libraries
+        List<URL> optLibs  = new ArrayList<URL>(); //java ME optional libraries
+
+        try {
+            Collections.addAll(pathList, Boot.getInstance().getRuntimeUserClassPath());
+    
+            pathList.addAll(libraryUrls);
+            
+            // The current project dir must be added to the project class path too.
+            pathList.add(getProjectDir().toURI().toURL());
+            
+            //Add Java ME jars if this is a Java ME project. 
+            if ( isJavaMEproject ) { 
+                coreLibs = getJavaMELibraries( "core"     ) ;
+                optLibs  = getJavaMELibraries( "optional" ) ;                
+                pathList.addAll( coreLibs );  
+                pathList.addAll( optLibs );         
+            }
+        }
+        catch ( Exception exc ) {
+            // Should never happen
+            Debug.reportError("Project.getClassLoader() exception: " + exc.getMessage());
+            exc.printStackTrace();
+        }
+
+        URL [] newUrls = (URL [])pathList.toArray(new URL[pathList.size()]);
+        
+        // The Project Class Loader should not see the BlueJ classes (the necessary
+        // ones have been added to the URL list anyway). So we use the boot loader
+        // as parent.
+        currentClassLoader = new BPClassLoader( newUrls,
+                     Boot.getInstance().getBootClassLoader(), isJavaMEproject );
+        
+        currentClassLoader.setJavaMEcoreLibs(coreLibs);
+        currentClassLoader.setJavaMEoptLibs (optLibs);
+        
+        return currentClassLoader;
+    }
+    
+    /**
+     * Get the classpath for libraries - those specified in preferences, in the project's +libs,
+     * in the BlueJ userlib folder, etc. This doesn't include the BlueJ runtime.
+     * 
+     * <p>Most of the time, the list in {@code libraryUrls} should be used instead of calling this
+     * method, as it represents the libraries known to the currently executing VM.
+     */
+    private List<URL> getLibrariesClasspath()
+    {
+        ArrayList<URL> pathList = new ArrayList<URL>();
+        
+        // Next part is the libraries that are added trough the config panel.
+        pathList.addAll(PrefMgrDialog.getInstance().getUserConfigLibPanel().getUserConfigContent());
+        
+        // Then the libraries that are in the userlib directory
+        pathList.addAll(getUserlibContent());
+        
+        // The libraries that are in the project +libs directory
+        pathList.addAll(getPlusLibsContent());
+        
+        return pathList;
+    }
+
+    /**
+     * Get an entity resolver which can be used to resolve symbols for this project.
+     * 
+     * @return an entity resolver which resolves symbols from classes in this project,
+     *         and from the classpath.
+     */
+    public EntityResolver getEntityResolver()
+    {
+        return new ProjectEntityResolver(this);
+    }
+    
+    /**
+     * Get a javadoc resolver, which can be used to retrieve comments for methods.
+     */
+    public JavadocResolver getJavadocResolver()
+    {
+        return javadocResolver;
+    }
+    
+    /**
+     * Convert a filename into a fully qualified Java name.
+     * Returns null if the file is outside the project
+     * directory.
+     *
+     * The behaviour of this function is not guaranteed if
+     * you pass in a directory name. It is meant for filenames
+     * like /foo/bar/p1/s1/TestName.java
+     */
+    public String convertPathToPackageName(String pathname) 
+    {
+        return JavaNames.convertFileToQualifiedName(getProjectDir(),
+            new File(pathname));
+    }
+
+    public void removeStepMarks() 
+    {
+        // remove step marks for all packages
+        Iterator<Package> i = packages.values().iterator();
+
+        while (i.hasNext()) {
+            Package pkg = (Package) i.next();
+            pkg.removeStepMarks();
+        }
+
+        return;
+    }
+
+    // ---- DebuggerListener interface ----
+
+    /**
+     * A debugger event was fired. Analyse which event it was, and take
+     * appropriate action.
+     */
+    public void processDebuggerEvent(final DebuggerEvent event, boolean skipUpdate)
+    {
+        if (skipUpdate) {
+            return;
+        }
+        
+        EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                if (event.getID() == DebuggerEvent.DEBUGGER_STATECHANGED) {
+                    PkgMgrFrame[] frames = PkgMgrFrame.getAllProjectFrames(Project.this);
+
+                    if (frames == null) {
+                        return;
+                    }
+
+                    int newState = event.getNewState();
+                    int oldState = event.getOldState();
+
+                    for (int i = 0; i < frames.length; i++)
+                        frames[i].setDebuggerState(newState);
+
+                    // check whether we just got a freshly created VM
+                    if ((oldState == Debugger.NOTREADY) &&
+                            (newState == Debugger.IDLE)) {
+                        vmReady();
+                    }
+
+                    // check whether a good VM just disappeared
+                    if ((oldState == Debugger.IDLE) &&
+                            (newState == Debugger.NOTREADY)) {
+                        removeStepMarks();
+                        vmClosed();
+                    }
+
+                    // check whether we failed to create the VM
+                    if (newState == Debugger.LAUNCH_FAILED) {
+                        BlueJEvent.raiseEvent(BlueJEvent.CREATE_VM_FAILED, null);
+                    }
+
+                    return;
+                }
+
+                DebuggerThread thr = event.getThread();
+                if (thr == null) {
+                    return; // Not a thread event
+                }
+                String packageName = JavaNames.getPrefix(thr.getClass(0));
+                Package pkg = getPackage(packageName);
+
+                if (pkg != null) {
+                    switch (event.getID()) {
+                    case DebuggerEvent.THREAD_BREAKPOINT:
+                        pkg.hitBreakpoint(thr);
+                        break;
+
+                    case DebuggerEvent.THREAD_HALT_UNKNOWN:
+                    case DebuggerEvent.THREAD_HALT_STEP_INTO:
+                    case DebuggerEvent.THREAD_HALT_STEP_OVER:
+                        pkg.hitHalt(thr);
+                        break;
+                    }
+                }
+                
+                switch (event.getID())
+                {
+                    case DebuggerEvent.THREAD_HALT_UNKNOWN:
+                        break;
+                    case DebuggerEvent.THREAD_HALT_STEP_INTO:
+                        break;
+                    case DebuggerEvent.THREAD_HALT_STEP_OVER:
+                        break;
+                    case DebuggerEvent.THREAD_BREAKPOINT:
+                        break;
+                }
+            }
+        });
+    }
+    
+    /**
+     * Show the source code corresponding to the top of the given thread stack.
+     */
+    public void showSource(DebuggerThread thread)
+    {
+        String packageName = JavaNames.getPrefix(thread.getClass(0));
+        Package pkg = getPackage(packageName);
+        if (pkg != null) {
+            pkg.showSourcePosition(thread);
+        }
+    }
+
+    // ---- end of DebuggerListener interface ----
+
+    /**
+     * String representation for debugging.
+     */
+    public String toString()
+    {
+        return "Project:" + getProjectName();
+    }
+
+    /**
+     * Removes a package (and any sub-packages) from the map of open
+     * packages in the project.
+     * 
+     * @param packageQualifiedName The qualified name of the package.
+     */
+    public void removePackage(String packageQualifiedName)
+    {
+        Package pkg = packages.get(packageQualifiedName);
+        if (pkg != null) {
+            List<Package> childPackages = pkg.getChildren(false);
+            Iterator<Package> i = childPackages.iterator();
+            while (i.hasNext()) {
+                Package childPkg = (Package) i.next();
+                removePackage(childPkg.getQualifiedName());
+            }
+            packages.remove(packageQualifiedName);
+        }
+    }
+    
+    // ---- teamwork
+    
+    /**
+     * Return the teamwork action group.
+     */
+    public TeamActionGroup getTeamActions()
+    {
+        return teamActions;
+    }
+    
+    /**
+     * Determine if project is a team project. 
+     * The method will look for the existence of the team configuration file
+     * team.defs
+     * @return true if the project is a team project
+     */
+    public boolean isTeamProject()
+    {
+        return isSharedProject;
+    }
+
+    /**
+     * Get an array of Files that resides in the project folders.
+     * @param includePkgFiles   true if package layout files should be included
+     * @param includeDirs       true if directories should be included
+     * @return List of File objects 
+     */
+    public Set<File> getFilesInProject(boolean includePkgFiles, boolean includeDirs)
+    {
+        Set<File> files = new LinkedHashSet<File>();
+        if (includeDirs) {
+            files.add(projectDir);
+        }
+        traverseDirsForFiles(files, projectDir, includePkgFiles, includeDirs);
+        return files;
+    }
+
+    /**
+     * Get the teams settings controller for this project. Returns null
+     * if this is not a shared project.
+     */
+    public TeamSettingsController getTeamSettingsController()
+    {
+        if(teamSettingsController == null && isSharedProject) {
+            teamSettingsController = new TeamSettingsController(this);
+        }
+        return teamSettingsController;
+    }
+
+    /**
+     * Traverse the directory tree starting in dir an add all the encountered 
+     * files to the List allFiles. The parameter includePkgFiles determine 
+     * whether bluej.pkg files should be added to allFiles as well.
+     * @param allFiles a List to which the method will add the files it meets.
+     * @param dir the directory the search starts from
+     * @param includePkgFiles if true, bluej.pkg files are included as well.
+     */
+    private void traverseDirsForFiles(Set<File> allFiles, File dir, boolean includePkgFiles,
+            boolean includeDirs)
+    {
+        TeamSettingsController teamSettingsController = getTeamSettingsController();
+        File[] files = dir.listFiles(teamSettingsController == null ? null : teamSettingsController.getFileFilter(includePkgFiles));
+        if (files==null){
+            return;
+        }
+        for(int i=0; i< files.length; i++ ){
+            if (files[i].isFile()) {
+                allFiles.add(files[i]);
+            } else {
+                if (includeDirs) {
+                    allFiles.add(files[i]);
+                }
+                traverseDirsForFiles(allFiles, files[i], includePkgFiles, includeDirs);
+            }
+        }
+    }
+
+    /**
+     * Get the team settings dialog for this project. Only call this if the
+     * project is a shared project.
+     */
+    public TeamSettingsDialog getTeamSettingsDialog()
+    {
+        return getTeamSettingsController().getTeamSettingsDialog();
+    }
+    
+    /**
+     * Get the commit dialog for this project
+     */
+    public CommitCommentsFrame getCommitCommentsDialog()
+    {
+        // lazy instantiation of commit comments frame
+        if(commitCommentsFrame == null) {
+            commitCommentsFrame = new CommitCommentsFrame(this);
+        }
+        return commitCommentsFrame;
+    }
+    
+    /**
+     * Get the update dialog for this project
+     */
+    public UpdateFilesFrame getUpdateDialog()
+    {
+        if (updateFilesFrame == null) {
+            updateFilesFrame = new UpdateFilesFrame(this);
+        }
+        return updateFilesFrame;
+    }
+        
+    /**
+     * Set this project as either shared or non-shared.
+     */
+    private void setProjectShared(boolean shared)
+    {
+        isSharedProject = shared;
+        teamActions.setTeamMode(shared);
+        
+        PkgMgrFrame[] frames = PkgMgrFrame.getAllProjectFrames(this);
+        if (frames != null) {
+            for (int i = 0; i < frames.length; i++) {
+                frames[i].updateSharedStatus(shared);
+            }
+        }
+    }
+    
+    /**
+     * Find the package name of the package containing the given file.
+     * Might return null if the file isn't in the package, or the directory the
+     * file is in doesn't translate to a valid package name. However, may
+     * return a valid package name which doesn't actually exist as a package
+     * in the project.
+     */
+    public String getPackageForFile(File f)
+    {
+        File projdir = getProjectDir();
+        
+        // First find out the package name...
+        String packageName = "";
+        File parentDir = f.getParentFile();
+        while (! parentDir.equals(projdir)) {
+            String parentName = parentDir.getName();
+            if (!JavaNames.isIdentifier(parentName)) {
+                return null;
+            }
+            
+            if (packageName.equals("")) {
+                packageName = parentName;
+            }
+            else {
+                packageName = parentName + "." + packageName;
+            }
+            parentDir = parentDir.getParentFile();
+            if (parentDir == null) {
+                // file not in project?
+                return null;
+            }
+        }
+        
+        return packageName;
+    }
+    
+    
+    /**
+     * Set the team settings controller for this project. This makes the
+     * project a shared project (unless the controller is null).
+     */
+    public void setTeamSettingsController(TeamSettingsController tsc)
+    {
+        teamSettingsController = tsc;
+        if (tsc != null) {
+            tsc.setProject(this);
+            tsc.writeToProject();
+        }
+        setProjectShared (tsc != null);
+    }
+
+    /**
+     * return the associated status window
+     */
+    public StatusFrame getStatusWindow(Window parent)
+    {
+        if(statusFrame == null) {
+            statusFrame = new StatusFrame(this);
+            statusFrame.setLocationRelativeTo(parent);
+        }
+        return statusFrame;
+    }
+    
+    /**
+     * Prepare for the deletion of a directory inside the project. This is
+     * a notification which allows the team management code to save the
+     * version control metadata elsewhere, if necessary.
+     */
+    public boolean prepareDeleteDir(File dir)
+    {
+        TeamSettingsController tsc = getTeamSettingsController();
+        if (tsc != null) {
+            return tsc.prepareDeleteDir(dir);
+        }
+        else {
+            return true;
+        }
+    }
+    
+    /**
+     * Prepare for the creation of a directory inside the project. This is a 
+     * notification which allows the team management code to perform any
+     * necessary metadata actions.
+     */
+    public void prepareCreateDir(File dir)
+    {
+        TeamSettingsController tsc = getTeamSettingsController();
+        if (tsc != null) {
+            tsc.prepareCreateDir(dir);
+        }
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerListener#examineDebuggerEvent(bluej.debugger.DebuggerEvent)
+     */
+    @Override
+    public boolean examineDebuggerEvent(DebuggerEvent e)
+    {
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ProjectEntityResolver.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ProjectEntityResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e4c63832663a88da6b69e819c59bb11b227fcfe
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ProjectEntityResolver.java
@@ -0,0 +1,93 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.JavaEntity;
+import bluej.parser.entity.PackageEntity;
+import bluej.parser.entity.PackageOrClass;
+import bluej.parser.entity.TypeEntity;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.Target;
+
+/**
+ * Resolve project entities.
+ * 
+ * @author Davin McCall
+ */
+public class ProjectEntityResolver implements EntityResolver
+{
+    private Project project;
+    
+    /**
+     * Construct a ProjectEntityResolver for the given project.
+     */
+    public ProjectEntityResolver(Project project)
+    {
+        this.project = project;
+    }
+    
+    public JavaEntity getValueEntity(String name, Reflective querySource)
+    {
+        return resolvePackageOrClass(name, querySource);
+    }
+
+    public PackageOrClass resolvePackageOrClass(String name, Reflective querySource)
+    {
+        // Try in java.lang
+        Class<?> cl = project.loadClass("java.lang." + name);
+        if (cl != null) {
+            return new TypeEntity(cl);
+        }
+        
+        // Have to assume it's a package
+        return new PackageEntity(name, this);
+    }
+
+    public TypeEntity resolveQualifiedClass(String name)
+    {
+        int lastDot = name.lastIndexOf('.');
+        String pkgName = lastDot != -1 ? name.substring(0, lastDot) : "";
+        String baseName = name.substring(lastDot + 1);
+        Package pkg = project.getPackage(pkgName);
+        if (pkg != null) {
+            Target target = pkg.getTarget(baseName);
+            if (target instanceof ClassTarget) {
+                ClassTarget ct = (ClassTarget) target;
+                Reflective ref = ct.getTypeRefelective();
+                if (ref != null) {
+                    return new TypeEntity(ref);
+                }
+            }
+        }
+
+        // Try as a class which might be external to the project 
+        Class<?> cl = project.loadClass(name);
+        if (cl != null) {
+            return new TypeEntity(cl);
+        }
+        
+        return null;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ProjectJavadocResolver.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ProjectJavadocResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b8731bbfe3ec3436679bf8736888dd070d588d9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ProjectJavadocResolver.java
@@ -0,0 +1,245 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.MethodReflective;
+import bluej.debugger.gentype.Reflective;
+import bluej.parser.InfoParser;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.PackageResolver;
+import bluej.parser.symtab.ClassInfo;
+import bluej.utility.Debug;
+import bluej.utility.JavaNames;
+import bluej.views.Comment;
+import bluej.views.MethodView;
+import bluej.views.View;
+
+/**
+ * Resolves javadoc from classes within a project.
+ * 
+ * @author Davin McCall
+ */
+public class ProjectJavadocResolver implements JavadocResolver
+{
+    private Project project;
+    private CommentCache commentCache = new CommentCache();
+    
+    public ProjectJavadocResolver(Project project)
+    {
+        this.project = project;
+    }
+    
+    public void getJavadoc(MethodReflective method)
+    {
+        Reflective declaring = method.getDeclaringType();
+        String declName = declaring.getName();
+        String methodSig = buildSig(method);
+        
+        try {
+            Class<?> cl = project.getClassLoader().loadClass(declName);
+            View clView = View.getView(cl);
+            MethodView [] methods = clView.getAllMethods();
+            
+            for (int i = 0; i < methods.length; i++) {
+                if (methodSig.equals(methods[i].getSignature())) {
+                    Comment comment = methods[i].getComment();
+                    if (comment != null) {
+                        method.setJavaDoc(comment.getText());
+                        List<String> paramNames = new ArrayList<String>(comment.getParamCount());
+                        for (int j = 0; j < comment.getParamCount(); j++) {
+                            paramNames.add(comment.getParamName(j));
+                        }
+                        method.setParamNames(paramNames);
+                        return;
+                    }
+                    break;
+                }
+            }
+        }
+        catch (ClassNotFoundException cnfe) {}
+        catch (LinkageError e) {}
+        
+        Properties comments = commentCache.get(declName);
+        if (comments == null) {
+            comments = getCommentsFromSource(declName);
+            if (comments == null) {
+                return;
+            }
+            commentCache.put(declName, comments);
+        }
+
+        // Find the comment for the particular method we want
+        for (int i = 0; ; i++) {
+            String comtarget = comments.getProperty("comment" + i + ".target");
+            if (comtarget == null) {
+                break;
+            }
+            if (comtarget.equals(methodSig)) {
+                method.setJavaDoc(comments.getProperty("comment" + i + ".text"));
+                String paramNames = comments.getProperty("comment" + i + ".params");
+                StringTokenizer tokenizer = new StringTokenizer(paramNames);
+                List<String> paramNamesList = new ArrayList<String>();
+                while (tokenizer.hasMoreTokens()) {
+                    paramNamesList.add(tokenizer.nextToken());
+                }
+                method.setParamNames(paramNamesList);
+                break;
+            }
+        }
+    }
+
+    /**
+     * Find the javadoc for a given class (target) by searching the project source path.
+     * In particular, this normally includes the JDK source. When source for the required
+     * class is found, it is parsed to extract comments.
+     */
+    private Properties getCommentsFromSource(String target)
+    {
+        List<DocPathEntry> sourcePath = project.getSourcePath();
+        String pkg = JavaNames.getPrefix(target);
+        String entName = target.replace('.', '/') + ".java";
+        String entNameFs = target.replace('.', File.separatorChar) + ".java";
+        EntityResolver resolver = new PackageResolver(project.getEntityResolver(), pkg);
+        
+        for (DocPathEntry pathEntry : sourcePath) {
+            File jarFile = pathEntry.getFile();
+            if (jarFile.isFile()) {
+                String fullEntryName = pathEntry.getPathPrefix();
+                if (fullEntryName.length() != 0 && !fullEntryName.endsWith("/")) {
+                    fullEntryName += "/";
+                }
+                fullEntryName += entName;
+                Reader r = null;
+                try {
+                    ZipFile zipFile = new ZipFile(jarFile);
+                    ZipEntry zipEnt = zipFile.getEntry(fullEntryName);
+                    if (zipEnt != null) {
+                        InputStream zeis = zipFile.getInputStream(zipEnt);
+                        r = new InputStreamReader(zeis, project.getProjectCharset());
+                        ClassInfo info = InfoParser.parse(r, resolver, null);
+                        if (info == null) {
+                            return null;
+                        }
+                        return info.getComments();
+                    }
+                }
+                catch (IOException ioe) {}
+                finally {
+                    if (r != null) {
+                        try {
+                            r.close();
+                        }
+                        catch (IOException e) {}
+                    }
+                }
+            }
+            else if (jarFile.isDirectory()) {
+                File base = jarFile;
+                String prefix = pathEntry.getPathPrefix();
+                if (prefix != null && !prefix.isEmpty()) {
+                    base = new File(base, prefix);
+                }
+                
+                File srcFile = new File(base, entNameFs);
+                FileInputStream fis = null;
+                try {
+                    if (srcFile.canRead()) {
+                        fis = new FileInputStream(srcFile);
+                        Reader r = new InputStreamReader(fis, project.getProjectCharset());
+                        ClassInfo info = InfoParser.parse(r, resolver, null);
+                        r.close();
+                        if (info == null) {
+                            return null;
+                        }
+                        return info.getComments();
+                    }
+                }
+                catch (IOException ioe) {
+                    if (fis != null) {
+                        try {
+                            fis.close();
+                        }
+                        catch (IOException e) {}
+                    }
+                }
+            }
+        }
+        
+        // Try and load the source from the class path. This allows source to be bundled in
+        // with the classes.
+        String targetName = target.replace('.', '/') + ".java";
+        URL srcUrl = project.getClassLoader().findResource(targetName);
+        if (srcUrl != null) {
+            try {
+                Reader r = new InputStreamReader(srcUrl.openStream(), project.getProjectCharset());
+                ClassInfo info = InfoParser.parse(r, resolver, null);
+                if (info != null) {
+                    return info.getComments();
+                }
+            }
+            catch (IOException ioe) {
+                Debug.message("I/O exception while trying to retrieve javadoc for " + target);
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Build a method signature from a MethodReflective.
+     */
+    private static String buildSig(MethodReflective method)
+    {
+        String sig = method.getReturnType().getErasedType().toString();
+        sig = sig.replace('$', '.');
+        sig += ' ';
+        
+        sig += method.getName() + '(';
+        Iterator<JavaType> i = method.getParamTypes().iterator();
+        while (i.hasNext()) {
+            JavaType ptype = i.next();
+            sig += ptype.getErasedType().toString().replace('$', '.');
+            if (i.hasNext()) {
+                sig += ", ";
+            }
+        }
+        sig += ')';
+        
+        return sig;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ProjectPrintDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ProjectPrintDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f39c8f9efb306fa1caba496e5d4e5b23c4827f7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/ProjectPrintDialog.java
@@ -0,0 +1,176 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import bluej.*;
+import bluej.Config;
+
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+
+/**
+ * Dialog for creating a new Package
+ * 
+ * @version $Id: ProjectPrintDialog.java 7055 2010-01-27 13:58:55Z plcs $
+ * @author Bruce Quig
+ */
+public class ProjectPrintDialog extends EscapeDialog
+{
+    private boolean ok; // result: which button?
+    private JCheckBox printDiagram;
+    private JCheckBox printSource;
+    private JCheckBox printReadme;
+
+    /**
+     * Creates a new ProjectPrintDialog object.
+     * 
+     * @param parent the frame that called the print dialog
+     */
+    public ProjectPrintDialog(PkgMgrFrame parent)
+    {
+        super(parent, Config.getString("pkgmgr.printDialog.title"), true);
+
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent E)
+            {
+                ok = false;
+                setVisible(false);
+            }
+        });
+
+        JPanel mainPanel = new JPanel();
+
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+        mainPanel.setBorder(BlueJTheme.dialogBorder);
+        mainPanel.add(Box.createVerticalStrut(
+                              BlueJTheme.dialogCommandButtonsVertical));
+
+        printDiagram = new JCheckBox(Config.getString("pkgmgr.printDialog.printDiagram"));
+        printDiagram.setSelected(true);
+        mainPanel.add(printDiagram);
+                
+        printSource = new JCheckBox(Config.getString("pkgmgr.printDialog.printSource"));
+        mainPanel.add(printSource);
+                
+        if(parent.getPackage().isUnnamedPackage()) {
+            printReadme = new JCheckBox(Config.getString("pkgmgr.printDialog.printReadme"));
+            mainPanel.add(printReadme);
+        }
+        mainPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+        buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+        JButton okButton = BlueJTheme.getOkButton();
+        okButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent evt) { doOK(); }        		
+        });
+        
+        JButton cancelButton = BlueJTheme.getCancelButton();
+        cancelButton.addActionListener(new ActionListener() {
+        	public void actionPerformed(ActionEvent evt) { doCancel(); }        		
+		});
+
+        DialogManager.addOKCancelButtons(buttonPanel, okButton, cancelButton);
+
+        getRootPane().setDefaultButton(okButton);
+
+        mainPanel.add(buttonPanel);
+
+        getContentPane().add(mainPanel);
+        pack();
+
+        DialogManager.centreDialog(this);
+    }
+
+    /**
+     * Show this dialog and return true if "OK" was pressed, false if
+     * cancelled.
+     * 
+     * @return the status of the print job, proceed if true, cancel if false
+     */
+    public boolean display()
+    {
+        ok = false;
+        setVisible(true);
+
+        return ok;
+    }
+
+    /**
+     * Close action called when OK button is pressed.  It only sets ok boolean
+     * flag to true as long as one of the check boxes is selected
+     */
+    public void doOK()
+    {
+        ok = (printDiagram() || printSource() || printReadme());
+        setVisible(false);
+    }
+
+    /**
+     * Close action when Cancel is pressed.
+     */
+    public void doCancel()
+    {
+        ok = false;
+        setVisible(false);
+    }
+
+    /**
+     * Print class diagram selection status
+     * 
+     * @return true if radio button is selected meaning  diagram should be
+     *         printed
+     */
+    public boolean printDiagram()
+    {
+        return printDiagram.isSelected();
+    }
+
+    /**
+     * Print all source code selection status
+     * 
+     * @return true if radio button is selected meaning  source code should be
+     *         printed
+     */
+    public boolean printSource()
+    {
+        return printSource.isSelected();
+    }
+
+    /**
+     * Print project's readme selection status
+     * 
+     * @return true if radio button is selected meaning  readme should be
+     *         printed
+     */
+    public boolean printReadme()
+    {
+        return (printReadme != null && printReadme.isSelected());
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/RunAppletDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/RunAppletDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..38796210b1d662580b3aaef2509abae7297531dd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/RunAppletDialog.java
@@ -0,0 +1,486 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.Enumeration;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+import bluej.*;
+import bluej.pkgmgr.target.role.AppletClassRole;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+
+/**
+ * Dialog for generating HTML and running applets.
+ * 
+ * @author Bruce Quig
+ */
+public class RunAppletDialog extends EscapeDialog
+    implements ListSelectionListener
+{
+    // Internationalisation
+    static final String createWebPage = Config.getString("pkgmgr.runApplet.webPageLabel");
+    static final String radioButtonText1 = Config.getString("pkgmgr.runApplet.webPage");
+    static final String radioButtonText2 = Config.getString("pkgmgr.runApplet.appletviewer");
+    static final String radioButtonText3 = Config.getString("pkgmgr.runApplet.webBrowser");
+    static final String heightLbl = Config.getString("pkgmgr.runApplet.heightLbl");
+    static final String widthLbl = Config.getString("pkgmgr.runApplet.widthLbl");
+    static final String newParameterLbl = Config.getString("pkgmgr.runApplet.newParameterLbl");
+    static final String appletParameterLbl = Config.getString("pkgmgr.runApplet.appletParameterLbl");
+    static final String nameLbl = Config.getString("pkgmgr.runApplet.nameLbl");
+    static final String valueLbl = Config.getString("pkgmgr.runApplet.valueLbl");
+
+    public static final int EXEC_APPLETVIEWER = 0;
+    public static final int EXEC_WEBBROWSER = 1;
+    public static final int GENERATE_PAGE_ONLY = 2;
+
+    private String webPageName;
+
+    private JList parameterList;
+    private DefaultListModel appletParameters;
+    private JTextField paramNameField;
+    private JTextField paramValueField;
+    private JTextField heightField;
+    private JTextField widthField;
+    private JButton addButton;
+    private JButton deleteButton;
+    private JFrame parent;
+    private JRadioButton generateWebPage;
+    private JRadioButton runAppletViewer;
+    private JRadioButton runWebBrowser;
+
+    private boolean ok; // result: which button?
+
+    public RunAppletDialog(JFrame parent, String appletClassName)
+    {
+        super(parent, Config.getString("pkgmgr.runApplet.title"), true);
+        this.parent = parent;
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent E)
+            {
+                ok = false;
+                setVisible(false);
+            }
+        });
+        JPanel mainPanel = (JPanel) getContentPane(); // has BorderLayout
+        mainPanel.setBorder(BlueJTheme.dialogBorder);
+
+        appletParameters = new DefaultListModel();
+        webPageName = appletClassName + AppletClassRole.HTML_EXTENSION;
+
+        // button panel at bottom of dialog
+        JPanel buttonPanel = new JPanel();
+        buttonPanel.setLayout(new FlowLayout());
+        buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+        JButton button;
+        buttonPanel.add(button = BlueJTheme.getOkButton());
+        button.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent evt)
+            {
+                doOK();
+            }
+        });
+        getRootPane().setDefaultButton(button);
+        buttonPanel.add(button = BlueJTheme.getCancelButton());
+        button.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent evt)
+            {
+                doCancel();
+            }
+        });
+        getContentPane().add("South", buttonPanel);
+
+        GridBagLayout gridBag = new GridBagLayout();
+        GridBagConstraints gridConstraints = new GridBagConstraints();
+        gridConstraints.insets = new Insets(5, 5, 5, 5);
+        JPanel webPanel = new JPanel();
+
+        // Radio Button group for execution options
+        ButtonGroup bGroup = new ButtonGroup();
+        JPanel radioPanel = new JPanel();
+        radioPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
+        radioPanel.setLayout(new GridLayout(3, 1));
+        generateWebPage = new JRadioButton(radioButtonText1, false);
+        radioPanel.add(generateWebPage);
+        bGroup.add(generateWebPage);
+        runAppletViewer = new JRadioButton(radioButtonText2, true);
+        radioPanel.add(runAppletViewer);
+        bGroup.add(runAppletViewer);
+        runWebBrowser = new JRadioButton(radioButtonText3, false);
+        radioPanel.add(runWebBrowser);
+        bGroup.add(runWebBrowser);
+        getContentPane().add("North", radioPanel);
+
+        webPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.darkGray),
+                BorderFactory.createEmptyBorder(10, 10, 10, 10)));
+
+        gridConstraints.weightx = 0;
+        gridConstraints.weighty = 0;
+        addGridBagComponent(webPanel, gridBag, gridConstraints, new JLabel(heightLbl), 0, 1, 1, 1,
+                GridBagConstraints.EAST);
+
+        gridConstraints.fill = GridBagConstraints.HORIZONTAL;
+        heightField = new JTextField(5);
+        gridConstraints.weightx = 1.0;
+        gridConstraints.weighty = 1.0;
+        addGridBagComponent(webPanel, gridBag, gridConstraints, heightField, 1, 1, 1, 1, GridBagConstraints.WEST);
+
+        gridConstraints.fill = GridBagConstraints.NONE;
+        gridConstraints.weightx = 0;
+        gridConstraints.weighty = 0;
+        addGridBagComponent(webPanel, gridBag, gridConstraints, new JLabel(widthLbl), 2, 1, 1, 1,
+                GridBagConstraints.EAST);
+
+        gridConstraints.fill = GridBagConstraints.HORIZONTAL;
+        gridConstraints.weightx = 1.0;
+        gridConstraints.weighty = 1.0;
+        widthField = new JTextField(5);
+        addGridBagComponent(webPanel, gridBag, gridConstraints, widthField, 3, 1, 1, 1, GridBagConstraints.WEST);
+
+        gridConstraints.fill = GridBagConstraints.NONE;
+        addGridBagComponent(webPanel, gridBag, gridConstraints, new JLabel(newParameterLbl), 5, 2, 1, 1,
+                GridBagConstraints.CENTER);
+
+        parameterList = new JList(appletParameters);
+        parameterList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        parameterList.setModel(appletParameters);
+        parameterList.addListSelectionListener(this);
+        JScrollPane parameterScroller = new JScrollPane(parameterList);
+        parameterScroller.setColumnHeaderView(new JLabel(appletParameterLbl, JLabel.CENTER));
+        
+        gridConstraints.fill = GridBagConstraints.BOTH;
+        addGridBagComponent(webPanel, gridBag, gridConstraints, parameterScroller, 0, 2, 4, 4,
+                GridBagConstraints.CENTER);
+
+        gridConstraints.fill = GridBagConstraints.NONE;
+        addGridBagComponent(webPanel, gridBag, gridConstraints, new JLabel(nameLbl), 4, 3, 1, 1,
+                GridBagConstraints.EAST);
+
+        gridConstraints.weightx = 1.0;
+        gridConstraints.weighty = 1.0;
+        gridConstraints.fill = GridBagConstraints.HORIZONTAL;
+        paramNameField = new JTextField(16);
+        addGridBagComponent(webPanel, gridBag, gridConstraints, paramNameField, 5, 3, 1, 1, GridBagConstraints.WEST);
+
+        gridConstraints.weightx = 0;
+        gridConstraints.weighty = 0;
+        gridConstraints.fill = GridBagConstraints.NONE;
+        addGridBagComponent(webPanel, gridBag, gridConstraints, new JLabel(valueLbl), 4, 4, 1, 1,
+                GridBagConstraints.EAST);
+
+        gridConstraints.weightx = 1.0;
+        gridConstraints.weighty = 1.0;
+        gridConstraints.fill = GridBagConstraints.HORIZONTAL;
+        paramValueField = new JTextField(16);
+        addGridBagComponent(webPanel, gridBag, gridConstraints, paramValueField, 5, 4, 1, 1, GridBagConstraints.WEST);
+
+        gridConstraints.weightx = 0;
+        gridConstraints.weighty = 0;
+        gridConstraints.fill = GridBagConstraints.NONE;
+        deleteButton = new JButton(Config.getString("classmgr.delete"));
+        deleteButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent evt)
+            {
+                doDelete();
+            }
+        });
+ 
+        deleteButton.setEnabled(false);
+
+        addButton = new JButton(Config.getString("classmgr.add"));
+        addButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent evt)
+            {
+                doAdd();
+            }
+        });
+        addButton.setEnabled(true);
+
+        JPanel addDeletePanel = new JPanel();
+        addDeletePanel.add(deleteButton);
+        addDeletePanel.add(addButton);
+        addGridBagComponent(webPanel, gridBag, gridConstraints, addDeletePanel, 5, 5, 1, 1, GridBagConstraints.CENTER);
+        
+        getContentPane().add("Center", webPanel);
+
+        DialogManager.centreDialog(this);
+    }
+
+    /**
+     * Method to simplify adding components to a gridbag layout and modify
+     * constraints
+     * 
+     * @param container
+     *            the container the component is to be added to
+     * @param layout
+     *            the GridBagLayout object to be used
+     * @param constraints
+     *            the GridBagConstraints object being used
+     * @param component
+     *            the component to be added
+     * @param gridx
+     *            x coordinate for component starting position
+     * @param gridy
+     *            y coordinate for component starting position
+     * @param gridWidth
+     *            number of grid cells for width of component
+     * @param gridHeight
+     *            number of grid cells for height of component
+     * @param anchor
+     *            the alignment of component within grid cell
+     */
+    private void addGridBagComponent(Container container, GridBagLayout layout, GridBagConstraints constraints,
+            Component component, int gridx, int gridy, int gridWidth, int gridHeight, int anchor)
+    {
+        constraints.gridx = gridx;
+        constraints.gridy = gridy;
+        constraints.gridwidth = gridWidth;
+        constraints.gridheight = gridHeight;
+        constraints.anchor = anchor;
+        layout.setConstraints(component, constraints);
+        // check that this layout has not already been set
+        if (!container.getLayout().equals(layout))
+            container.setLayout(layout);
+        container.add(component);
+    }
+
+    /**
+     * Show this dialog and return true if "OK" was pressed, false if cancelled.
+     */
+    public boolean display()
+    {
+        ok = false;
+        pack();
+        setVisible(true);
+        return ok;
+    }
+
+    /**
+     * Show this dialog and return true if "OK" was pressed, false if cancelled.
+     */
+    public String getWebPageName()
+    {
+        return webPageName;
+    }
+
+    /**
+     * Add a parameter to the applet parameter list.
+     */
+    public void addAppletParameter()
+    {
+
+        AppletParam param = new AppletParam(paramNameField.getText(), paramValueField.getText());
+
+        int index = appletParameters.indexOf(param);
+        if (index == -1)
+            appletParameters.addElement(param);
+        else
+            appletParameters.set(index, param);
+
+        clearInput();
+
+    }
+
+    /**
+     * clear the input fields
+     */
+    private void clearInput()
+    {
+        paramNameField.setText("");
+        paramValueField.setText("");
+    }
+
+    /**
+     * Clear list selection and input fields. Based on the assumption we don't
+     * want them next time.
+     */
+    private void prepareForClosure()
+    {
+        clearInput();
+        parameterList.getSelectionModel().clearSelection();
+    }
+
+    /**
+     * Close action when OK is pressed.
+     */
+    public void doOK()
+    {
+        if (!checkFieldsAreValid()) {
+            DialogManager.showError(parent, "applet-height-width");
+        }
+        else { // collect information from fields
+            ok = true;
+            prepareForClosure();
+            setVisible(false);
+        }
+    }
+
+    /**
+     * Close action when Cancel is pressed.
+     */
+    public void doCancel()
+    {
+        ok = false;
+        prepareForClosure();
+        setVisible(false);
+    }
+
+    public void doAdd()
+    {
+        if (!paramNameField.getText().equals("") && !paramValueField.getText().equals("")) {
+            addAppletParameter();
+            parameterList.getSelectionModel().clearSelection();
+            paramNameField.requestFocus();
+        }
+    }
+
+    public void doDelete()
+    {
+        appletParameters.remove(parameterList.getSelectedIndex());
+        clearInput();
+        deleteButton.setEnabled(false);
+    }
+
+    /**
+     * Check that required fields have entries. There is no checking the
+     * validity of what is entered.
+     * 
+     * @return true if both width and height fields are not empty
+     */
+    public boolean checkFieldsAreValid()
+    {
+        return (!widthField.getText().equals("") && !heightField.getText().equals(""));
+    }
+
+    /**
+     * Returns height of height text field.
+     * 
+     * @return height of applet as a String
+     */
+    public String getAppletHeight()
+    {
+        return heightField.getText();
+    }
+
+    /**
+     * Returns value of width text field.
+     * 
+     * @return width of Applet as a String
+     */
+    public String getAppletWidth()
+    {
+        return widthField.getText();
+    }
+
+    /**
+     * sets value of height text field.
+     * 
+     * @param height
+     *            value to set in field
+     */
+    public void setAppletHeight(int height)
+    {
+        heightField.setText(String.valueOf(height));
+    }
+
+    /**
+     * sets value of width text field.
+     * 
+     * @param width
+     *            value to set in field
+     */
+    public void setAppletWidth(int width)
+    {
+        widthField.setText(String.valueOf(width));
+    }
+
+    /**
+     * Returns applet parameters.
+     * 
+     * @return applet parameters as an array of Strings or null if no parameters
+     */
+    public String[] getAppletParameters()
+    {
+        String[] paramStringArray = new String[appletParameters.size()];
+        Enumeration<?> e = appletParameters.elements();
+        for (int i = 0; e.hasMoreElements() && i < paramStringArray.length; i++) {
+            AppletParam ap = (AppletParam) e.nextElement();
+            paramStringArray[i] = ap.toString();
+        }
+        return paramStringArray;
+    }
+
+    /**
+     * Set applet parameters as an array of Strings or null if no parameters
+     */
+    public void setAppletParameters(String[] parameters)
+    {
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                appletParameters.addElement(new AppletParam(parameters[i]));
+            }
+        }
+    }
+
+    /**
+     * Returns an int representing the radio button chosen for execution option.
+     * 
+     * @return int representing index of radio button selected
+     */
+    public int getAppletExecutionOption()
+    {
+        if (runAppletViewer.isSelected()) {
+            return EXEC_APPLETVIEWER;
+        }
+        else if (runWebBrowser.isSelected()) {
+            return EXEC_WEBBROWSER;
+        }
+        else {
+            return GENERATE_PAGE_ONLY;
+        }
+    }
+
+    // ----- ListSelectionListener interface -----
+
+    /**
+     * The value of the list selection has changed.
+     */
+    public void valueChanged(ListSelectionEvent e)
+    {
+        //if(e.getValueIsAdjusting()) // ignore mouse down, dragging, etc.
+        //    return;
+        if (!parameterList.isSelectionEmpty()) {
+            deleteButton.setEnabled(true);
+            AppletParam param = (AppletParam) parameterList.getSelectedValue();
+            paramNameField.setText(param.getParamName());
+            paramValueField.setText(param.getParamValue());
+        }
+
+    }
+
+    // ----- end of ListSelectionListener interface -----
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/SourceInfo.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/SourceInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..e912085ad588a722de255c7750701bfd6ec30266
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/SourceInfo.java
@@ -0,0 +1,84 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import bluej.parser.InfoParser;
+import bluej.parser.symtab.ClassInfo;
+
+/**
+ * A container holding information about a class's source file. The
+ * information is collected mainly by the class parser, and used for
+ * automatic editing of the source.
+ *
+ * @author  Michael Kolling
+ * @version $Id: SourceInfo.java 8295 2010-09-10 06:03:56Z davmac $
+ */
+public final class SourceInfo
+{
+    private boolean valid;
+    private ClassInfo info;
+
+    public SourceInfo()
+    {
+        valid = true;
+        info = null;
+    }
+
+    public boolean isValid()
+    {
+        return valid;
+    }
+
+    public void setSourceModified()
+    {
+        info = null;
+    }
+
+    public ClassInfo getInfo(File sourceFile, Package pkg)
+    {
+        if(info == null)
+        {
+            try {
+                info = InfoParser.parse(sourceFile, pkg);
+                valid = info != null && ! info.hadParseError();
+            }
+            catch (FileNotFoundException fnfe) {
+                info = null;
+                valid = false;
+            }
+        }
+
+        return info;
+    }
+
+    /**
+     * Similar to getInfo, but do not parse if info is not available.
+     * Instead, return null, if we got no info.
+     */
+    public ClassInfo getInfoIfAvailable()
+    {
+        return info;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/TestRunnerThread.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/TestRunnerThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..beb2cf9ec985809b193e82e369ae79c59e90e94b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/TestRunnerThread.java
@@ -0,0 +1,166 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.EventQueue;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import bluej.Config;
+import bluej.debugger.DebuggerTestResult;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.role.UnitTestClassRole;
+import bluej.testmgr.TestDisplayFrame;
+
+/**
+ * Provide a thread class for running unit tests.
+ * 
+ * Unit tests are user code so they must be executed on a seperate thread.
+ * This class provides the means to do this.
+ * 
+ * There are two primary modes of operation: run a single test (methodname != null),
+ * and run all tests for a series of ClassTargets.
+ * 
+ * @author Davin McCall
+ */
+public class TestRunnerThread extends Thread
+{
+    private Iterator<ClassTarget> testIterator;
+    private DebuggerTestResult lastResult = null;
+    private PkgMgrFrame pmf;
+
+    private ClassTarget ct;
+    private String[] allMethods;
+    private String methodName; // Name of the test method; null to run all tests.
+    
+    private int state;
+    
+    /**
+     * Construct a test runner thread for running multiple tests.
+     */
+    public TestRunnerThread(PkgMgrFrame pmf, Iterator<ClassTarget> i)
+    {
+        this.pmf = pmf;
+        testIterator = i;
+        state = 0;
+    }
+    
+    /**
+     * Construct a test runner thread for running a single test.
+     */
+    public TestRunnerThread(PkgMgrFrame pmf, ClassTarget ct, String methodName)
+    {
+        this.pmf = pmf;
+        List<ClassTarget> l = new ArrayList<ClassTarget>(1);
+        l.add(ct);
+        testIterator = l.iterator();
+        this.methodName = methodName;
+        state = 0;
+    }
+    
+    /**
+     * Set the methods to be tested. The UnitTestClassRole calls this after determining
+     * which methods should be run.
+     * 
+     * @param methods  An array of method names
+     */
+    public void setMethods(String [] methods)
+    {
+        allMethods = methods;
+    }
+    
+    public void run()
+    {
+        // This implements a state machine. State 0 is the first state, and consists of
+        // the primary loop from which the other states are executed
+        // (via EventQueue.invokeAndWait).
+        
+        switch (state) {
+            case 0:
+                try {
+                    while (testIterator.hasNext()) {
+                        
+                        ct = (ClassTarget) testIterator.next();
+                        
+                        if (methodName == null) {
+                            // Run all tests for a target.
+                            state = 1;
+                            EventQueue.invokeAndWait(this);
+                        }
+                        else {
+                            // Run only a single test.
+                            allMethods = new String [] { methodName };
+                        }
+                        
+                        // State 1 has given us the tests we need to run. Now run them:
+                        for (int i = 0; i < allMethods.length; i++) {
+                            lastResult = pmf.getProject().getDebugger().runTestMethod(ct.getQualifiedName(), allMethods[i]);
+                            
+                            // Add the test result to the test display frame in state 2:
+                            state = 2;
+                            EventQueue.invokeAndWait(this);
+                        }
+                    }
+                    
+                    // Finally, tell the PkgMgrFrame that we're done:
+                    state = 3;
+                    EventQueue.invokeAndWait(this);
+                }
+                catch (InvocationTargetException ite) { ite.printStackTrace(); }
+                catch (InterruptedException ie) {}
+                break;
+                
+            // State 1 is where we confirm that we really do have an executable unit
+            // test class, and we delegate to the unit test role to gives us some
+            // test methods to executed.
+            case 1:
+                if (ct.isCompiled() && ct.isUnitTest() && ! ct.isAbstract()) {
+                    UnitTestClassRole utcr = (UnitTestClassRole) ct.getRole();
+
+                    utcr.doRunTest(pmf, ct, TestRunnerThread.this);
+                }
+                else {
+                    allMethods = new String[0];
+                }
+                break;
+                
+            // Here we add a test result to the test display frame.
+            case 2:
+                boolean quiet = methodName != null && lastResult.isSuccess();
+                TestDisplayFrame.getTestDisplay().addResult(lastResult, quiet);
+                
+                if (quiet)
+                    pmf.setStatus(methodName + " " + Config.getString("pkgmgr.test.succeeded"));
+
+                break;
+
+            // Now we are finished.
+            case 3:
+                if (methodName == null)
+                    pmf.endTestRun();
+                
+                break;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/VersionCheckDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/VersionCheckDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..1953ac6d1fab67abf583213e4f7fac4f1025f1e7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/VersionCheckDialog.java
@@ -0,0 +1,257 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.URL;
+
+import javax.swing.*;
+
+import bluej.*;
+import bluej.utility.*;
+
+/**
+ * Dialog implementing version check functionality.
+ *
+ * @author  Michael Kolling
+ * @version $Id: VersionCheckDialog.java 7055 2010-01-27 13:58:55Z plcs $
+ */
+
+final public class VersionCheckDialog extends EscapeDialog
+     implements ActionListener
+{
+    // Internationalisation
+    private static final String close = Config.getString("close");
+    private static final String check = Config.getString("pkgmgr.versionDlg.check");
+    private static final String dialogTitle = Config.getString("pkgmgr.versionDlg.title");
+    private static final String helpLine1 = Config.getString("pkgmgr.versionDlg.helpLine1");
+    private static final String helpLine2 = Config.getString("pkgmgr.versionDlg.helpLine2");
+
+    private static final String versionURL = Config.getPropString("bluej.url.versionCheck");
+
+    private JTextArea textArea;
+    private JButton closeButton;
+
+    private String newVersion = null;
+    private Thread versionThread = null;
+    private boolean isClosed = false;
+
+    /**
+     * Create a new version check dialogue and make it visible.
+     */
+    public VersionCheckDialog(PkgMgrFrame parent)
+    {
+        super(parent, dialogTitle, true);
+        makeDialog();
+        setVisible(true);
+    }
+
+    /**
+     * A button was pressed. Check which one and do the right thing.
+     */
+    public void actionPerformed(ActionEvent evt)
+    {
+        String cmd = evt.getActionCommand();
+        if(check.equals(cmd)) {
+            doVersionCheck();
+            getRootPane().setDefaultButton(closeButton);
+        }
+        else if(close.equals(cmd))
+            doClose();
+    }
+
+    /**
+     * Action when Close is pressed.
+     */
+    private void doClose()
+    {
+        isClosed = true;
+        setVisible(false);
+    }
+
+    /**
+     * Perform a version check. 
+     */
+    private void doVersionCheck()
+    {
+        versionThread = new VersionChecker();
+        //versionThread.setPriority(Thread.MIN_PRIORITY);
+        versionThread.start();
+    }
+
+
+
+    /**
+     * Create the dialog interface.
+     */
+    private void makeDialog()
+    {
+        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+
+        JPanel mainPanel = new JPanel();
+        {
+            mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+            mainPanel.setBorder(BlueJTheme.dialogBorder);
+
+            JLabel helpText1 = new JLabel(helpLine1);
+            mainPanel.add(helpText1);
+
+            JLabel helpText2 = new JLabel(helpLine2);
+            mainPanel.add(helpText2);
+
+            Font smallFont = helpText1.getFont().deriveFont(10);
+            helpText1.setFont(smallFont);
+            helpText2.setFont(smallFont);
+
+            mainPanel.add(Box.createVerticalStrut(5));
+
+            textArea = new JTextArea(14, 46);
+            textArea.setEditable(false);
+            JScrollPane scrollPane = new JScrollPane(textArea);
+
+            mainPanel.add(scrollPane);
+            mainPanel.add(Box.createVerticalStrut(BlueJTheme.dialogCommandButtonsVertical));
+
+            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+            {
+                buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                JButton checkButton = new JButton(check);
+                checkButton.addActionListener(this);
+
+                closeButton = new JButton(close);
+                closeButton.addActionListener(this);
+
+                DialogManager.addOKCancelButtons(buttonPanel, checkButton, closeButton);
+
+                getRootPane().setDefaultButton(checkButton);
+                checkButton.requestFocus();
+
+                // try to make the OK and cancel buttons have equal width
+                closeButton.setPreferredSize(
+                                 new Dimension(checkButton.getPreferredSize().width,
+                                 closeButton.getPreferredSize().height));
+            }
+
+            mainPanel.add(buttonPanel);
+        }
+
+        getContentPane().add(mainPanel);
+        pack();
+
+        DialogManager.centreDialog(this);
+    }
+
+
+    /**
+     * Private class to run the actual version checking in separate thread.
+     */
+    private class VersionChecker extends Thread
+    {
+        public VersionChecker()
+        {
+        }
+
+        /**
+         * Do a version check. That is: open a URL connection to the remote 
+         * version file and read it. Display version info as appropriate.
+         */
+        public void run()
+        {
+            textArea.setText(Config.getString("pkgmgr.checkingVersion"));
+            try {
+                InputStream is = new URL(versionURL).openStream();
+                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+                
+                if(isOutOfDate(reader)) {
+                    if(!isClosed)
+                        displayNewVersionInfo(reader);
+                }
+                else {
+                    if(!isClosed)
+                        textArea.setText(Config.getString("pkgmgr.versionDlg.upToDate"));
+                }
+            }
+            catch(IOException exc) {
+                if(!isClosed)
+                    textArea.setText("Error: could not access remote version information");
+                Debug.reportError("IO error when trying to access URL\n" + exc);
+            }
+        }
+
+        /**
+         * Given a reader for the (remote) version file, check whether this
+         * version is out of date. We know that the first line of the version
+         * file contains the up-to-date version number.
+         */
+        private boolean isOutOfDate(BufferedReader versionReader)
+        {
+            try {
+                newVersion = versionReader.readLine();
+                if(newVersion != null)
+                    newVersion = newVersion.trim();
+            }
+            catch(IOException exc) {
+                textArea.setText("Error: could not read remote version information");
+                Debug.reportError("IO error when reading remote version info\n" + exc);
+            }
+            return ! Boot.BLUEJ_VERSION.equals(newVersion);
+        }
+
+        /**
+         * Given a reader for the (remote) version file, read the version
+         * info text out of it and display it in the text area.
+         */
+        private void displayNewVersionInfo(BufferedReader versionReader)
+        {
+            if(newVersion == null)
+                textArea.setText("Error: could not read remote version info");
+            else {
+                textArea.setText(Config.getString("pkgmgr.versionDlg.currentVersion"));
+                textArea.append(" ");
+                textArea.append(Boot.BLUEJ_VERSION);
+                textArea.append("\n");
+                textArea.append(Config.getString("pkgmgr.versionDlg.newVersion"));
+                textArea.append(" ");
+                textArea.append(newVersion);
+                textArea.append("\n");
+
+                try {
+                    String line = versionReader.readLine();
+                    while(line != null) {
+                        textArea.append(line);
+                        textArea.append("\n");
+                        line = versionReader.readLine();
+                    }
+                }
+                catch(IOException exc) {
+                    Debug.reportError("IO error when reading from version file");
+                }
+                textArea.setCaretPosition(0);
+            }
+        }
+
+    } // end class VersionChecker
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/AddClassAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/AddClassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..6ff8287c27229cd695b888965553fd3970b678e9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/AddClassAction.java
@@ -0,0 +1,46 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "Add class from file" command. This allows the user to add into the current
+ * project a class from another project or an external source.
+ * 
+ * @author Davin McCall
+ * @version $Id: AddClassAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+final public class AddClassAction extends PkgMgrAction
+{
+    public AddClassAction()
+    {
+        super("menu.edit.addClass");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doAddFromFile();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CancelTestRecordAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CancelTestRecordAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b3b0b504ec3178015080c9c479e954b4be276bc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CancelTestRecordAction.java
@@ -0,0 +1,60 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Cancel recording of a test method. Also removes from the bench objects which
+ * were created since recording began.
+ * 
+ * @author Davin McCall
+ * @version $Id: CancelTestRecordAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class CancelTestRecordAction extends PkgMgrAction
+{
+    static private CancelTestRecordAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public CancelTestRecordAction getInstance()
+    {
+        if(instance == null)
+            instance = new CancelTestRecordAction();
+        return instance;
+    }
+    
+    private CancelTestRecordAction()
+    {
+        super("menu.tools.cancel");
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.test.cancel"));
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.doCancelTest();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CheckExtensionsAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CheckExtensionsAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..e792cd9ed9731bd6d87b04fea5727340d6e5d57f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CheckExtensionsAction.java
@@ -0,0 +1,61 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.extmgr.ExtensionsManager;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Check installed extensions. Pop up a dialog box displaying summary info
+ * about each installed extension, allowing user to get a brief description
+ * of each one.
+ * 
+ * @author Davin McCall
+ * @version $Id: CheckExtensionsAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public final class CheckExtensionsAction extends PkgMgrAction {
+    
+    static private CheckExtensionsAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public CheckExtensionsAction getInstance()
+    {
+        if(instance == null)
+            instance = new CheckExtensionsAction();
+        return instance;
+    }
+    
+    private CheckExtensionsAction()
+    {
+        super("menu.help.extensions");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        ExtensionsManager.getInstance().showHelp(pmf);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CheckVersionAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CheckVersionAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..45153534cb7fbb57a0e735a3972cff000025bd15
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CheckVersionAction.java
@@ -0,0 +1,61 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.VersionCheckDialog;
+
+/**
+ * help...check for new version. Displays a dialog box with a "check version"
+ * button, when pressed queries the web server to see if a newer version of
+ * BlueJ is available.
+ * 
+ * @author Davin McCall
+ * @version $Id: CheckVersionAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class CheckVersionAction extends PkgMgrAction {
+    
+    static private CheckVersionAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public CheckVersionAction getInstance()
+    {
+        if(instance == null)
+            instance = new CheckVersionAction();
+        return instance;
+    }
+
+    private CheckVersionAction()
+    {
+        super("menu.help.versionCheck");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        new VersionCheckDialog(pmf);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CloseProjectAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CloseProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..1423c135a2758023b616a21af49fdb01fdfd8712
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CloseProjectAction.java
@@ -0,0 +1,46 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * User chooses "close project". Save & close the current project. If the command
+ * was issued from a menu, always keep the last window open, otherwise close
+ * the window regardless.
+ * 
+ * @author Davin McCall
+ * @version $Id: CloseProjectAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class CloseProjectAction extends PkgMgrAction
+{
+    public CloseProjectAction()
+    {
+        super("menu.package.close");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doClose(true, true);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CompileAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CompileAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..05d28545bfec313d1e13659abccfe416831dbcce
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CompileAction.java
@@ -0,0 +1,47 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "Compile" command. Compiles all class files in the project which need to
+ * be compiled.
+ * 
+ * @author Davin McCall
+ * @version $Id: CompileAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class CompileAction extends PkgMgrAction
+{
+    public CompileAction()
+    {
+        super("menu.tools.compile");
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.compile"));
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.getPackage().compile();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CompileSelectedAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CompileSelectedAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee4152b5993feefe3433b64e9e7abd340b546bc4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/CompileSelectedAction.java
@@ -0,0 +1,44 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "Compile selected" command. Compiles the selected classes.
+ * 
+ * @author Davin McCall
+ * @version $Id: CompileSelectedAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class CompileSelectedAction extends PkgMgrAction
+{
+    public CompileSelectedAction()
+    {
+        super("menu.tools.compileSelected");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.compileSelected();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/DeployMIDletAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/DeployMIDletAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3c6f011c95bfb73440348a7d05869ce855a371f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/DeployMIDletAction.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Deploys the MIDlet suite contained in the Java ME project.
+ * 
+ * @author Cecilia Vargas
+ */
+final public class DeployMIDletAction extends PkgMgrAction
+{
+    public DeployMIDletAction()
+    {
+        super( "menu.package.deploy.MIDlet" );
+        putValue( SHORT_DESCRIPTION, Config.getString( "tooltip.deployMIDlet" ) );
+    }
+    
+    public void actionPerformed( PkgMgrFrame pmf )
+    {
+        pmf.menuCall();
+        pmf.doDeployMIDlet();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/EndTestRecordAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/EndTestRecordAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..f99d600df5a0a8fad88242a243da92fb1290c63f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/EndTestRecordAction.java
@@ -0,0 +1,61 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * End a recording of a test method. Creates a new test case class and
+ * compiles it. Removes objects from the bench which were created since
+ * recording began.
+ * 
+ * @author Davin McCall
+ * @version $Id: EndTestRecordAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class EndTestRecordAction extends PkgMgrAction
+{
+    static private EndTestRecordAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public EndTestRecordAction getInstance()
+    {
+        if(instance == null)
+            instance = new EndTestRecordAction();
+        return instance;
+    }
+    
+    private EndTestRecordAction()
+    {
+        super("menu.tools.end");
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.test.end"));
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.doEndTest();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ExportProjectAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ExportProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..785014d00d70988432fc7611dbc5eb92cd13addb
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ExportProjectAction.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Export to external package. Allow the user to export the project to a
+ * directory structure or Jar file.
+ * 
+ * @author Davin McCall
+ * @version $Id: ExportProjectAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class ExportProjectAction extends PkgMgrAction
+{
+    public ExportProjectAction()
+    {
+        super("menu.package.export");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doExport();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/GenerateDocsAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/GenerateDocsAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..991cc4b699eab956132039bb78856a7e5bce2244
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/GenerateDocsAction.java
@@ -0,0 +1,46 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "Project Documentation" command. Generate the documentation for all classes
+ * using javadoc. Attempt to display the generated documentation using a web
+ * browser.
+ * 
+ * @author Davin McCall
+ * @version $Id: GenerateDocsAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class GenerateDocsAction extends PkgMgrAction
+{
+    public GenerateDocsAction()
+    {
+        super("menu.tools.generateDoc");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.generateProjectDocumentation();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/HelpAboutAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/HelpAboutAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f7bd0676729faa19dbe771ad960f7ec7f975ccc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/HelpAboutAction.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * help...about. Display a brief info dialog on BlueJ.
+ * 
+ * @author Davin McCall
+ * @version $Id: HelpAboutAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class HelpAboutAction extends PkgMgrAction {
+    
+    static private HelpAboutAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public HelpAboutAction getInstance()
+    {
+        if(instance == null)
+            instance = new HelpAboutAction();
+        return instance;
+    }
+    
+    private HelpAboutAction()
+    {
+        super("menu.help.about");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.aboutBlueJ();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ImportProjectAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ImportProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..0541e66c5dfd71206bed9340fe2d83b46a83a389
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ImportProjectAction.java
@@ -0,0 +1,44 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Import external project (directory structure / jar file).
+ * 
+ * @author Davin McCall
+ * @version $Id: ImportProjectAction.java 6215 2009-03-30 13:28:25Z polle $ 
+ */
+final public class ImportProjectAction extends PkgMgrAction
+{
+    public ImportProjectAction()
+    {
+        super("menu.package.import");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doImport();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewClassAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewClassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..f14fb8585a65dacc13ac28b6faed1a4d76368e18
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewClassAction.java
@@ -0,0 +1,48 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "New Class" command. Create a new class in the package, allow the user
+ * to enter the name of the class and specify its type (abstract, interface,
+ * applet, etc)
+ * 
+ * @author Davin McCall
+ * @version $Id: NewClassAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class NewClassAction extends PkgMgrAction
+{
+    public NewClassAction()
+    {
+        super("menu.edit.newClass");
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.newClass"));
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doCreateNewClass();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewInheritsAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewInheritsAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..89aaafa5dc848d6f23d73e16a5eae739cdc2da7a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewInheritsAction.java
@@ -0,0 +1,49 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "New 'inherits' relationship" command. User can select two classes to
+ * create an inheritance relationship between them. The relationship is also
+ * inserted into the code ("class A extends B"...).
+ * 
+ * @author Davin McCall
+ * @version $Id: NewInheritsAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class NewInheritsAction extends PkgMgrAction
+{
+    public NewInheritsAction()
+    {
+        super("menu.edit.newInherits");
+        putValue(SMALL_ICON, Config.getImageAsIcon("image.build.extends"));
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.newExtends"));
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.clearStatus();
+        pmf.doNewInherits();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewMEprojectAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewMEprojectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..7627b985f533f1e295a057c3006b01008670283b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewMEprojectAction.java
@@ -0,0 +1,56 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Java ME Project action. User chooses "create new ME project". This prompts for a
+ * project name, creates the directory, and displays the new project in a new window.
+ * 
+ * @author Cecilia Vargas (based on Davin McCall's NewProjectAction)
+ * @version $Id: NewProjectAction.java 2505 2004-04-21 01:50:28Z davmac $
+ */
+
+final public class NewMEprojectAction extends PkgMgrAction {
+    
+    static private NewMEprojectAction instance = null;
+    
+    private NewMEprojectAction()  { super("menu.mepackage.new"); }
+    
+    /**
+     * Factory method to retrieve an instance of the class as constructor is private.
+     * @return an instance of the class.
+     */
+    static public NewMEprojectAction getInstance()
+    {
+        if(instance == null)
+            instance = new NewMEprojectAction();
+        return instance;
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doNewProject( true );  //pass true because we are creating an ME project
+    }                        
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewPackageAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewPackageAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..4729e4cee66998248bca75cf6edf5ffe29e5a174
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewPackageAction.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "New Package" command. Allows the user to create a new sub-package with a
+ * specified name.
+ * 
+ * @author Davin McCall
+ * @version $Id: NewPackageAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class NewPackageAction extends PkgMgrAction
+{
+    public NewPackageAction()
+    {
+        super("menu.edit.newPackage");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doCreateNewPackage();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewProjectAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..154e0d053fbc767494aca80692531c4b0c701f38
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewProjectAction.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+
+/**
+ * Project action. User chooses "create new project". This prompts for a
+ * choice of project name, creates the directory, and displays the new
+ * project in a new window.
+ * 
+ * @author Davin McCall
+ * @version $Id: NewProjectAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+final public class NewProjectAction extends PkgMgrAction {
+    
+    static private NewProjectAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public NewProjectAction getInstance()
+    {
+        if(instance == null)
+            instance = new NewProjectAction();
+        return instance;
+    }
+    
+    private NewProjectAction()
+    {
+        super("menu.package.new");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doNewProject( false ); //pass false because we are not creating an ME project
+    }                        
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewUsesAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewUsesAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..0753c61db9baa3d98cc452aa7ec740d2c765bc3b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/NewUsesAction.java
@@ -0,0 +1,49 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "New 'Uses' relationship" command. User chooses two classes and a "uses"
+ * relationship is created between them on the graph.
+ * 
+ * @author Davin McCall
+ * @version $Id: NewUsesAction.java 6215 2009-03-30 13:28:25Z polle $  
+ */
+
+final public class NewUsesAction extends PkgMgrAction
+{
+    public NewUsesAction()
+    {
+        super("menu.edit.newUses");
+        putValue(SMALL_ICON, Config.getImageAsIcon("image.build.depends"));
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.newUses"));
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.clearStatus();
+        pmf.doNewUses(); 
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/OpenNonBlueJAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/OpenNonBlueJAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..ffacdd0e487d289c0e429fd8b1369e4f8e826577
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/OpenNonBlueJAction.java
@@ -0,0 +1,56 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * User chooses "open non-BlueJ". This allows them to choose a directory to
+ * open as a project.
+ */
+final public class OpenNonBlueJAction extends PkgMgrAction {
+    
+    static private OpenNonBlueJAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public OpenNonBlueJAction getInstance()
+    {
+        if(instance == null)
+            instance = new OpenNonBlueJAction();
+        return instance;
+    }
+    
+    private OpenNonBlueJAction()
+    {
+        super("menu.package.openNonBlueJ");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doOpenNonBlueJ();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/OpenProjectAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/OpenProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..55c56b91a629f7ed2b75750065789e1f8346d9c8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/OpenProjectAction.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * User chooses "open existing project". Allows for opening a blueJ project
+ * into a new window or (if no project is currently open) into the current
+ * window.
+ */
+
+final public class OpenProjectAction extends PkgMgrAction {
+    
+    static private OpenProjectAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public OpenProjectAction getInstance()
+    {
+        if(instance == null)
+            instance = new OpenProjectAction();
+        return instance;
+    }
+    
+    private OpenProjectAction()
+    {
+        super("menu.package.open");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doOpen();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PageSetupAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PageSetupAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d97f68aca691c0b15f1fb445fd8699664186477
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PageSetupAction.java
@@ -0,0 +1,44 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Page setup, for printing. Specify page layout etc via a dialog box.
+ * 
+ * @author Davin McCall
+ * @version $Id: PageSetupAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class PageSetupAction extends PkgMgrAction
+{
+    public PageSetupAction()
+    {
+        super("menu.package.pageSetup");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doPageSetup();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PkgMgrAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PkgMgrAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..85d053b173775303ddc7c643842bbd1539a149dc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PkgMgrAction.java
@@ -0,0 +1,150 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import java.awt.Component;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+
+import javax.swing.*;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * This class is intended to act as a base class for actions which require
+ * a reference to the PkgMgrFrame object.<p>
+ * 
+ * It translates the "name" of the action in the sub-class automatically.
+ * It can also set-up an accelerator key.
+ * 
+ * @author Davin McCall
+ * @version $Id: PkgMgrAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public abstract class PkgMgrAction extends AbstractAction {
+        
+    // --------- CLASS VARIABLES ----------
+
+    protected static final int SHORTCUT_MASK =
+        Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+    
+    
+    // --------- STATIC METHODS ------------
+    
+    /**
+     * From some event go up the component hiearchy from the source of the event until the
+     * PkgMgrFrame is found. This also handles the case where the source is a menu item on
+     * a popup menu.
+     * 
+     * @param event     The event for which to find the frame.
+     * @return      The discovered frame (or null).
+     */
+    public static PkgMgrFrame frameFromEvent(ActionEvent event)
+    {
+        Component jc = (Component)event.getSource();
+        while( jc != null ) {            
+             //System.out.println("hello " + jc.getClass().getName());
+             //System.out.flush();
+            
+            if( jc instanceof PkgMgrFrame ) {
+                break;
+            }
+            
+            if( jc instanceof JPopupMenu ) {
+                jc = ((JPopupMenu)jc).getInvoker();
+            }
+            else {
+                jc = jc.getParent();
+            }
+        }                
+        return (PkgMgrFrame)jc;
+    }
+    
+    
+    // --------- INSTANCE METHODS ----------
+    
+    public PkgMgrAction(String s)
+    { 
+        super(Config.getString(s)); 
+        if (!Config.isMacOS()){
+        	// Mnemonic keys are against the apple gui guidelines.
+        	putValue(MNEMONIC_KEY, new Integer(Config.getMnemonicKey(s)));
+        }
+        if (Config.hasAcceleratorKey(s)){
+            putValue(ACCELERATOR_KEY, Config.getAcceleratorKey(s));
+        }
+    }
+    
+    /**
+     * Constructor for an action with an accelerator key. The default shift
+     * modifiers are used.
+     * @param s         the untranslated action "name" (label)
+     * @param keycode       the keycode of the accelerator key (one of
+     *                          KeyEvent.*)
+     */
+    public PkgMgrAction(String s, int keycode)
+    {
+        super(Config.getString(s));
+        KeyStroke ks = KeyStroke.getKeyStroke(keycode, SHORTCUT_MASK);
+        putValue(ACCELERATOR_KEY, ks);
+    }
+    
+    /**
+     * Constructor for an action with an accelerator key, not using the default modifiers.
+     * @param s         the untranslated action "name" (menu label)
+     * @param keycode       the keycode of the accelerator key (one of KeyEvent.*)
+     * @param modifiers     the shift modifiers for the accelerator key (Event.*)
+     */
+    public PkgMgrAction(String s, int keycode, int modifiers)
+    {
+
+        super(Config.getString(s));
+        KeyStroke ks = KeyStroke.getKeyStroke(keycode, modifiers);
+        putValue(ACCELERATOR_KEY, ks);
+    }
+    
+    /**
+     * Retrieve the "toggle model" if any of an action. An action only has a toggle
+     * model if it has an assosciated boolean state which should be displayed as a check
+     * box.
+     * 
+     * By default there is no toggle model.
+     * 
+     * @return the toggle model for this action (or null).
+     */
+    public ButtonModel getToggleModel(PkgMgrFrame pmf)
+    {
+        return null;
+    }
+        
+    final public void actionPerformed(ActionEvent event)
+    {
+        PkgMgrFrame pmf = frameFromEvent(event);
+        actionPerformed(pmf);
+    }
+        
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        // default is to do nothing.
+    }
+}
+    
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PreferencesAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PreferencesAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f5fe5f9d5bdafbc4e42484c917c543650fb4666
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PreferencesAction.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "Preferences" command. Displays a dialog box in which user can set various
+ * preferences as to how BlueJ should behave.
+ * 
+ * @author Davin McCall
+ */
+final public class PreferencesAction extends PkgMgrAction {
+    
+    static private PreferencesAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public PreferencesAction getInstance()
+    {
+        if(instance == null)
+            instance = new PreferencesAction();
+        return instance;
+    }
+    
+    private PreferencesAction()
+    {
+        super("menu.tools.preferences");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.showPreferences();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PrintAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PrintAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..de54e87333eae572a95aa3f91ccde4928aec5966
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/PrintAction.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Print command. Allow user to print any of the class diagram, source code,
+ * and project "README".
+ * 
+ * @author Davin McCall
+ * @version $Id: PrintAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class PrintAction extends PkgMgrAction
+{
+    public PrintAction()
+    {
+        super("menu.package.print");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doPrint();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/QuitAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/QuitAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..40d10ea69d30a8ef3443aee0618b8de1fce14429
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/QuitAction.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Quit command. Save all projects, close all windows.
+ * 
+ * @author Davin McCall
+ * @version $Id: QuitAction.java 9277 2011-11-01 12:17:20Z mik $
+ */
+final public class QuitAction extends PkgMgrAction {
+    
+    static private QuitAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public QuitAction getInstance()
+    {
+        if(instance == null)
+            instance = new QuitAction();
+        return instance;
+    }
+    
+    private QuitAction()
+    {
+        super("menu.package.quit");
+    }
+    
+    @Override
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall(); 
+        bluej.Main.wantToQuit();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RebuildAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RebuildAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..4bd583940b5f1b3df7cfa68e557a696952a446d4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RebuildAction.java
@@ -0,0 +1,46 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "Rebuild package" command. Re-compiles all classes regardless of whether
+ * they need it or not (!).
+ * 
+ * @author Davin McCall
+ * @version $Id: RebuildAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+final public class RebuildAction extends PkgMgrAction
+{
+    public RebuildAction()
+    {
+        super("menu.tools.rebuild");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.getPackage().rebuild();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RemoveAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RemoveAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c4ed9c21d9ecddd7998df4bde48013ec8a6f285
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RemoveAction.java
@@ -0,0 +1,46 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "Remove (class/relation/package)" command. Remove an item from the
+ * graph. If it's a class/package, prompt before removal. For a dependency
+ * relation, modify the source to reflect the change.
+ * 
+ * @author Davin McCall.
+ * @version $Id: RemoveAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class RemoveAction extends PkgMgrAction
+{
+    public RemoveAction()
+    {
+        super("menu.edit.remove");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.doRemove();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RestartVMAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RestartVMAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..8fca81e49f5775562760879aba14a1934da464ab
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RestartVMAction.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Restart VM. Restarts the VM in which objects on the object bench live
+ * (and in which programs running under BlueJ execute). This also removes
+ * objects from the bench.
+ * 
+ * @author Davin McCall
+ * @version $Id: RestartVMAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class RestartVMAction extends PkgMgrAction
+{    
+    static private RestartVMAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public RestartVMAction getInstance()
+    {
+        if(instance == null)
+            instance = new RestartVMAction();
+        return instance;
+    }
+    
+    private RestartVMAction()
+    {
+        super("workIndicator.resetMachine");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.restartDebugger();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RunTestsAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RunTestsAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf28c7abce1db34907b6f91d5b7536dcf43ef8b7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/RunTestsAction.java
@@ -0,0 +1,46 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "Run all tests" action (test panel). Runs all the unit tests which have
+ * been created in this project. Displays the results.
+ * 
+ * @author Davin McCall
+ * @version $Id: RunTestsAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class RunTestsAction extends PkgMgrAction
+{
+    public RunTestsAction()
+    {
+        super("menu.tools.run");
+        putValue(SHORT_DESCRIPTION, Config.getString("tooltip.test"));
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.doTest();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/SaveProjectAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/SaveProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..957e1860141305483fdbbc8261e33eca9ea22da7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/SaveProjectAction.java
@@ -0,0 +1,44 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * User chooses "save project". Save all files in the project.
+ * 
+ * @author Davin McCall
+ * @version $Id: SaveProjectAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class SaveProjectAction extends PkgMgrAction
+{
+    public SaveProjectAction()
+    {
+        super("menu.package.save");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.getProject().saveAll();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/SaveProjectAsAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/SaveProjectAsAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..4bb352d54aaa487cfc53205791473f2ce5b25dc3
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/SaveProjectAsAction.java
@@ -0,0 +1,95 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import java.io.File;
+
+import bluej.Config;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+
+/**
+ * User chooses "save project as". This allows saving the project under a
+ * different name, to make a backup etc.
+ * 
+ * @author Davin McCall
+ */
+final public class SaveProjectAsAction extends PkgMgrAction
+{
+    public SaveProjectAsAction()
+    {
+        super("menu.package.saveAs");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        saveAs(pmf, pmf.getProject());
+    }
+    
+    public void saveAs(PkgMgrFrame frame, Project project)
+    {
+        // get a file name to save under
+        File newName = FileUtility.getDirName(frame,
+                Config.getString("pkgmgr.saveAs.title"),
+                Config.getString("pkgmgr.saveAs.buttonLabel"), false, true);
+
+        if (newName != null) {
+            project.saveAll();
+
+            int result = FileUtility.copyDirectory(project.getProjectDir(),
+                    newName);
+
+            switch (result) {
+            case FileUtility.NO_ERROR:
+                break;
+
+            case FileUtility.DEST_EXISTS:
+                DialogManager.showError(frame, "directory-exists");
+                return;
+
+            case FileUtility.SRC_NOT_DIRECTORY:
+            case FileUtility.COPY_ERROR:
+                DialogManager.showError(frame, "cannot-save-project");
+                return;
+            }
+
+            PkgMgrFrame.closeProject(project);
+
+            // open new project
+            Project openProj = Project.openProject(newName.getAbsolutePath(), null);
+
+            if (openProj != null) {
+                Package pkg = openProj.getPackage("");
+                PkgMgrFrame pmf = PkgMgrFrame.createFrame(pkg);
+                pmf.setVisible(true);
+            } else {
+                Debug.message("Save as: could not open package under new name");
+            }
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowCopyrightAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowCopyrightAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..97e291c51f5e9a05c3892a3f93c35f29df5f3913
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowCopyrightAction.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Show copyright info in a dialog box.
+ * 
+ * @author Davin McCall
+ * @version $Id: ShowCopyrightAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class ShowCopyrightAction extends PkgMgrAction {
+    
+    static private ShowCopyrightAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public ShowCopyrightAction getInstance()
+    {
+        if(instance == null)
+            instance = new ShowCopyrightAction();
+        return instance;
+    }
+    
+    private ShowCopyrightAction()
+    {
+        super("menu.help.copyright");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.showCopyright();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowDebuggerAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowDebuggerAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6a85483caf791c7a7567bc67accdfa4f2ad9117
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowDebuggerAction.java
@@ -0,0 +1,46 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import javax.swing.ButtonModel;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Action to toggle display of debugger. This action provides a ButtonModel
+ * so that it can be tied to a check-box.
+ * 
+ * @author Davin McCall
+ * @version $Id: ShowDebuggerAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class ShowDebuggerAction extends PkgMgrAction
+{
+    public ShowDebuggerAction()
+    {
+        super("menu.view.showExecControls");
+    }
+            
+    public ButtonModel getToggleModel(PkgMgrFrame pmf)
+    {
+        return new bluej.debugmgr.ExecControlButtonModel(pmf);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowInheritsAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowInheritsAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..906f0051a87776802d7cbb5959825a1429b7f40b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowInheritsAction.java
@@ -0,0 +1,44 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Action to toggle display of "extends" relationships in the graph window.
+ * 
+ * @author Davin McCall
+ * @version $Id: ShowInheritsAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class ShowInheritsAction extends PkgMgrAction
+{
+    public ShowInheritsAction()
+    {
+        super("menu.view.showInherits");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.updateShowExtendsInPackage();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowTerminalAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowTerminalAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a87d4747c811f75e2159bba0e9b17cc17e89797
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowTerminalAction.java
@@ -0,0 +1,47 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import javax.swing.ButtonModel;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Action to toggle display of terminal. This action provides a ButtonModel
+ * which can be tied to a check-box.
+ * 
+ * @author Davin McCall
+ * @version $Id: ShowTerminalAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+final public class ShowTerminalAction extends PkgMgrAction
+{
+    public ShowTerminalAction()
+    {
+        super("menu.view.showTerminal");
+    }
+    
+    public ButtonModel getToggleModel(PkgMgrFrame pmf)
+    {
+        return new bluej.terminal.TerminalButtonModel(pmf);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowTestResultsAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowTestResultsAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..180b51879e26c44fc604425879d6ba3b8f457ee7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowTestResultsAction.java
@@ -0,0 +1,61 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import javax.swing.ButtonModel;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Action to toggle display of test results. This action provides a ButtonModel
+ * which can be tied to a check-box.
+ * 
+ * @author Davin McCall
+ * @version $Id: ShowTestResultsAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class ShowTestResultsAction extends PkgMgrAction
+{
+    
+    static private ShowTestResultsAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public ShowTestResultsAction getInstance()
+    {
+        if(instance == null)
+            instance = new ShowTestResultsAction();
+        return instance;
+    }
+    
+    private ShowTestResultsAction()
+    {
+        super("menu.view.showTestDisplay");
+    }
+    
+    public ButtonModel getToggleModel(PkgMgrFrame pmf)
+    {
+        return new bluej.testmgr.TestDisplayButtonModel();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowTextEvalAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowTextEvalAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..f69d89dfec23c3c82fb33b5c720abeba9c73793e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowTextEvalAction.java
@@ -0,0 +1,43 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import javax.swing.ButtonModel;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * User wants to see the text evaluation component. Show it.
+ */
+
+final public class ShowTextEvalAction extends PkgMgrAction
+{
+    public ShowTextEvalAction()
+    {
+        super("menu.view.showTextEval");
+    }
+    
+    public ButtonModel getToggleModel(PkgMgrFrame pmf)
+    {
+        return new bluej.debugmgr.texteval.TextEvalButtonModel(pmf);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowUsesAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowUsesAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..3f9698f785a7e8b91dfe2c2dc3de243f5b066ad8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/ShowUsesAction.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Action to toggle display of "uses" relationships in the graph window.
+ * 
+ * @author Davin McCall
+ * @version $Id: ShowUsesAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+
+final public class ShowUsesAction extends PkgMgrAction
+{
+    public ShowUsesAction()
+    {
+        super("menu.view.showUses");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.updateShowUsesInPackage();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/StandardAPIHelpAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/StandardAPIHelpAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..b104e8d995c7618b89ceb083253d779262a66169
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/StandardAPIHelpAction.java
@@ -0,0 +1,60 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Standard API help. Attempt to show the API help in a web browser. The
+ * URL is taken from bluej.defs configuration file.
+ * 
+ * @author Davin McCall
+ * @version $Id: StandardAPIHelpAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class StandardAPIHelpAction extends PkgMgrAction {
+    
+    static private StandardAPIHelpAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public StandardAPIHelpAction getInstance()
+    {
+        if(instance == null)
+            instance = new StandardAPIHelpAction();
+        return instance;
+    }
+    
+    private StandardAPIHelpAction()
+    {
+        super("menu.help.standardApi");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.showWebPage(Config.getPropString("bluej.url.javaStdLib"));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/TutorialAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/TutorialAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ef45c712f559b8bd99c7ce22952c3f50948166c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/TutorialAction.java
@@ -0,0 +1,60 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * BlueJ tutorial website - attempt to show it in a web browser. The URL
+ * is taken from bluej.defs configuration file.
+ * 
+ * @author Davin McCall
+ * @version $Id: TutorialAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+final public class TutorialAction extends PkgMgrAction {
+    
+    static private TutorialAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public TutorialAction getInstance()
+    {
+        if(instance == null)
+            instance = new TutorialAction();
+        return instance;
+    }
+    
+    private TutorialAction()
+    {
+        super("menu.help.tutorial");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.showWebPage(Config.getPropString("bluej.url.tutorial"));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/UseLibraryAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/UseLibraryAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b8122806511508f6b150bd04767d44c4c1e2ebd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/UseLibraryAction.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * "Use library class" command. Allow the user to instantiate an object
+ * from the standard library onto the object bench.
+ * 
+ * @author Davin McCall
+ * @version $Id: UseLibraryAction.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class UseLibraryAction extends PkgMgrAction
+{
+    public UseLibraryAction()
+    {
+        super("menu.tools.callLibrary");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.callLibraryClass();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/WebsiteAction.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/WebsiteAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..23e3e81d903577353d7480be4cb1e91f5ac3bec9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/actions/WebsiteAction.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.actions;
+
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Attempt to open the BlueJ website in a browser. The url is taken from the
+ * bluej.defs configuration file.
+ */
+
+final public class WebsiteAction extends PkgMgrAction {
+    
+    static private WebsiteAction instance = null;
+    
+    /**
+     * Factory method. This is the way to retrieve an instance of the class,
+     * as the constructor is private.
+     * @return an instance of the class.
+     */
+    static public WebsiteAction getInstance()
+    {
+        if(instance == null)
+            instance = new WebsiteAction();
+        return instance;
+    }
+    
+    private WebsiteAction()
+    {
+        super("menu.help.website");
+    }
+    
+    public void actionPerformed(PkgMgrFrame pmf)
+    {
+        pmf.menuCall();
+        pmf.showWebPage(Config.getPropString("bluej.url.bluej"));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/Dependency.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/Dependency.java
new file mode 100644
index 0000000000000000000000000000000000000000..30cec8e07901078aa5fe909632bcaa9044e24806
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/Dependency.java
@@ -0,0 +1,281 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.dependency;
+
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.util.Properties;
+
+import javax.swing.*;
+import javax.swing.AbstractAction;
+
+import bluej.Config;
+import bluej.extensions.BDependency;
+import bluej.extensions.BDependency.Type;
+import bluej.extensions.ExtensionBridge;
+import bluej.extensions.event.DependencyEvent;
+import bluej.extmgr.ExtensionsManager;
+import bluej.graph.*;
+import bluej.graph.Edge;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.target.*;
+import bluej.utility.Debug;
+
+/**
+ * A dependency between two targets in a package.
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ */
+public abstract class Dependency extends Edge
+{
+    Package pkg;
+    private static final String removeStr = Config.getString("pkgmgr.classmenu.remove");
+    protected boolean selected = false;
+    //    protected static final float strokeWithDefault = 1.0f;
+    //    protected static final float strokeWithSelected = 2.0f;
+    private BDependency singleBDependency; // every Dependency has none or one BDependency
+
+    static final int SELECT_DIST = 4;
+
+    public Dependency(Package pkg, DependentTarget from, DependentTarget to)
+    {
+        super(from, to);
+        this.pkg = pkg;
+    }
+
+    public Dependency(Package pkg)
+    {
+        this(pkg, null, null);
+    }
+
+    @Override
+    public boolean equals(Object other)
+    {
+        if (!(other instanceof Dependency))
+            return false;
+        Dependency d = (Dependency) other;
+        return (d != null) && (d.from == from) && (d.to == to);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return to.hashCode() - from.hashCode();
+    }
+
+    public void repaint()
+    {
+        pkg.repaint();
+    }
+
+    public DependentTarget getFrom()
+    {
+        return (DependentTarget) from;
+    }
+
+    public DependentTarget getTo()
+    {
+        return (DependentTarget) to;
+    }
+
+    public BDependency getBDependency()
+    {
+        if (singleBDependency == null) {
+            singleBDependency = ExtensionBridge.newBDependency(this, getType());
+        }
+
+        return singleBDependency;
+    }
+
+    /**
+     * Returns the type of this dependency. This information is used by
+     * extensions to distinguish between the different types of dependencies.
+     * Subclasses must implement this method and return an appropriate constant
+     * of {@link bluej.extensions.BDependency.Type}.
+     * 
+     * @return The type of this dependency;
+     */
+    public abstract Type getType();
+
+    public void load(Properties props, String prefix)
+    {
+        String fromName = props.getProperty(prefix + ".from");
+        this.from = pkg.getTarget(fromName);
+        if (this.from == null)
+            Debug.reportError("Failed to find 'from' target " + fromName);
+        String toName = props.getProperty(prefix + ".to");
+        this.to = pkg.getTarget(toName);
+        if (this.to == null)
+            Debug.reportError("Failed to find 'to' target " + toName);
+    }
+
+    public void save(Properties props, String prefix)
+    {
+        props.put(prefix + ".from", ((DependentTarget) from).getIdentifierName());
+        props.put(prefix + ".to", ((DependentTarget) to).getIdentifierName());
+    }
+
+    /**
+     * Disply the context menu.
+     */
+    public void popupMenu(int x, int y, GraphEditor graphEditor)
+    {
+        JPopupMenu menu = new JPopupMenu();
+        menu.add(new RemoveAction());
+        menu.show(graphEditor, x, y);
+    }
+
+    private class RemoveAction extends AbstractAction
+    {
+        public RemoveAction()
+        {
+            putValue(NAME, removeStr);
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            remove();
+
+        }
+    }
+
+    public String toString()
+    {
+        return getFrom().getIdentifierName() + " --> " + getTo().getIdentifierName();
+    }
+
+    @Override
+    public void setVisible(boolean visible)
+    {
+        if (visible != isVisible()) {
+            super.setVisible(visible);
+            
+            // Inform all listeners about the visibility change
+            DependencyEvent event = new DependencyEvent(this, getFrom().getPackage(), visible);
+            ExtensionsManager.getInstance().delegateEvent(event);
+        }
+    }
+
+    @Override
+    public void setSelected(boolean selected)
+    {
+        this.selected = selected;
+        repaint();
+    }
+
+    @Override
+    public boolean isSelected()
+    {
+        return selected;
+    }
+
+    @Override
+    public boolean isHandle(int x, int y)
+    {
+        return false;
+    }
+
+    /**
+     * Contains method for dependencies that are drawn as more or less straight
+     * lines (e.g. extends). Should be overwritten for dependencies with
+     * different shape.
+     */
+    @Override
+    public boolean contains(int x, int y)
+    {
+        Line line = computeLine();
+        Rectangle bounds = getBoxFromLine(line);
+
+        // Now check if <p> is in the rectangle
+        if (!bounds.contains(x, y)) {
+            return false;
+        }
+
+        // Get the angle of the line from pFrom to p
+        double theta = Math.atan2(-(line.from.y - y), line.from.x - x);
+
+        double norm = normDist(line.from.x, line.from.y, x, y, Math.sin(line.angle - theta));
+        return (norm < SELECT_DIST * SELECT_DIST);
+    }
+
+    static final double normDist(int ax, int ay, int bx, int by, double scale)
+    {
+        return ((ax - bx) * (ax - bx) + (ay - by) * (ay - by)) * scale * scale;
+    }
+
+    /**
+     * Given the line describing start and end points of this dependency, return
+     * its bounding box.
+     */
+    protected Rectangle getBoxFromLine(Line line)
+    {
+        int x = Math.min(line.from.x, line.to.x) - SELECT_DIST;
+        int y = Math.min(line.from.y, line.to.y) - SELECT_DIST;
+        int width = Math.max(line.from.x, line.to.x) - x + (2*SELECT_DIST);
+        int height = Math.max(line.from.y, line.to.y) - y + (2*SELECT_DIST);
+
+        return new Rectangle(x, y, width, height);
+    }
+
+    /**
+     * Compute line information (start point, end point, angle) for the current
+     * state of this dependency. This is accurate for dependencis that are drawn
+     * as straight lines from and to the target border (such as extends
+     * dependencies) and should be redefined for different shaped dependencies.
+     */
+    public Line computeLine()
+    {
+        // Compute centre points of source and dest target
+        Point pFrom = new Point(from.getX() + from.getWidth() / 2, from.getY() + from.getHeight() / 2);
+        Point pTo = new Point(to.getX() + to.getWidth() / 2, to.getY() + to.getHeight() / 2);
+
+        // Get the angle of the line from pFrom to pTo.
+        double angle = Math.atan2(-(pFrom.y - pTo.y), pFrom.x - pTo.x);
+
+        // Compute intersection points with target border
+        pFrom = ((DependentTarget) from).getAttachment(angle + Math.PI);
+        pTo = ((DependentTarget) to).getAttachment(angle);
+
+        return new Line(pFrom, pTo, angle);
+    }
+
+    /**
+     * Inner class to describe the most important state of this dependency
+     * (start point, end point, angle) concisely.
+     */
+    public class Line
+    {
+        public Point from;
+        public Point to;
+        double angle;
+
+        Line(Point from, Point to, double angle)
+        {
+            this.from = from;
+            this.to = to;
+            this.angle = angle;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/ExtendsDependency.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/ExtendsDependency.java
new file mode 100644
index 0000000000000000000000000000000000000000..f05f07c15eae53a3b53c6e67750d075b6f8b5c01
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/ExtendsDependency.java
@@ -0,0 +1,73 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.dependency;
+
+import bluej.extensions.BDependency.Type;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.target.*;
+
+import java.util.Properties;
+
+/**
+ * An "extends" dependency between two (class) targets in a package
+ *
+ * @author Michael Kolling
+ */
+public class ExtendsDependency extends Dependency
+{
+    public ExtendsDependency(Package pkg, DependentTarget from, DependentTarget to)
+    {
+        super(pkg, from, to);
+    }
+
+    public ExtendsDependency(Package pkg)
+    {
+        this(pkg, null, null);
+    }
+
+    public void load(Properties props, String prefix)
+    {
+        super.load(props, prefix);
+    }
+
+    public void save(Properties props, String prefix)
+    {
+        super.save(props, prefix);
+        props.put(prefix + ".type", "ExtendsDependency");
+    }
+    
+    public void remove()
+    {
+        pkg.removeArrow(this);
+    }
+    
+    public boolean isResizable()
+    {
+        return false;
+    }
+    
+    @Override
+    public Type getType()
+    {
+        return Type.EXTENDS;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/ImplementsDependency.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/ImplementsDependency.java
new file mode 100644
index 0000000000000000000000000000000000000000..ffb6bd58072d698745cdae59c6cd4a2d56221b0d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/ImplementsDependency.java
@@ -0,0 +1,73 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.dependency;
+
+import java.util.Properties;
+
+import bluej.extensions.BDependency.Type;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.target.*;
+
+/**
+ * An "implements" dependency between two (class) targets in a package
+ *
+ * @author  Michael Kolling
+ */
+public class ImplementsDependency extends Dependency
+{
+    public ImplementsDependency(Package pkg, DependentTarget from, DependentTarget to)
+    {
+        super(pkg, from, to);
+    }
+
+    public ImplementsDependency(Package pkg)
+    {
+        this(pkg, null, null);
+    }
+
+    public void load(Properties props, String prefix)
+    {
+        super.load(props, prefix);
+    }
+
+    public void save(Properties props, String prefix)
+    {
+        super.save(props, prefix);
+        props.put(prefix + ".type", "ImplementsDependency");
+    }
+    
+    public void remove()
+    {
+        pkg.removeArrow(this);
+    }
+    
+    public boolean isResizable()
+    {
+        return false;
+    }
+    
+    @Override
+    public Type getType()
+    {
+        return Type.IMPLEMENTS;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/UsesDependency.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/UsesDependency.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf75c4b81e11a32b938403a2ebf3fd40f8854c5b
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/dependency/UsesDependency.java
@@ -0,0 +1,224 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.dependency;
+
+import bluej.extensions.BDependency.Type;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.target.*;
+
+import java.util.Properties;
+import java.awt.*;
+
+/**
+ * A dependency between two targets in a package
+ *
+ * @author  Michael Kolling
+ * @version $Id: UsesDependency.java 9624 2012-03-29 17:04:54Z davmac $
+ */
+public class UsesDependency extends Dependency
+{
+    private int sourceX, sourceY, destX, destY;
+    private boolean startTop, endLeft;
+    private boolean flag;    // flag to mark some dependencies
+
+    public UsesDependency(Package pkg, DependentTarget from, DependentTarget to)
+    {
+        super(pkg, from, to);
+        flag = false;
+    }
+
+    public UsesDependency(Package pkg)
+    {
+        this(pkg, null, null);
+    }
+
+    public void setSourceCoords(int src_x, int src_y, boolean start_top)
+    {
+        this.sourceX = src_x;
+        this.sourceY = src_y;
+        this.setStartTop(start_top);
+    }
+
+    public void setDestCoords(int dst_x, int dst_y, boolean end_left)
+    {
+        this.destX = dst_x;
+        this.destY = dst_y;
+        this.setEndLeft(end_left);
+    }
+
+    /**
+     * Test whether (x,y) is in rectangle (x0,x1,y0,y1),
+     */
+    static final boolean inRect(int x, int y, int x0, int y0, int x1, int y1)
+    {
+        int xmin = Math.min(x0, x1);
+        int xmax = Math.max(x0, x1);
+        int ymin = Math.min(y0, y1);
+        int ymax = Math.max(y0, y1);
+        return (xmin <= x) && (ymin <= y) && (x < xmax) && (y < ymax);
+    }
+
+    public boolean contains(int x, int y)
+    {
+        int src_x = this.sourceX;
+        int src_y = this.sourceY;
+        int dst_x = this.destX;
+        int dst_y = this.destY;
+
+        // Check the first segment
+        int corner_y = src_y + (isStartTop() ? -15 : 15);
+        if(inRect(x, y, src_x - SELECT_DIST, corner_y, src_x + SELECT_DIST, src_y))
+            return true;
+
+        src_y = corner_y;
+
+        // Check the last line segment
+        int corner_x = dst_x + (isEndLeft() ? -15 : 15);
+        if(inRect(x, y, corner_x, dst_y - SELECT_DIST, dst_x, dst_y + SELECT_DIST))
+            return true;
+
+        dst_x = corner_x;
+
+        // if arrow vertical corner, check first segment up to corner
+        if((src_y != dst_y) && (isStartTop() == (src_y < dst_y))) {
+            corner_x = ((src_x + dst_x) / 2) + (isEndLeft() ? 15 : -15);
+            corner_x = (isEndLeft() ? Math.min(dst_x, corner_x) :
+                        Math.max(dst_x, corner_x));
+            if(inRect(x, y, src_x, src_y - SELECT_DIST, corner_x, src_y + SELECT_DIST))
+                return true;
+            src_x = corner_x;
+        }
+
+        // if arrow horiz. corner, check first segment up to corner
+        if((src_x != dst_x) && (isEndLeft() == (src_x > dst_x))) {
+            corner_y = ((src_y + dst_y) / 2) + (isStartTop() ? 15 : -15);
+            corner_y = (isStartTop() ? Math.min(src_y, corner_y) :
+                        Math.max(src_y, corner_y));
+            if(inRect(x, y, dst_x - SELECT_DIST, corner_y, dst_x + SELECT_DIST, dst_y))
+                return true;
+            dst_y = corner_y;
+        }
+
+        // Check the middle bit
+        return inRect(x, y, src_x - SELECT_DIST, src_y, src_x + SELECT_DIST, dst_y)
+            || inRect(x, y, src_x, dst_y - SELECT_DIST, dst_x, dst_y + SELECT_DIST);
+    }
+
+    
+    /**
+     * Compute line information (start point, end point, angle)
+     * for the current state of this dependency.
+     */
+    public Line computeLine()
+    {
+        return new Line(new Point(sourceX, sourceY), new Point(destX, destY), 0.0);
+    }
+    
+
+    public void load(Properties props, String prefix)
+    {
+        super.load(props, prefix);
+
+        // Nothing extra to do.
+    }
+
+    public void save(Properties props, String prefix)
+    {
+        super.save(props, prefix);
+
+        // This may be overridden by decendents
+        props.put(prefix + ".type", "UsesDependency");
+    }
+
+    public void setFlag(boolean value)
+    {
+        flag = value;
+    }
+
+    public boolean isFlagged()
+    {
+        return flag;
+    }
+    
+    public void remove()
+    {
+        pkg.removeArrow(this);
+    }
+    
+    /**
+     * @return Returns the sourceX.
+     */
+    public int getSourceX() {
+        return sourceX;
+    }
+    /**
+     * @return Returns the sourceY.
+     */
+    public int getSourceY() {
+        return sourceY;
+    }
+    /**
+     * @param sourceY The sourceY to set.
+     */
+    public void setSourceY(int sourceY) {
+        this.sourceY = sourceY;
+    }
+    /**
+     * @return Returns the destX.
+     */
+    public int getDestX() {
+        return destX;
+    }
+    /**
+     * @return Returns the destY.
+     */
+    public int getDestY() {
+        return destY;
+    }
+
+    public void setStartTop(boolean startTop) {
+        this.startTop = startTop;
+    }
+
+    public boolean isStartTop() {
+        return startTop;
+    }
+
+    public void setEndLeft(boolean endLeft) {
+        this.endLeft = endLeft;
+    }
+
+    public boolean isEndLeft() {
+        return endLeft;
+    }
+    
+    public boolean isResizable()
+    {
+        return false;
+    }
+
+    @Override
+    public Type getType()
+    {
+        return Type.USES;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ClassTargetPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ClassTargetPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..07c0acaf3e16f319dc4bed8fc4292d3526ff36a1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ClassTargetPainter.java
@@ -0,0 +1,236 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.graphPainter;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Image;
+
+import bluej.Config;
+import bluej.extensions.painter.ExtensionClassTargetPainter;
+import bluej.extmgr.ExtensionsManager;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.Target;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.Utility;
+
+/**
+ * Paints a ClassTarget
+ * 
+ * @author fisker
+ */
+public class ClassTargetPainter
+{
+    /**
+     * The constants in this enumeration are used to define which method of the
+     * {@link ExtensionClassTargetPainter} shall be called.
+     * 
+     * @author Simon Gerlach
+     */
+    public enum Layer {
+        BACKGROUND, FOREGROUND;
+    }
+
+    private static final int HANDLE_SIZE = 20;
+    private static final String STEREOTYPE_OPEN = "<<";
+    private static final String STEREOTYPE_CLOSE = ">>";
+    private static final Color textcolor = Color.BLACK;
+    private static final Color borderColor = Color.BLACK;
+    private static final Color stripeColor = new Color(158,139,116);
+    private static final Image brokenImage = Config.getFixedImageAsIcon("broken-symbol.png").getImage();
+    private static final Font targetFont = PrefMgr.getTargetFont();
+
+    private static final int TEXT_HEIGHT = GraphPainterStdImpl.TEXT_HEIGHT;
+    private static final int TEXT_BORDER = GraphPainterStdImpl.TEXT_BORDER;
+    private static final AlphaComposite alphaComposite = GraphPainterStdImpl.alphaComposite;
+    private static Composite oldComposite;
+
+    /**
+     * Construct the ClassTargetPainter
+     *  
+     */
+    public ClassTargetPainter()
+    { }
+
+    public void paint(Graphics2D g, ClassTarget classTarget, boolean hasFocus)
+    {
+        g.translate(classTarget.getX(), classTarget.getY());
+        
+        int width = classTarget.getWidth();
+        int height = classTarget.getHeight();
+        
+        // draw the stationary class
+        drawShadow(g, width, height);
+        drawSkeleton(g, classTarget, width, height);
+        drawUMLStyle(g, classTarget, hasFocus, width, height);
+        // drawRole(g);  // currently, roles don't draw
+        g.translate(-classTarget.getX(), -classTarget.getY());
+    }
+
+    public void paintGhost(Graphics2D g, Target target, boolean hasFocus)
+    {
+        ClassTarget classTarget = (ClassTarget) target;
+        oldComposite = g.getComposite();
+        g.translate(classTarget.getGhostX(), classTarget.getGhostY());
+        int width = classTarget.getGhostWidth();
+        int height = classTarget.getGhostHeight();
+        
+        g.setComposite(alphaComposite);
+        drawSkeleton(g, classTarget, width, height);
+        drawUMLStyle(g, classTarget, hasFocus, width, height);
+        // drawRole(g);  // currently, roles don't draw
+        g.setComposite(oldComposite);
+        g.translate(-classTarget.getGhostX(), -classTarget.getGhostY());
+    }
+
+    /**
+     * Draw the Coloured rectangle and the borders.
+     *  
+     */
+    private void drawSkeleton(Graphics2D g, ClassTarget classTarget, int width, int height)
+    {
+        g.setPaint(classTarget.getBackgroundPaint(width, height));
+        g.fillRect(0, 0, width, height);
+    }
+
+    /**
+     * Draw the stereotype, identifier name and the line beneath the identifier
+     * name.
+     */
+    private void drawUMLStyle(Graphics2D g, ClassTarget classTarget, boolean hasFocus, int width, int height)
+    {
+        ExtensionsManager extensionsManager = ExtensionsManager.getInstance();
+
+        // get the Stereotype
+        String stereotype = classTarget.getRole().getStereotypeLabel();
+
+        g.setColor(textcolor);
+        int currentTextPosY = 2;
+
+        // draw stereotype if applicable
+        if (stereotype != null) {
+            String stereotypeLabel = STEREOTYPE_OPEN + stereotype + STEREOTYPE_CLOSE;
+            Font stereotypeFont = targetFont.deriveFont((float) (targetFont.getSize() - 2));
+            g.setFont(stereotypeFont);
+            Utility.drawCentredText(g, stereotypeLabel, TEXT_BORDER, currentTextPosY, width - 2
+                    * TEXT_BORDER, TEXT_HEIGHT);
+            currentTextPosY += TEXT_HEIGHT - 2;
+        }
+
+        g.setFont(targetFont);
+
+        // draw the identifiername of the class
+        Utility.drawCentredText(g, classTarget.getDisplayName(), TEXT_BORDER, currentTextPosY, width
+                - 2 * TEXT_BORDER, TEXT_HEIGHT);
+        currentTextPosY += TEXT_HEIGHT;
+
+        // draw line beneath the stereotype and indentifiername. The UML-style
+        g.setColor(borderColor);
+        g.drawLine(0, currentTextPosY, width, currentTextPosY);
+        
+        // Ask extensions to draw their background of the class target
+        int extensionGraphicsX = 1;
+        int extensionGraphicsY = currentTextPosY + 1;
+        int extensionGraphicsWidth = width - 1;
+        int extensionGraphicsHeight = height - currentTextPosY - 1;
+
+        Graphics2D backgroundGraphics = (Graphics2D) g.create(extensionGraphicsX,
+            extensionGraphicsY, extensionGraphicsWidth, extensionGraphicsHeight);
+        extensionsManager.drawExtensionClassTarget(Layer.BACKGROUND, classTarget.getBClassTarget(),
+            backgroundGraphics, extensionGraphicsWidth, extensionGraphicsHeight);
+
+        // Ask extensions to draw their foreground of the class target
+        Graphics2D foregroundGraphics = (Graphics2D) g.create(extensionGraphicsX,
+            extensionGraphicsY, extensionGraphicsWidth, extensionGraphicsHeight);
+        extensionsManager.drawExtensionClassTarget(Layer.FOREGROUND, classTarget.getBClassTarget(),
+            foregroundGraphics, extensionGraphicsWidth, extensionGraphicsHeight);
+
+        // Last, draw the warnings if something is wrong with the class
+        drawWarnings(g, classTarget, width, height);
+
+        g.setColor(borderColor);
+        boolean drawSelected = classTarget.isSelected() && hasFocus;
+        drawBorder(g, drawSelected, width, height);
+    }
+
+    /**
+     * If the state of the class insn't normal, make it stripped. Write warning
+     * if the sourcecode is missing. Display the "broken" image if the
+     * sourcecode couldn't be parsed.
+     */
+    private void drawWarnings(Graphics2D g, ClassTarget classTarget, int width, int height)
+    {
+
+        // If the state isn't normal, draw stripes in the rectangle
+        String stereotype = classTarget.getRole().getStereotypeLabel();
+        if (classTarget.getState() != ClassTarget.S_NORMAL) {
+            g.setColor(stripeColor);
+            int divider = (stereotype == null) ? 19 : 33;
+            Utility.stripeRect(g, 0, divider, width, height - divider, 8, 3);
+        }
+
+        // if sourcecode is missing. Write "(no source)" in the diagram
+        if (!classTarget.hasSourceCode()) {
+            g.setColor(textcolor);
+            g.setFont(targetFont.deriveFont((float) (targetFont.getSize() - 2)));
+            Utility.drawCentredText(g, "(no source)", TEXT_BORDER, height - 18, width
+                    - 2 * TEXT_BORDER, TEXT_HEIGHT);
+        }
+        // if the sourcecode is invalid, display the "broken" image in diagram
+        else if (!classTarget.getSourceInfo().isValid()) {
+            g.drawImage(brokenImage, TEXT_BORDER, height - 22, null);
+        }
+    }
+
+    /**
+     * Draw the borders of this target.
+     */
+    private void drawBorder(Graphics2D g, boolean selected, int width, int height)
+    {
+        int thickness = 1; // default thickness
+
+        if (selected) {
+            thickness = 2; // thickness of borders when class is selected
+            // Draw lines showing resize tag
+            g.drawLine(width - HANDLE_SIZE - 2, height, width, height - HANDLE_SIZE - 2);
+            g.drawLine(width - HANDLE_SIZE + 2, height, width, height - HANDLE_SIZE + 2);
+        }
+        Utility.drawThickRect(g, 0, 0, width, height, thickness);
+    }
+
+    /**
+     * Draw a 'shadow' appearance under and to the right of the target.
+     */
+    private void drawShadow(Graphics2D g, int width, int height)
+    {
+        // A uniform tail-off would have equal values for each,
+        // as they all get drawn on top of each other:
+        final int shadowAlphas[] = {20, 15, 10, 5, 5};
+        for (int i = 0;i < 5;i++) {
+            g.setColor(new Color(0, 0, 0, shadowAlphas[i]));
+            g.fillRoundRect(2 - i, 4 - i, width + (2*i) - 1, height + (2*i) - 1, 8, 8);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/DependencyPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/DependencyPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..9923592e7883496c6bd15d9c719ec4d67f50fa67
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/DependencyPainter.java
@@ -0,0 +1,37 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.graphPainter;
+
+import java.awt.Graphics2D;
+import java.awt.Point;
+
+import bluej.pkgmgr.dependency.Dependency;
+
+/**
+ * @author fisker
+ *
+ */
+public interface DependencyPainter
+{
+    public Point getPopupMenuPosition(Dependency dependency);
+    public void paint(Graphics2D g, Dependency d, boolean hasFocus);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ExtendsDependencyPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ExtendsDependencyPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..b2ce1779f1faebecc11db2ce7bdc67c5f6a2e3f4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ExtendsDependencyPainter.java
@@ -0,0 +1,126 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.graphPainter;
+
+import java.awt.*;
+
+import bluej.graph.RubberBand;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.dependency.ExtendsDependency;
+import bluej.pkgmgr.dependency.Dependency.Line;
+
+/**
+ * Paints a ClassTarget
+ * 
+ * @author fisker
+ * @author Michael Kolling
+ * @version $Id: ExtendsDependencyPainter.java 9034 2011-06-24 02:42:21Z davmac $
+ */
+public class ExtendsDependencyPainter
+    implements DependencyPainter
+{
+    protected static final float strokeWidthDefault = 1.0f;
+    protected static final float strokeWidthSelected = 2.0f;
+
+    static final Color normalColour = Color.BLACK;
+    private static final BasicStroke normalSelected = new BasicStroke(strokeWidthSelected);
+    private static final BasicStroke normalUnselected = new BasicStroke(strokeWidthDefault);
+    static final int ARROW_SIZE = 18; // pixels
+    static final double ARROW_ANGLE = Math.PI / 6; // radians
+
+    public ExtendsDependencyPainter()
+    {}
+
+    public void paint(Graphics2D g, Dependency dependency, boolean hasFocus)
+    {
+        if (!(dependency instanceof ExtendsDependency)) {
+            throw new IllegalArgumentException("Not a ExtendsDependency");
+        }
+        Stroke oldStroke = g.getStroke();
+        ExtendsDependency d = (ExtendsDependency) dependency;
+
+        boolean isSelected = d.isSelected() && hasFocus;
+        g.setStroke((isSelected ? normalSelected : normalUnselected));
+
+        Line line = d.computeLine();
+
+        paintArrow(g, line.from, line.to);
+        g.setStroke(oldStroke);
+    }
+
+    /**
+     * Draw an ExtendsDependency from DependTarget d to the mouse position
+     */
+    public void paintIntermediateDependency(Graphics2D g, RubberBand rb)
+    {
+        g.setStroke(normalUnselected);
+        paintArrow(g, rb.startPt, rb.endPt);
+    }
+
+    private void paintArrow(Graphics2D g, Point pFrom, Point pTo)
+    {
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        g.setColor(normalColour);
+        double angle = Math.atan2(-(pFrom.y - pTo.y), pFrom.x - pTo.x);
+
+        Point pArrow = new Point(pTo.x + (int) ((ARROW_SIZE - 2) * Math.cos(angle)), pTo.y
+                - (int) ((ARROW_SIZE - 2) * Math.sin(angle)));
+
+        // draw the arrow head
+        int[] xPoints = {pTo.x, pTo.x + (int) ((ARROW_SIZE) * Math.cos(angle + ARROW_ANGLE)),
+                pTo.x + (int) (ARROW_SIZE * Math.cos(angle - ARROW_ANGLE))};
+        int[] yPoints = {pTo.y, pTo.y - (int) ((ARROW_SIZE) * Math.sin(angle + ARROW_ANGLE)),
+                pTo.y - (int) (ARROW_SIZE * Math.sin(angle - ARROW_ANGLE))};
+
+        g.drawPolygon(xPoints, yPoints, 3);
+        g.drawLine(pFrom.x, pFrom.y, pArrow.x, pArrow.y);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see bluej.pkgmgr.graphPainter.DependencyPainter#getPopupMenuPosition(bluej.pkgmgr.dependency.Dependency)
+     */
+    public Point getPopupMenuPosition(Dependency dependency)
+    {
+
+        if (!(dependency instanceof ExtendsDependency)) {
+            throw new IllegalArgumentException("Not a ExtendsDependency");
+        }
+        Point pFrom = new Point(dependency.getFrom().getX() + dependency.getFrom().getWidth() / 2, dependency.getFrom()
+                .getY()
+                + dependency.getFrom().getHeight() / 2);
+        Point pTo = new Point(dependency.getTo().getX() + dependency.getTo().getWidth() / 2, dependency.getTo().getY()
+                + dependency.getTo().getHeight() / 2);
+        // Get the angle of the line from src to dst.
+        double angle = Math.atan2(-(pFrom.y - pTo.y), pFrom.x - pTo.x);
+        pTo = dependency.getTo().getAttachment(angle);
+        //          draw the arrow head
+        int[] xPoints = {pTo.x, pTo.x + (int) ((ARROW_SIZE) * Math.cos(angle + ARROW_ANGLE)),
+                pTo.x + (int) (ARROW_SIZE * Math.cos(angle - ARROW_ANGLE))};
+        int[] yPoints = {pTo.y, pTo.y - (int) ((ARROW_SIZE) * Math.sin(angle + ARROW_ANGLE)),
+                pTo.y - (int) (ARROW_SIZE * Math.sin(angle - ARROW_ANGLE))};
+        return new Point((xPoints[0] + xPoints[1] + xPoints[2]) / 3, (yPoints[0] + yPoints[1] + yPoints[2]) / 3);
+
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/GraphPainterStdImpl.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/GraphPainterStdImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..c52ad5acd37df38297a688aba538c249f61cec80
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/GraphPainterStdImpl.java
@@ -0,0 +1,257 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.graphPainter;
+
+import java.awt.*;
+import java.util.Iterator;
+import java.util.Map;
+
+import bluej.Config;
+import bluej.graph.*;
+import bluej.pkgmgr.dependency.*;
+import bluej.pkgmgr.target.*;
+import bluej.pkgmgr.Package;
+
+/**
+ * Paints a Graph using TargetPainters
+ * 
+ * @author fisker
+ */
+public class GraphPainterStdImpl
+    implements GraphPainter
+{
+    static final int TEXT_HEIGHT = Integer.parseInt(Config.getPropString("bluej.target.fontsize")) + 4;
+    static final int TEXT_BORDER = 4;
+    static final float alpha = (float) 0.5;
+    static AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
+
+    private final ClassTargetPainter classTargetPainter = new ClassTargetPainter();
+    private final ReadmeTargetPainter readmePainter = new ReadmeTargetPainter();
+    private final PackageTargetPainter packageTargetPainter = new PackageTargetPainter();
+    private final ExtendsDependencyPainter extendsDependencyPainter = new ExtendsDependencyPainter();
+    private final ImplementsDependencyPainter implementsDependencyPainter = new ImplementsDependencyPainter();
+    private final UsesDependencyPainter usesDependencyPainter = new UsesDependencyPainter();
+    private static final GraphPainterStdImpl singleton = new GraphPainterStdImpl();
+
+    private GraphEditor graphEditor;
+
+    private GraphPainterStdImpl()
+    {} // prevent instantiation
+
+    /**
+     * Paint 'graph' on 'g'
+     */
+    public void paint(Graphics2D g, GraphEditor graphEditor)
+    {
+        // Use system settings for text rendering (Java 6 only)
+        Toolkit tk = Toolkit.getDefaultToolkit(); 
+        Map<?,?> desktopHints = (Map<?,?>) (tk.getDesktopProperty("awt.font.desktophints")); 
+        if (desktopHints != null) { 
+            g.addRenderingHints(desktopHints); 
+        } 
+        
+        this.graphEditor = graphEditor;
+        Graph graph = graphEditor.getGraph();
+        paintEdges(g, graph);
+        paintVertices(g, graph);
+        paintGhosts(g, graph);
+        paintIntermediateDependency(g, graph);
+    }
+
+    /**
+     * Paint the edges in 'graph' on 'g'. Edges that are declared as
+     * "not visible" will not be painted.
+     * 
+     * @param g
+     * @param graph
+     */
+    private void paintEdges(Graphics2D g, Graph graph)
+    {
+        Edge edge;
+        //Paint the edges
+        for (Iterator<? extends Edge> it = graph.getEdges(); it.hasNext();) {
+            edge = it.next();
+            if (edge.isVisible()) {
+                paintEdge(g, edge);
+            }
+        }
+    }
+
+    /**
+     * Paint the vertices in 'graph' on 'g'. If one of the targets to be painted
+     * is in the process of drawing a dependency to another class, assign that
+     * class to 'dependency'. Vertices that are declared as "not visible" will
+     * not be painted.
+     * 
+     * @param g
+     * @param graph
+     * @param dependentTarget
+     * @return the class from which a dependency is being drawn. Null if none.
+     */
+    private void paintVertices(Graphics2D g, Graph graph)
+    {
+        for (Iterator<? extends Vertex> it = graph.getVertices(); it.hasNext();) {
+            Vertex vertex = it.next();
+            if (vertex.isVisible()) {
+                paintVertex(g, vertex);
+            }
+        }
+    }
+
+    /**
+     * Paint the ghosts (transparent versions) of the vertices in 'graph' that
+     * are being dragged in the diagram.
+     * 
+     * @param g
+     * @param graph
+     */
+    private void paintGhosts(Graphics2D g, Graph graph)
+    {
+        for (Iterator<? extends Vertex> it = graph.getVertices(); it.hasNext();) {
+            Vertex vertex = it.next();
+            if (vertex instanceof Moveable) {
+                Moveable moveable = (Moveable) vertex;
+                if (moveable.isDragging()) {
+                    paintGhostVertex(g, moveable);
+                }
+            }
+        }
+    }
+
+    /**
+     * Paint 'edge' on 'g'
+     */
+    private void paintEdge(Graphics2D g, Edge edge)
+    {
+        if (!(edge instanceof Dependency)) {
+            throw new IllegalArgumentException("Not a dependency");
+        }
+        Dependency dependency = (Dependency) edge;
+        getDependencyPainter(dependency).paint(g, dependency, isPermanentFocusOwner());
+    }
+
+    /**
+     * Return the appropriate painter for a given dependency.
+     * 
+     * @param edge  The dependency we want to paint
+     * @return  A painter that can paint the given dependency.
+     */
+    public DependencyPainter getDependencyPainter(Edge edge)
+    {
+        if (edge instanceof ImplementsDependency) {
+            return implementsDependencyPainter;
+        }
+        else if (edge instanceof ExtendsDependency) {
+            return extendsDependencyPainter;
+        }
+        else if (edge instanceof UsesDependency) {
+            return usesDependencyPainter;
+        }
+        else {
+            //assert false;
+            return null;
+        }
+    }
+
+    /**
+     * Paint 'vertex' on 'g' using the appropiate painter.
+     * 
+     * @param g
+     * @param vertex
+     */
+    private void paintVertex(Graphics2D g, Vertex vertex)
+    {
+        if (vertex instanceof ClassTarget) {
+            classTargetPainter.paint(g, (ClassTarget) vertex, isPermanentFocusOwner());
+        }
+        else if (vertex instanceof ReadmeTarget) {
+            readmePainter.paint(g, (ReadmeTarget) vertex, isPermanentFocusOwner());
+        }
+        else if (vertex instanceof PackageTarget) {
+            packageTargetPainter.paint(g, (PackageTarget) vertex, isPermanentFocusOwner());
+        }
+        else {
+            //asserts false;
+        }
+    }
+
+    /**
+     * Paint a ghostet (transparent) version of 'vertex' on 'g'
+     * 
+     * @param g
+     * @param vertex
+     */
+    private void paintGhostVertex(Graphics2D g, Moveable vertex)
+    {
+        if (vertex instanceof ClassTarget) {
+            classTargetPainter.paintGhost(g, (ClassTarget) vertex, isPermanentFocusOwner());
+        }
+        else if (vertex instanceof PackageTarget) {
+            packageTargetPainter.paintGhost(g, (PackageTarget) vertex, isPermanentFocusOwner());
+        }
+        else {
+            //asserts false;
+        }
+    }
+
+    /**
+     * Paint an arrow representing the intermediate dependency 'd', using the
+     * appropiate painter, on 'g'
+     * 
+     * @param g
+     * @param d
+     */
+    private void paintIntermediateDependency(Graphics2D g, Graph graph)
+    {
+        RubberBand rb = graphEditor.getRubberBand();
+        if (rb != null) {
+            if (((Package)graph).getState() == Package.S_CHOOSE_EXT_TO) {
+                extendsDependencyPainter.paintIntermediateDependency(g, rb);
+            }
+            else if (((Package)graph).getState() == Package.S_CHOOSE_USES_TO) {
+                usesDependencyPainter.paintIntermedateDependency(g, rb);
+            }
+        }
+    }
+
+    /**
+     * Tell whether the graph editor has the permanent key focus - 
+     * this is NOT the temporary which hasFocus() and isFocusOwner() uses.
+     */
+    private boolean isPermanentFocusOwner()
+    {
+        return graphEditor.hasFocus();// graphEditor.hasFocus is overloaded
+        //Component permanentFocusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
+        //return (permanentFocusOwner == graphEditor);
+    }
+
+    /**
+     * Get reference to the singleton GraphPainterStdImpl
+     * 
+     * @return GraphPainterStdImpl
+     */
+    public static GraphPainter getInstance()
+    {
+        return singleton;
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ImplementsDependencyPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ImplementsDependencyPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9bcd9924856aafb3b4cbda08a1c6aec11348aa0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ImplementsDependencyPainter.java
@@ -0,0 +1,138 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.graphPainter;
+
+import java.awt.*;
+import java.awt.Graphics2D;
+
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.dependency.ImplementsDependency;
+
+/**
+ * Paintes ImplementsDependencies
+ * 
+ * @author fisker
+ * @author Michael Kolling
+ */
+public class ImplementsDependencyPainter
+    implements DependencyPainter
+{
+    protected static final float strokeWidthDefault = 1.0f;
+    protected static final float strokeWidthSelected = 2.0f;
+
+    static final Color normalColour = Color.BLACK;
+    static final int ARROW_SIZE = 18; // pixels
+    static final double ARROW_ANGLE = Math.PI / 6; // radians
+    //static final int SELECT_DIST = 4;
+    private static final float dash1[] = {5.0f, 2.0f};
+    private static final BasicStroke dashedUnselected = new BasicStroke(strokeWidthDefault, BasicStroke.CAP_BUTT,
+            BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
+    private static final BasicStroke dashedSelected = new BasicStroke(strokeWidthSelected, BasicStroke.CAP_BUTT,
+            BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
+    private static final BasicStroke normalSelected = new BasicStroke(strokeWidthSelected);
+    private static final BasicStroke normalUnselected = new BasicStroke(strokeWidthDefault);
+
+    public ImplementsDependencyPainter()
+    {
+    }
+
+    public void paint(Graphics2D g, Dependency dependency, boolean hasFocus)
+    {
+        if (!(dependency instanceof ImplementsDependency)) {
+            throw new IllegalArgumentException();
+        }
+        Stroke oldStroke = g.getStroke();
+
+        ImplementsDependency d = (ImplementsDependency) dependency;
+        Stroke dashedStroke, normalStroke;
+        boolean isSelected = d.isSelected() && hasFocus;
+        if (isSelected) {
+            dashedStroke = dashedSelected;
+            normalStroke = normalSelected;
+        }
+        else {
+            dashedStroke = dashedUnselected;
+            normalStroke = normalUnselected;
+        }
+
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        g.setColor(normalColour);
+
+        // Start from the centre of the src class
+        Point pFrom = new Point(d.getFrom().getX() + d.getFrom().getWidth() / 2, d.getFrom().getY()
+                + d.getFrom().getHeight() / 2);
+        Point pTo = new Point(d.getTo().getX() + d.getTo().getWidth() / 2, d.getTo().getY()
+                + d.getTo().getHeight() / 2);
+
+        // Get the angle of the line from src to dst.
+        double angle = Math.atan2(-(pFrom.getY() - pTo.getY()), pFrom.getX() - pTo.getX());
+
+        // Get the dest point
+        pFrom = d.getFrom().getAttachment(angle + Math.PI);
+        pTo = d.getTo().getAttachment(angle);
+
+        Point pArrow = new Point(pTo.x + (int) ((ARROW_SIZE - 2) * Math.cos(angle)), pTo.y
+                - (int) ((ARROW_SIZE - 2) * Math.sin(angle)));
+
+        // draw the arrow head
+        int[] xPoints = {pTo.x, pTo.x + (int) ((ARROW_SIZE) * Math.cos(angle + ARROW_ANGLE)),
+                pTo.x + (int) (ARROW_SIZE * Math.cos(angle - ARROW_ANGLE))};
+        int[] yPoints = {pTo.y, pTo.y - (int) ((ARROW_SIZE) * Math.sin(angle + ARROW_ANGLE)),
+                pTo.y - (int) (ARROW_SIZE * Math.sin(angle - ARROW_ANGLE))};
+
+        g.setStroke(dashedStroke);
+        g.drawLine(pFrom.x, pFrom.y, pArrow.x, pArrow.y);
+
+        g.setStroke(normalStroke);
+        g.drawPolygon(xPoints, yPoints, 3);
+
+        g.setStroke(oldStroke);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see bluej.pkgmgr.graphPainter.DependencyPainter#getPopupMenuPosition(bluej.pkgmgr.dependency.Dependency)
+     */
+    public Point getPopupMenuPosition(Dependency dependency)
+    {
+        if (!(dependency instanceof ImplementsDependency)) {
+            throw new IllegalArgumentException("Not a ExtendsDependency");
+        }
+        Point pFrom = new Point(dependency.getFrom().getX() + dependency.getFrom().getWidth() / 2, dependency.getFrom()
+                .getY()
+                + dependency.getFrom().getHeight() / 2);
+        Point pTo = new Point(dependency.getTo().getX() + dependency.getTo().getWidth() / 2, dependency.getTo().getY()
+                + dependency.getTo().getHeight() / 2);
+        // Get the angle of the line from src to dst.
+        double angle = Math.atan2(-(pFrom.y - pTo.y), pFrom.x - pTo.x);
+        pTo = dependency.getTo().getAttachment(angle);
+
+        //      draw the arrow head
+        int[] xPoints = {pTo.x, pTo.x + (int) ((ARROW_SIZE) * Math.cos(angle + ARROW_ANGLE)),
+                pTo.x + (int) (ARROW_SIZE * Math.cos(angle - ARROW_ANGLE))};
+        int[] yPoints = {pTo.y, pTo.y - (int) ((ARROW_SIZE) * Math.sin(angle + ARROW_ANGLE)),
+                pTo.y - (int) (ARROW_SIZE * Math.sin(angle - ARROW_ANGLE))};
+
+        return new Point((xPoints[0] + xPoints[1] + xPoints[2]) / 3, (yPoints[0] + yPoints[1] + yPoints[2]) / 3);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/PackageTargetPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/PackageTargetPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..21f0a06db2df3e857d8f8d569f92a1cb94ebe8b7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/PackageTargetPainter.java
@@ -0,0 +1,148 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.graphPainter;
+
+import java.awt.*;
+
+import bluej.pkgmgr.target.*;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.Utility;
+
+/**
+ * Paints a packageTarget
+ * 
+ * @author fisker
+ */
+public class PackageTargetPainter
+{
+    private static final int TAB_HEIGHT = 12;
+    private static final int HANDLE_SIZE = 20;
+
+    private static final Color bordercolour = Color.BLACK;
+
+    private static final int TEXT_HEIGHT = GraphPainterStdImpl.TEXT_HEIGHT;
+    private static final int TEXT_BORDER = GraphPainterStdImpl.TEXT_BORDER;
+    private static final AlphaComposite alphaComposite = GraphPainterStdImpl.alphaComposite;
+    private static Composite oldComposite;
+    private int tabWidth;
+
+    /**
+     * Construct a new PackageTargetPainter.
+     */
+    public PackageTargetPainter()
+    {
+    }
+
+    public void paint(Graphics2D g, Target target, boolean hasFocus)
+    {
+        PackageTarget packageTarget = (PackageTarget) target;
+        g.translate(packageTarget.getX(), packageTarget.getY());
+        int width = packageTarget.getWidth();
+        int height = packageTarget.getHeight();
+        drawUMLStyle(g, packageTarget, hasFocus, width, height);
+        g.translate(-packageTarget.getX(), -packageTarget.getY());
+    }
+
+    public void paintGhost(Graphics2D g, Target target, boolean hasFocus)
+    {
+        PackageTarget packageTarget = (PackageTarget) target;
+        oldComposite = g.getComposite();
+        g.translate(packageTarget.getGhostX(), packageTarget.getGhostY());
+        int width = packageTarget.getGhostWidth();
+        int height = packageTarget.getGhostHeight();
+
+        g.setComposite(alphaComposite);
+        drawUMLStyle(g, packageTarget, hasFocus, width, height);
+        g.setComposite(oldComposite);
+        g.translate(-packageTarget.getGhostX(), -packageTarget.getGhostY());
+    }
+
+    /**
+     * Draw the package icon.
+     */
+    private void drawUMLStyle(Graphics2D g, PackageTarget packageTarget, boolean hasFocus, int width, int height)
+    {
+        tabWidth = packageTarget.getWidth() / 3;
+        
+        int thickness = 1;  // default
+        boolean isSelected = packageTarget.isSelected() && hasFocus;
+        if (isSelected)
+            thickness = 2;
+
+        Paint fill;
+        fill = new GradientPaint(
+                width/4, 0, new Color(229, 183, 173),
+                width*3/4, height, new Color(207, 130, 117));
+        
+        drawShadow(g, packageTarget, tabWidth, width, height);
+
+        g.setPaint(fill);
+        g.fillRoundRect(0, 0, tabWidth, TAB_HEIGHT+5, 5, 5);
+        g.setColor(bordercolour);
+        Utility.drawThickRoundRect(g, 0, 0, tabWidth, TAB_HEIGHT+5, 5, thickness);
+        // The main rectangles draw on the top of the previous small tab rectangles:
+        g.setPaint(fill);
+        g.fillRect(0, TAB_HEIGHT, width, height - TAB_HEIGHT);
+        g.setColor(bordercolour);
+        for (int i = 0; i < thickness; i++) {
+            // Draws the rect: (i, TAB_HEIGHT+i, width - 2 * i, height - TAB_HEIGHT - 2 * i)
+            // But misses out the top portion on the left for tabWidth
+            g.drawLine(tabWidth - (isSelected ? 1 : 0), TAB_HEIGHT + i, width - i, TAB_HEIGHT + i); //top
+            g.drawLine(i, height - i, width - i, height - i); //bottom
+            g.drawLine(i, TAB_HEIGHT, i, height - i); //left
+            g.drawLine(width - i, TAB_HEIGHT + i, width - i, height - i); //right
+        }
+
+        g.setFont(getFont(packageTarget));
+        Utility.drawCentredText(g, packageTarget.getDisplayName(), TEXT_BORDER, TEXT_BORDER + TAB_HEIGHT + 10,
+                width - 2 * TEXT_BORDER, TEXT_HEIGHT);       
+
+        if (isSelected) {
+            // Draw lines showing resize tag
+            g.drawLine(width - HANDLE_SIZE - 2, height, width, height - HANDLE_SIZE - 2);
+            g.drawLine(width - HANDLE_SIZE + 2, height, width, height - HANDLE_SIZE + 2);
+        }
+    }
+
+    /**
+     * Draw the shadow.
+     */
+    private void drawShadow(Graphics2D g, PackageTarget packageTarget, int tabWidth, int width, int height)
+    {
+     // A uniform tail-off would have equal values for each,
+        // as they all get drawn on top of each other:
+        final int shadowAlphas[] = {20, 15, 10, 5, 5};
+        for (int i = 0;i < 5;i++) {
+            g.setColor(new Color(0, 0, 0, shadowAlphas[i]));
+            
+            // Tab:
+            g.fillRoundRect(2 - i, 4 - i, tabWidth + (2*i) - 1, (TAB_HEIGHT + 5) + (2*i) - 1, 8, 8);
+            // Main:
+            g.fillRoundRect(2 - i, TAB_HEIGHT + 4 - i, width + (2*i) - 1, height - TAB_HEIGHT + (2*i) - 1, 8, 8);
+        }
+    }
+
+    private Font getFont(PackageTarget packageTarget)
+    {
+        return PrefMgr.getTargetFont();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ReadmeTargetPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ReadmeTargetPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..124b7fac53c585e32b506332be6da131ce6e1dd0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/ReadmeTargetPainter.java
@@ -0,0 +1,67 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.graphPainter;
+
+import java.awt.*;
+
+import bluej.Config;
+import bluej.pkgmgr.target.*;
+
+/**
+ * Paints a ReadmeTarget
+ * @author fisker
+ * @version $Id: ReadmeTargetPainter.java 7642 2010-05-20 09:36:36Z nccb $
+ */
+public class ReadmeTargetPainter
+{
+    // Images
+    private static final Image readmeImage = Config.getImageAsIcon("image.readme").getImage();
+    private static final Image selectedReadmeImage = Config.getImageAsIcon("image.readme-selected").getImage();
+
+    /**
+     * Create the painter.
+     */
+    public ReadmeTargetPainter()
+    {
+    }
+    
+    /**
+     * Paint the given target on the specified graphics context.
+     * @param g  The graphics context to paint on.
+     * @param target  The target to paint.
+     */
+    public void paint(Graphics2D g, Target target, boolean hasFocus)
+    {
+        boolean isSelected = target.isSelected() && hasFocus;
+        g.drawImage(isSelected ? selectedReadmeImage : readmeImage, target.getX(), target.getY(), null);
+    }
+    
+    public static int getMaxImageWidth()
+    {
+        return Math.max(readmeImage.getWidth(null), selectedReadmeImage.getWidth(null));
+    }
+    
+    public static int getMaxImageHeight()
+    {
+        return Math.max(readmeImage.getHeight(null), selectedReadmeImage.getHeight(null));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/UsesDependencyPainter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/UsesDependencyPainter.java
new file mode 100644
index 0000000000000000000000000000000000000000..09f2e831da340cb1f4cc6f41283f04c6dc131fcd
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/graphPainter/UsesDependencyPainter.java
@@ -0,0 +1,193 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.graphPainter;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.RenderingHints;
+import java.awt.Stroke;
+
+import bluej.graph.RubberBand;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.dependency.UsesDependency;
+
+/**
+ * Paints usesDependencies
+ * 
+ * @author fisker
+ * @author Michael Kolling
+ */
+public class UsesDependencyPainter
+    implements DependencyPainter
+{
+    protected static final float strokeWidthDefault = 1.0f;
+    protected static final float strokeWidthSelected = 2.0f;
+    static final int ARROW_SIZE = 10; // pixels
+    static final double ARROW_ANGLE = Math.PI / 6; // radians
+
+    private static final Color normalColour = Color.BLACK;
+
+    private static final float dash1[] = {5.0f, 2.0f};
+    private static final BasicStroke dashedUnselected = new BasicStroke(strokeWidthDefault, BasicStroke.CAP_BUTT,
+            BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
+    private static final BasicStroke dashedSelected = new BasicStroke(strokeWidthSelected, BasicStroke.CAP_BUTT,
+            BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f);
+    private static final BasicStroke normalSelected = new BasicStroke(strokeWidthSelected);
+    private static final BasicStroke normalUnselected = new BasicStroke(strokeWidthDefault);
+
+    public UsesDependencyPainter()
+    {
+    }
+
+    public void paint(Graphics2D g, Dependency dependency, boolean hasFocus)
+    {
+        if (!(dependency instanceof UsesDependency)) {
+            throw new IllegalArgumentException("Not a UsesDependency");
+        }
+        Stroke oldStroke = g.getStroke();
+        UsesDependency d = (UsesDependency) dependency;
+        Stroke dashedStroke, normalStroke;
+        boolean isSelected = d.isSelected() && hasFocus;
+        if (isSelected) {
+            dashedStroke = dashedSelected;
+            normalStroke = normalSelected;
+        }
+        else {
+            dashedStroke = dashedUnselected;
+            normalStroke = normalUnselected;
+        }
+        g.setStroke(normalStroke);
+        int src_x = d.getSourceX();
+        int src_y = d.getSourceY();
+        int dst_x = d.getDestX();
+        int dst_y = d.getDestY();
+        ;
+
+        g.setColor(normalColour);
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        // Draw the end arrow
+        int delta_x = d.isEndLeft() ? -10 : 10;
+
+        g.drawLine(dst_x, dst_y, dst_x + delta_x, dst_y + 4);
+        g.drawLine(dst_x, dst_y, dst_x + delta_x, dst_y - 4);
+        g.setStroke(dashedStroke);
+
+        // Draw the start
+        int corner_y = src_y + (d.isStartTop() ? -15 : 15);
+        g.drawLine(src_x, corner_y, src_x, src_y);
+        src_y = corner_y;
+
+        // Draw the last line segment
+        int corner_x = dst_x + (d.isEndLeft() ? -15 : 15);
+        g.drawLine(corner_x, dst_y, dst_x, dst_y);
+        dst_x = corner_x;
+
+        // if arrow vertical corner, draw first segment up to corner
+        if ((src_y != dst_y) && (d.isStartTop() == (src_y < dst_y))) {
+            corner_x = ((src_x + dst_x) / 2) + (d.isEndLeft() ? 15 : -15);
+            corner_x = (d.isEndLeft() ? Math.min(dst_x, corner_x) : Math.max(dst_x, corner_x));
+            g.drawLine(src_x, src_y, corner_x, src_y);
+            src_x = corner_x;
+        }
+
+        // if arrow horiz. corner, draw first segment up to corner
+        if ((src_x != dst_x) && (d.isEndLeft() == (src_x > dst_x))) {
+            corner_y = ((src_y + dst_y) / 2) + (d.isStartTop() ? 15 : -15);
+            corner_y = (d.isStartTop() ? Math.min(src_y, corner_y) : Math.max(src_y, corner_y));
+            g.drawLine(dst_x, corner_y, dst_x, dst_y);
+            dst_y = corner_y;
+        }
+
+        // draw the middle bit
+        g.drawLine(src_x, src_y, src_x, dst_y);
+        g.drawLine(src_x, dst_y, dst_x, dst_y);
+
+        g.setStroke(oldStroke);
+    }
+
+    /**
+     * Paint the usesdependency from DependTarget d, as a straight arrow to a
+     * point in the graph determined also by d
+     * 
+     * @param g
+     * @param d
+     */
+    public void paintIntermedateDependency(Graphics2D g, RubberBand rb)
+    {
+        Stroke dashedStroke, normalStroke;
+        dashedStroke = dashedUnselected;
+        normalStroke = normalUnselected;
+        g.setStroke(normalStroke);
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+        g.setColor(normalColour);
+
+        // Start from the centre of the src class
+        Point pFrom = rb.startPt;
+        Point pTo = rb.endPt;
+
+        // Get the angle of the line from src to dst.
+        double angle = Math.atan2(-(pFrom.getY() - pTo.getY()), pFrom.getX() - pTo.getX());
+
+//        Point pArrow = new Point(pTo.x + (int) ((ARROW_SIZE - 2) * Math.cos(angle)), pTo.y
+//                - (int) ((ARROW_SIZE - 2) * Math.sin(angle)));
+
+        // setup the arrow head
+        int[] xPoints = {pTo.x, pTo.x + (int) ((ARROW_SIZE) * Math.cos(angle + ARROW_ANGLE)),
+                pTo.x + (int) (ARROW_SIZE * Math.cos(angle - ARROW_ANGLE))};
+        int[] yPoints = {pTo.y, pTo.y - (int) ((ARROW_SIZE) * Math.sin(angle + ARROW_ANGLE)),
+                pTo.y - (int) (ARROW_SIZE * Math.sin(angle - ARROW_ANGLE))};
+
+        //draw the arrowhead
+        g.drawLine(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
+        g.drawLine(xPoints[0], yPoints[0], xPoints[2], yPoints[2]);
+        //draw the arrow line
+        g.setStroke(dashedStroke);
+        g.drawLine(pFrom.x, pFrom.y, xPoints[0], yPoints[0]);
+
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see bluej.pkgmgr.graphPainter.DependencyPainter#getPopupMenuPosition(bluej.pkgmgr.dependency.Dependency)
+     */
+    public Point getPopupMenuPosition(Dependency d)
+    {
+        UsesDependency usesDependency;
+        if (!(d instanceof UsesDependency)) {
+            throw new IllegalArgumentException("Not a UsesDependency");
+        }
+        usesDependency = (UsesDependency) d;
+
+        int delta_x = usesDependency.isEndLeft() ? -10 : 10;
+        int dst_x = usesDependency.getDestX();
+        int dst_y = usesDependency.getDestY();
+
+        int[] xPoints = {dst_x, dst_x + delta_x, dst_x + delta_x};
+        int[] yPoints = {dst_y, dst_y - 3, dst_y + 3};
+
+        return new Point((xPoints[0] + xPoints[1] + xPoints[2]) / 3, (yPoints[0] + yPoints[1] + yPoints[2]) / 3);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/ClassTarget.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/ClassTarget.java
new file mode 100644
index 0000000000000000000000000000000000000000..29fe304b600129858b61b84e204d5274560c2f22
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/ClassTarget.java
@@ -0,0 +1,2024 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target;
+
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.swing.AbstractAction;
+import javax.swing.JPopupMenu;
+
+import bluej.Config;
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.gentype.Reflective;
+import bluej.debugmgr.objectbench.InvokeListener;
+import bluej.editor.Editor;
+import bluej.editor.EditorManager;
+import bluej.extensions.BClass;
+import bluej.extensions.BClassTarget;
+import bluej.extensions.BDependency;
+import bluej.extensions.ExtensionBridge;
+import bluej.extensions.event.ClassEvent;
+import bluej.extensions.event.ClassTargetEvent;
+import bluej.extmgr.ClassMenuObject;
+import bluej.extmgr.ExtensionsManager;
+import bluej.extmgr.MenuManager;
+import bluej.graph.GraphEditor;
+import bluej.graph.Moveable;
+import bluej.graph.Vertex;
+import bluej.parser.entity.EntityResolver;
+import bluej.parser.entity.PackageResolver;
+import bluej.parser.entity.ParsedReflective;
+import bluej.parser.nodes.ParsedCUNode;
+import bluej.parser.nodes.ParsedTypeNode;
+import bluej.parser.symtab.ClassInfo;
+import bluej.parser.symtab.Selection;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.SourceInfo;
+import bluej.pkgmgr.dependency.Dependency;
+import bluej.pkgmgr.dependency.ExtendsDependency;
+import bluej.pkgmgr.dependency.ImplementsDependency;
+import bluej.pkgmgr.dependency.UsesDependency;
+import bluej.pkgmgr.target.role.AbstractClassRole;
+import bluej.pkgmgr.target.role.AppletClassRole;
+import bluej.pkgmgr.target.role.ClassRole;
+import bluej.pkgmgr.target.role.EnumClassRole;
+import bluej.pkgmgr.target.role.InterfaceClassRole;
+import bluej.pkgmgr.target.role.MIDletClassRole;
+import bluej.pkgmgr.target.role.StdClassRole;
+import bluej.pkgmgr.target.role.UnitTestClassRole;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.FileEditor;
+import bluej.utility.FileUtility;
+import bluej.utility.JavaNames;
+import bluej.utility.JavaReflective;
+import bluej.utility.JavaUtils;
+import bluej.views.ConstructorView;
+import bluej.views.MethodView;
+
+/**
+ * A class target in a package, i.e. a target that is a class file built from
+ * Java source code
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ * @author Bruce Quig
+ */
+public class ClassTarget extends DependentTarget
+    implements Moveable, InvokeListener
+{
+    final static int MIN_WIDTH = 60;
+    final static int MIN_HEIGHT = 30;
+    private final static String editStr = Config.getString("pkgmgr.classmenu.edit");
+    private final static String compileStr = Config.getString("pkgmgr.classmenu.compile");
+    private final static String inspectStr = Config.getString("pkgmgr.classmenu.inspect");
+    private final static String removeStr = Config.getString("pkgmgr.classmenu.remove");
+    private final static String createTestStr = Config.getString("pkgmgr.classmenu.createTest");
+
+    // Define Background Colours
+    private final static Color compbg = new Color(200,150,100);
+
+    private static String usesArrowMsg = Config.getString("pkgmgr.usesArrowMsg");
+
+    // temporary file name extension to trick windows if changing case only in
+    // class name
+    private static String TEMP_FILE_EXTENSION = "-temp";
+    
+    // the role object represents the changing roles that are class
+    // target can have ie changing from applet to an interface etc
+    // 'role' should never be null
+    // role should be accessed using getRole() and set using
+    // setRole(). A role should not contain important state information
+    // because role objects are thrown away at a whim.
+    private ClassRole role = new StdClassRole();
+
+    // a flag indicating whether an editor, when opened for the first
+    // time, should display the interface of this class
+    private boolean openWithInterface = false;
+
+    // cached information obtained by parsing the source code
+    // automatically becomes invalidated when the source code is
+    // edited
+    private SourceInfo sourceInfo = new SourceInfo();
+    
+    // caches whether the class is abstract. Only accurate when the
+    // classtarget state is normal (ie. the class is compiled).
+    private boolean isAbstract;
+    
+    // a flag indicating whether an editor should have the naviview expanded/collapsed
+    private Boolean isNaviviewExpanded=null;
+
+    // flag to prevent recursive calls to analyseDependancies()
+    private boolean analysing = false;
+
+    private int ghostX;
+    private int ghostY;
+    private int ghostWidth;
+    private int ghostHeight;
+    private boolean isDragging = false;
+    private boolean isMoveable = true;
+    private boolean hasSource;
+    
+    // Whether the source has been modified since it was last compiled. This
+    // starts off as "true", which is a lie, but it prevents setting breakpoints
+    // in an initially uncompiled class.
+    private boolean modifiedSinceCompile = true;
+
+    private String typeParameters = "";
+    
+    //properties map to store values used in the editor from the props (if necessary)
+    private Map<String,String> properties = new HashMap<String,String>();
+    
+    /**
+     * Create a new class target in package 'pkg'.
+     * 
+     * @param pkg Description of the Parameter
+     * @param baseName Description of the Parameter
+     */
+    public ClassTarget(Package pkg, String baseName)
+    {
+        this(pkg, baseName, null);
+    }
+
+    /**
+     * Create a new class target in package 'pkg'.
+     * 
+     * @param pkg Description of the Parameter
+     * @param baseName Description of the Parameter
+     * @param template Description of the Parameter
+     */
+    public ClassTarget(Package pkg, String baseName, String template)
+    {
+        super(pkg, baseName);
+        hasSource = getSourceFile().canRead();
+
+        // we can take a guess at what the role is going to be for the
+        // object based on the start of the template name. If we get this
+        // wrong, its no great shame as it'll be fixed the first time they
+        // successfully analyse/compile the source.
+        if (template != null) {
+            if (template.startsWith("applet")) {
+                role = new AppletClassRole();
+            }
+            else if (template.startsWith("unittest")) {
+                role = new UnitTestClassRole(true);
+            }
+            else if (template.startsWith("abstract")) {
+                role = new AbstractClassRole();
+            }
+            else if (template.startsWith("interface")) {
+                role = new InterfaceClassRole();
+            }
+            else if (template.startsWith("enum")) {
+                role = new EnumClassRole();
+            }
+            else if (template.startsWith("midlet")) {
+                role = new MIDletClassRole();
+            }            
+        }
+        setGhostPosition(0, 0);
+        setGhostSize(0, 0);
+    }
+
+    private BClass singleBClass;  // Every Target has none or one BClass
+    private BClassTarget singleBClassTarget; // Every Target has none or one BClassTarget
+    
+    /**
+     * Return the extensions BProject associated with this Project.
+     * There should be only one BProject object associated with each Project.
+     * @return the BProject associated with this Project.
+     */
+    public synchronized final BClass getBClass ()
+    {
+        if ( singleBClass == null ) {
+            singleBClass = ExtensionBridge.newBClass(this);
+        }
+          
+        return singleBClass;
+    }
+
+    /**
+     * Returns the {@link BClassTarget} associated with this {@link ClassTarget}
+     * . There should be only one {@link BClassTarget} object associated with
+     * each {@link ClassTarget}.
+     * 
+     * @return The {@link BClassTarget} associated with this {@link ClassTarget}.
+     */
+    public synchronized final BClassTarget getBClassTarget()
+    {
+        if (singleBClassTarget == null) {
+            singleBClassTarget = ExtensionBridge.newBClassTarget(this);
+        }
+
+        return singleBClassTarget;
+    }
+
+
+    /**
+     * Return the target's name, including the package name. eg.
+     * bluej.pkgmgr.Target
+     * 
+     * @return The qualifiedName value
+     */
+    public String getQualifiedName()
+    {
+        return getPackage().getQualifiedName(getBaseName());
+    }
+
+    /**
+     * Return the target's base name (ie the name without the package name). eg.
+     * Target
+     * 
+     * @return The baseName value
+     */
+    public String getBaseName()
+    {
+        return getIdentifierName();
+    }
+
+    /**
+     * Return information about the source of this class.
+     * 
+     * @return The source info object.
+     */
+    public SourceInfo getSourceInfo()
+    {
+        return sourceInfo;
+    }
+
+    /**
+     * Get a reflective for the type represented by this target.
+     * 
+     * @return  A suitable reflective, or null.
+     */
+    public Reflective getTypeRefelective()
+    {
+        // If compiled, return a reflective based on actual reflection
+        if (isCompiled()) {
+            Class<?> cl = getPackage().loadClass(getQualifiedName());
+            if (cl != null) {
+                return new JavaReflective(cl);
+            }
+            else {
+                return null;
+            }
+        }
+        
+        // Not compiled; try to get a reflective from the parser
+        ParsedCUNode node = null;
+        getEditor();
+        if (editor != null) {
+            node = editor.getParsedNode();
+        }
+        
+        if (node != null) {
+            ParsedTypeNode ptn = (ParsedTypeNode) node.getTypeNode(getBaseName());
+            if (ptn != null) {
+                return new ParsedReflective(ptn);
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Returns the text which the target is displaying as its label. For normal
+     * classes this is just the identifier name. For generic classes the generic
+     * parameters are shown as well
+     * 
+     * @return The displayName value
+     */
+    @Override
+    public String getDisplayName()
+    {
+        return super.getDisplayName() + getTypeParameters();
+    }
+
+    /**
+     * Returns the type parameters for a generic class as declared in the source
+     * file.
+     * 
+     * @return The typeParameters value
+     */
+    private String getTypeParameters()
+    {
+        return typeParameters;
+    }
+
+    /**
+     * Change the state of this target. The target will be repainted to show the
+     * new state.
+     * 
+     * @param newState The new state value
+     */
+    @Override
+    public void setState(int newState)
+    {
+        if (state != newState) {
+            getPackage().getProject().removeInspectorInstance(getQualifiedName());
+            
+            // Notify extensions if necessary. Note we don't distinguish
+            // S_COMPILING and S_INVALID.
+            if (newState == S_NORMAL) {
+                modifiedSinceCompile = false;
+                if (editor != null) {
+                    editor.reInitBreakpoints();
+                }
+                ClassEvent event = new ClassEvent(ClassEvent.STATE_CHANGED, getPackage(), getBClass(), true);
+                ExtensionsManager.getInstance().delegateEvent(event);
+            }
+            else if (state == S_NORMAL) {
+                ClassEvent event = new ClassEvent(ClassEvent.STATE_CHANGED, getPackage(), getBClass(), false);
+                ExtensionsManager.getInstance().delegateEvent(event);
+            }
+            
+            state = newState;
+            repaint();
+        }
+    }
+
+    /**
+     * Return the role object for this class target.
+     * 
+     * @return The role value
+     */
+    public ClassRole getRole()
+    {
+        return role;
+    }
+
+    /**
+     * Set the role for this class target.
+     * 
+     * <p>Avoids changing over the role object if the new one is of the same type.
+     * 
+     * @param newRole The new role value
+     */
+    protected void setRole(ClassRole newRole)
+    {
+        if (role.getRoleName() != newRole.getRoleName()) {
+            role = newRole;
+        }
+    }
+
+    /**
+     * Test if a given class is a Junit 4 test class.
+     * 
+     * <p>In Junit4, test classes can be of any type.
+     * The only way to test is to check if it has one of the following annotations:
+     * @Before, @Test or @After
+     * 
+     * @param cl class to test
+     */
+    @SuppressWarnings("unchecked")
+    public static boolean isJunit4TestClass(Class<?> cl)
+    {
+        ClassLoader clLoader = cl.getClassLoader();
+        try {
+            Class<? extends Annotation> beforeClass =
+                (Class<? extends Annotation>) Class.forName("org.junit.Before", false, clLoader);
+            Class<? extends Annotation> afterClass =
+                (Class<? extends Annotation>) Class.forName("org.junit.After", false, clLoader);
+            Class<? extends Annotation> testClass =
+                (Class<? extends Annotation>) Class.forName("org.junit.Test", false, clLoader);
+
+            Method[] methods = cl.getDeclaredMethods();
+            for (int i=0; i<methods.length; i++) {
+                if (methods[i].getAnnotation(beforeClass) != null) {
+                    return true;
+                }
+                if (methods[i].getAnnotation(afterClass) != null) {
+                    return true;
+                }
+                if (methods[i].getAnnotation(testClass) != null) {
+                    return true;
+                }
+            }
+
+        }
+        catch (ClassNotFoundException cnfe) {}
+        catch (LinkageError le) {}
+
+        // No suitable annotations found, so not a test class
+        return false;
+    }
+    
+    /**
+     * Use a variety of tests to determine what our role is.
+     * 
+     * <p>All tests must be very quick and should not rely on any significant
+     * computation (ie. reparsing). If computation is required, the existing
+     * role will do for the time being.
+     * 
+     * @param cl Description of the Parameter
+     */
+    public void determineRole(Class<?> cl)
+    {
+        isAbstract = false;
+        
+        if (cl != null) {
+            isAbstract = Modifier.isAbstract(cl.getModifiers());
+            
+            ClassLoader clLoader = cl.getClassLoader();
+            Class<?> junitClass = null;
+            Class<?> appletClass = null;
+            Class<?> midletClass = null;
+
+            // It shouldn't ever be the case that the class is on the bootstrap
+            // class path (and was loaded by the bootstrap class loader), unless
+            // someone has done something rather strange - but it has happened;
+            // see bug # 1017.
+
+            if (clLoader != null) {
+                try {
+                    junitClass = clLoader.loadClass("junit.framework.TestCase");
+                }
+                catch (ClassNotFoundException cnfe) {}
+                catch (LinkageError le) {}
+
+                try {
+                    appletClass = clLoader.loadClass("java.applet.Applet");
+                }
+                catch (ClassNotFoundException cnfe) {}
+                catch (LinkageError le) {}
+                
+                try {
+                    midletClass = clLoader.loadClass("javax.microedition.midlet.MIDlet");
+                }
+                catch (ClassNotFoundException cnfe) {}
+                catch (LinkageError le) {}
+            }
+            
+            if (junitClass == null) {
+                junitClass = junit.framework.TestCase.class;
+            }
+            
+            if (appletClass == null) {
+                appletClass = java.applet.Applet.class;
+            }
+            
+            // As cl is non-null, it is the definitive information
+            // source ie. if it thinks its an applet who are we to argue
+            // with it.
+            if (appletClass.isAssignableFrom(cl)) {
+                setRole(new AppletClassRole());
+            }
+            else if (junitClass.isAssignableFrom(cl)) {
+                setRole(new UnitTestClassRole(false));
+            }
+            else if (Modifier.isInterface(cl.getModifiers())) {
+                setRole(new InterfaceClassRole());
+            }
+            else if (JavaUtils.getJavaUtils().isEnum(cl)) {
+                setRole(new EnumClassRole());
+            }
+            else if (isAbstract) {
+                setRole(new AbstractClassRole());
+            }
+            else if ( ( midletClass != null )  &&  ( midletClass.isAssignableFrom(cl) ) ) {
+                setRole(new MIDletClassRole());
+            }
+            else if (isJunit4TestClass(cl)) {
+                setRole(new UnitTestClassRole(true));
+            }
+            else {
+                setRole(new StdClassRole());
+            }
+        }
+        else {
+            // try the parsed source code
+            ClassInfo classInfo = sourceInfo.getInfoIfAvailable();
+
+            if (classInfo != null) {
+                if (classInfo.isApplet()) {
+                    setRole(new AppletClassRole());
+                }
+                else if (classInfo.isMIDlet()) {
+                    setRole(new MIDletClassRole());
+                }          
+                else if (classInfo.isUnitTest()) {
+                    setRole(new UnitTestClassRole(false));
+                }
+                else if (classInfo.isInterface()) {
+                    setRole(new InterfaceClassRole());
+                }
+                else if (classInfo.isEnum()) {
+                    setRole(new EnumClassRole());
+                }
+                else if (classInfo.isAbstract()) {
+                    setRole(new AbstractClassRole());
+                }
+                else {
+                    // We shouldn't override applet/unit test class roles based only
+                    // on source analysis: if they inherit only indirectly from Applet
+                    // or UnitTest, source analysis won't give the correct role
+                    if (! (role instanceof AppletClassRole) &&
+                            ! (role instanceof UnitTestClassRole))
+                    {
+                        setRole(new StdClassRole());
+                    }
+                }
+            }
+            // If no information gained from parsing the file (classInfo = null),
+            // then we don't really know the role: let's leave it as it was
+        }
+    }
+
+    /**
+     * Load existing information about this class target
+     * 
+     * @param props the properties object to read
+     * @param prefix an internal name used for this target to identify its
+     *            properties in a properties file used by multiple targets.
+     * @exception NumberFormatException Description of the Exception
+     */
+    @Override
+    public void load(Properties props, String prefix)
+        throws NumberFormatException
+    {
+        super.load(props, prefix);
+
+        // try to determine if any role was set when we saved
+        // the class target. Be careful here as if you add role types
+        // you need to add them here as well.
+        String type = props.getProperty(prefix + ".type");
+
+        String intf = props.getProperty(prefix + ".showInterface");
+        openWithInterface = Boolean.valueOf(intf).booleanValue();
+
+        if (AppletClassRole.APPLET_ROLE_NAME.equals(type)) {
+            setRole(new AppletClassRole());
+        }
+        else if (MIDletClassRole.MIDLET_ROLE_NAME.equals(type)) {
+            setRole(new MIDletClassRole());
+        }
+        else if (UnitTestClassRole.UNITTEST_ROLE_NAME.equals(type)) {
+            setRole(new UnitTestClassRole(false));
+        }
+        else if (UnitTestClassRole.UNITTEST_ROLE_NAME_JUNIT4.equals(type)) {
+            setRole(new UnitTestClassRole(true));
+        }
+        else if (AbstractClassRole.ABSTRACT_ROLE_NAME.equals(type)) {
+            setRole(new AbstractClassRole());
+        }
+        else if (InterfaceClassRole.INTERFACE_ROLE_NAME.equals(type)) {
+            setRole(new InterfaceClassRole());
+        }
+        else if (EnumClassRole.ENUM_ROLE_NAME.equals(type)) {
+            setRole(new EnumClassRole());
+        }
+
+        getRole().load(props, prefix);
+        String value=props.getProperty(prefix + ".naviview.expanded");
+        if (value!=null){
+            setNaviviewExpanded(Boolean.parseBoolean(value));
+            setProperty(NAVIVIEW_EXPANDED_PROPERTY, String.valueOf(value));
+        }
+    }
+
+    /**
+     * Save information about this class target
+     * 
+     * 
+     * @param props the properties object to save to
+     * @param prefix an internal name used for this target to identify its
+     *            properties in a properties file used by multiple targets.
+     */
+    @Override
+    public void save(Properties props, String prefix)
+    {
+        super.save(props, prefix);
+
+        if (getRole().getRoleName() != null) {
+            props.put(prefix + ".type", getRole().getRoleName());
+        }
+
+        if (editorOpen()) {
+            openWithInterface = getEditor().isShowingInterface();          
+        }
+        //saving the state of the naviview (open/close) to the props 
+        //setting the value of the expanded according to the value from the editor (if there is)
+        //else if there was a previous setting use that
+        if (editorOpen() && getProperty(NAVIVIEW_EXPANDED_PROPERTY)!=null){
+            props.put(prefix + ".naviview.expanded", String.valueOf(getProperty(NAVIVIEW_EXPANDED_PROPERTY)));
+        } else if (isNaviviewExpanded!=null)
+                props.put(prefix + ".naviview.expanded", String.valueOf(isNaviviewExpanded()));
+            
+        props.put(prefix + ".showInterface", new Boolean(openWithInterface).toString());
+
+        getRole().save(props, 0, prefix);
+     
+        
+    }
+
+    /**
+     * Notification that the source file may have been updated, and so we should
+     * reload.
+     */
+    public void reload()
+    {
+        hasSource = getSourceFile().canRead();
+        if (hasSource) {
+            if (editor != null) {
+                editor.reloadFile();
+            }
+            else {
+                analyseSource();
+            }
+        }
+    }
+    
+    /**
+     * Check if the compiled class and the source are up to date.
+     * (Specifically, check if recompilation is not needed. This will
+     * always be considered true if the target has no source).
+     * 
+     * @return true if they are in sync (or there is no source); otherwise false.
+     */
+    public boolean upToDate()
+    {
+        // check if the class file is up to date
+        File src = getSourceFile();
+        File clss = getClassFile();
+
+        // if just a .class file with no src, it better be up to date
+        if (!hasSourceCode()) {
+            return true;
+        }
+
+        if (!clss.exists() || (src.exists() && (src.lastModified() > clss.lastModified()))) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Mark this class as modified, and mark all dependent classes too
+     */
+    public void invalidate()
+    {
+        setState(S_INVALID);
+        for (Iterator<? extends Dependency> it = dependents(); it.hasNext();) {
+            Dependency d = it.next();
+            ClassTarget dependent = (ClassTarget) d.getFrom();
+            
+            if (! dependent.isInvalidState()) {    
+                // Invalidate the dependent only if it is not already invalidated. 
+                // Will avoid going into an infinite circular loop.
+                dependent.invalidate();
+            }
+        }
+    }
+
+    /**
+     * Verify whether this class target is an interface class
+     * 
+     * @return true if class target is an interface class, else returns false
+     */
+    public boolean isInterface()
+    {
+        return (getRole() instanceof InterfaceClassRole);
+    }
+
+    /**
+     * Verify whether this class target is an unit test class
+     * 
+     * @return true if class target is a unit test class, else returns false
+     */
+    public boolean isUnitTest()
+    {
+        return (getRole() instanceof UnitTestClassRole);
+    }
+    
+    /**
+     * Verify whether this class target represents an Enum
+     * 
+     * @return true if class target represents an Enum, else false
+     */
+    public boolean isEnum()
+    {
+        return (getRole() instanceof EnumClassRole);
+    }
+
+    /**
+     * Check whether this class target represents an abstract class. This
+     * can be true regardless of the role (unit test, applet, standard class).
+     * 
+     * The return is only valid if isCompiled() is true.
+     */
+    public boolean isAbstract()
+    {
+        return isAbstract;
+    }
+    
+    // --- Target interface ---
+
+    /**
+     * Gets the backgroundColour attribute of the ClassTarget object
+     * 
+     * @return The backgroundColour value
+     */
+    public Paint getBackgroundPaint(int width, int height)
+    {
+        if (state == S_COMPILING) {
+            return compbg;
+        }
+        else {
+            return getRole().getBackgroundPaint(width, height);
+        }
+    }
+
+
+    // --- EditableTarget interface ---
+
+    /**
+     * Tell whether we have access to the source for this class.
+     * 
+     * @return Description of the Return Value
+     */
+    public boolean hasSourceCode()
+    {
+        return hasSource;
+    }
+
+    /**
+     * @return the name of the (text) file this target corresponds to.
+     */
+    public File getSourceFile()
+    {
+        return new File(getPackage().getPath(), getBaseName() + ".java");
+    }
+
+    /**
+     * @return the name of the context(.ctxt) file this target corresponds to.
+     */
+    public File getContextFile()
+    {
+        return new File(getPackage().getPath(), getBaseName() + ".ctxt");
+    }
+
+    /**
+     * @return the name of the class (.class) file this target corresponds to.
+     */
+    public File getClassFile()
+    {
+        return new File(getPackage().getPath(), getBaseName() + ".class");
+    }
+
+    /**
+     * Get the name of the documentation (.html) file corresponding to this target.
+     */
+    public File getDocumentationFile()
+    {
+        String filename = getSourceFile().getPath();
+        String docFilename = getPackage().getProject().getDocumentationFile(filename);
+        return new File(docFilename);
+    }
+    
+    /**
+     * Get a list of .class files for inner classes.
+     */
+    public File [] getInnerClassFiles()
+    {
+        File[] files = getPackage().getPath().listFiles(new InnerClassFileFilter());
+        return files;
+    }
+
+    /**
+     * Description of the Class
+     */
+    class InnerClassFileFilter
+        implements FileFilter
+    {
+        /**
+         * Description of the Method
+         * 
+         * @param pathname Description of the Parameter
+         * @return Description of the Return Value
+         */
+        public boolean accept(File pathname)
+        {
+            return pathname.getName().startsWith(getBaseName() + "$");
+        }
+    }
+
+    /**
+     * Get the editor associated with this class.
+     * @return the editor object associated with this target. May be null if
+     *         there was a problem opening this editor.
+     */
+    public Editor getEditor()
+    {
+        return getEditor(openWithInterface);
+    }
+
+    /**
+     * Get an editor for this class, either in source view or interface view.
+     * 
+     * @param showInterface Determine whether to show interface view or 
+     *         source view in the editor.
+     * @return the editor object associated with this target. May be null if
+     *         there was a problem opening this editor.
+     */
+    private Editor getEditor(boolean showInterface)
+    {
+        // ClassTarget must have source code if it is to provide an editor
+        if (editor == null) {
+            String filename = getSourceFile().getPath();
+            String docFilename = getPackage().getProject().getDocumentationFile(filename);
+            if (! hasSourceCode()) {
+                filename = null; // no source - show docs only
+                showInterface = true;
+                if (! new File(docFilename).exists()) {
+                    return null;
+                }
+            }
+            
+            Project project = getPackage().getProject();
+            EntityResolver resolver = new PackageResolver(project.getEntityResolver(),
+                    getPackage().getQualifiedName());
+            
+            if (editorBounds == null) {
+                PkgMgrFrame frame = PkgMgrFrame.findFrame(getPackage());
+                if (frame != null) {
+                    editorBounds = new Rectangle();
+                    editorBounds.x = frame.getX() + 40;
+                    editorBounds.y = frame.getY() + 20;
+                }
+            }
+            
+            editor = EditorManager.getEditorManager().openClass(filename, docFilename,
+                    project.getProjectCharset(),
+                    getBaseName(), this, isCompiled(), editorBounds, resolver,
+                    project.getJavadocResolver());
+            
+            // editor may be null if source has been deleted
+            // for example.
+            if (editor != null) {
+                editor.showInterface(showInterface);
+            }           
+        }
+        return editor;
+    }
+
+    /**
+     * Ensure that the source file of this class is up-to-date (i.e.
+     * that any possible unsaved changes in an open editor window are 
+     * saved).
+     * 
+     * <p>This can cause saveEvent() to be generated, which might move
+     * the class to a new package (if the package line has been changed).
+     */
+    @Override
+    public void ensureSaved() throws IOException
+    {
+        if(editor != null) {
+            editor.save();
+        }
+    }
+    
+    // --- end of EditableTarget interface ---
+
+    // --- user interface function implementation ---
+
+    /**
+     */
+    private void inspect()
+    {
+        new Thread() {
+            
+            int state = 0;
+            DebuggerClass clss;
+            
+            @Override
+            public void run() {
+                switch (state) {
+                    // This is the intial state. Try and load the class.
+                    case 0:
+                        try {
+                            clss = getPackage().getDebugger().getClass(getQualifiedName(), true);
+                            state = 1;
+                            EventQueue.invokeLater(this);
+                        }
+                        catch (ClassNotFoundException cnfe) {}
+                        break;
+                
+                    // Once this state is reached, we're running on the Swing event queue.
+                    case 1:
+                        getPackage().getProject().getClassInspectorInstance(clss, getPackage(), PkgMgrFrame.findFrame(getPackage()));
+                }
+            }
+        }.start();
+    }
+
+    // --- EditorWatcher interface ---
+
+    @Override
+    public void modificationEvent(Editor editor)
+    {
+        invalidate();
+        if (! modifiedSinceCompile) {
+            removeBreakpoints();
+            getPackage().getProject().getDebugger().removeBreakpointsForClass(getQualifiedName());
+            modifiedSinceCompile = true;
+        }
+        sourceInfo.setSourceModified();
+    }
+
+    @Override
+    public void saveEvent(Editor editor)
+    {
+        ClassInfo info = analyseSource();
+        if (info != null) {
+            updateTargetFile(info);
+        }
+        determineRole(null);
+    }
+
+    @Override
+    public String breakpointToggleEvent(Editor editor, int lineNo, boolean set)
+    {
+        if (isCompiled() || ! modifiedSinceCompile) {
+            String possibleError = getPackage().getDebugger().toggleBreakpoint(getQualifiedName(), lineNo, set, null);
+            return possibleError;
+        }
+        else {
+            return Config.getString("pkgmgr.breakpointMsg");
+        }
+    }
+
+    // --- end of EditorWatcher interface ---
+
+    /**
+     * Remove all breakpoints in this class.
+     */
+    public void removeBreakpoints()
+    {
+        if (editor != null) {
+            editor.removeBreakpoints();
+        }
+    }
+    
+    /**
+     * Re-initialize the breakpoints which have been set in this
+     * class.
+     */
+    public void reInitBreakpoints()
+    {
+        if (editor != null && isCompiled()) {
+            editor.reInitBreakpoints();
+        }
+    }
+    
+    /**
+     * Remove the step mark in this case
+     * (the mark in the editor that shows where execution is)
+     */
+    public void removeStepMark()
+    {
+        if (editor != null) {
+            editor.removeStepMark();
+        }
+    }
+
+    /**
+     * Gets the compiled attribute of the ClassTarget object
+     * 
+     * @return The compiled value
+     */
+    public boolean isCompiled()
+    {
+        return (state == S_NORMAL);
+    }
+
+    /**
+     * Description of the Method
+     * 
+     * @param editor Description of the Parameter
+     */
+    @Override
+    public void compile(Editor editor)
+    {
+        getPackage().compile(this);
+    }
+
+    /**
+     * Called when this class target has just been successfully compiled.
+     * 
+     * We load the compiled class if possible and check it the compilation has
+     * resulted in it taking a different role (ie abstract to applet)
+     */
+    public void endCompile()
+    {
+        Class<?> cl = getPackage().loadClass(getQualifiedName());
+
+        determineRole(cl);
+        analyseDependencies(cl);
+    }
+
+    /**
+     * generates a source code skeleton for this class
+     */
+    public boolean generateSkeleton(String template)
+    {
+        // delegate to role object
+        if (template == null) {
+            Debug.reportError("generate class skeleton error");
+            return false;
+        }
+        else {
+            boolean success = role.generateSkeleton(template, getPackage(), getBaseName(), getSourceFile().getPath());
+            if (success) {
+                // skeleton successfully generated
+                setState(S_INVALID);
+                hasSource = true;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Description of the Method
+     * 
+     * @param packageName Description of the Parameter
+     * @exception IOException Description of the Exception
+     */
+    public void enforcePackage(String packageName)
+        throws IOException
+    {
+        if (!JavaNames.isQualifiedIdentifier(packageName)) {
+            throw new IllegalArgumentException();
+        }
+
+        ClassInfo info = sourceInfo.getInfo(getSourceFile(), getPackage());
+        if (info == null) {
+            return;
+        }
+
+        // We may or may not need to change each of the semi colon selection text,
+        // package name selection text, and package statement selection text.
+        String semiReplacement = null;
+        String nameReplacement = null;
+        String pkgStatementReplacement = null;
+        
+        // Figure out if we need to change anything, and if so, what:
+        if (packageName.length() == 0) {
+            if (info.hasPackageStatement()) {
+                // we must delete all parts of the "package" statement
+                semiReplacement = "";
+                nameReplacement = "";
+                pkgStatementReplacement = "";
+            }
+            else {
+                // if we have no package statement we do not need
+                // to do anything to turn it into an anonymous package
+                return;
+            }
+        }
+        else {
+            if (info.hasPackageStatement()) {
+                // it is trivial to make the package name the same
+                if (info.getPackage().equals(packageName)) {
+                    return;
+                }
+                // we must change just the package name
+                nameReplacement = packageName;
+            }
+            else {
+                // we must insert all the "package" statement
+                semiReplacement = ";\n\n";
+                nameReplacement = packageName;
+                pkgStatementReplacement = "package ";
+            }
+        }
+
+        // Change the relevant parts of the file
+        FileEditor fed = new FileEditor(getSourceFile());
+
+        if (semiReplacement != null) {
+            Selection selSemi = info.getPackageSemiSelection();
+            fed.replaceSelection(selSemi, semiReplacement);
+        }
+        
+        if (nameReplacement != null) {
+            Selection selName = info.getPackageNameSelection();
+            fed.replaceSelection(selName, nameReplacement);
+        }
+
+        if (pkgStatementReplacement != null) {
+            Selection selStatement = info.getPackageStatementSelection();
+            fed.replaceSelection(selStatement, pkgStatementReplacement);
+        }
+
+        // save changes back to disk
+        fed.save();
+    }
+
+    /**
+     * Analyse the source code, and save retrieved information.
+     * This includes comments and parameter names for methods/constructors,
+     * class name, type parameters, etc.
+     * <p>
+     * Also causes the class role (normal class, unit test, etc) to be
+     * guessed based on the source.
+     */
+    public ClassInfo analyseSource()
+    {
+        if (analysing) {
+            return null;
+        }
+
+        analysing = true;
+
+        ClassInfo info = sourceInfo.getInfo(getSourceFile(), getPackage());
+
+        // info will be null if the source was unparseable
+        if (info != null) {
+            // the following may update the package display but it
+            // will not modify the classes source code
+            determineRole(null);
+            setTypeParameters(info);
+            analyseDependencies(info);
+        }
+
+        // getPackage().repaint();
+
+        analysing = false;
+        return info;
+    }
+    
+    /**
+     * Change file name and package to match that found in the source file.
+     * @param info  The information from source analysis
+     */
+    private void updateTargetFile(ClassInfo info)
+    {
+        if (analyseClassName(info)) {
+            if (nameEqualsIgnoreCase(info.getName())) {
+                // this means file has same name but different case
+                // to trick Windows OS to do a name change we need to
+                // rename to temp name and then rename to desired name
+                doClassNameChange(info.getName() + TEMP_FILE_EXTENSION);
+            }
+            doClassNameChange(info.getName());
+        }
+        if (analysePackageName(info)) {
+            doPackageNameChange(info.getPackage());
+        }
+    }
+
+    /**
+     * Sets the typeParameters attribute of the ClassTarget object
+     * 
+     * @param info The new typeParameters value
+     */
+    public void setTypeParameters(ClassInfo info)
+    {
+        String newTypeParameters = "";
+        if (info.hasTypeParameter()) {
+            Iterator<String> i = info.getTypeParameterTexts().iterator();
+            newTypeParameters = "<" + i.next();
+           
+            while (i.hasNext()) {
+                newTypeParameters += "," + i.next();
+            }
+            newTypeParameters += ">";
+        }
+        if (!newTypeParameters.equals(typeParameters)) {
+            typeParameters = newTypeParameters;
+            updateSize();
+        }
+    }
+
+    /**
+     * Analyses class name of Classtarget with that of parsed src file. Aim is
+     * to detect any textual changes of class name and modify resources to suit
+     * 
+     * 
+     * @param info contains parsed class information
+     * @return true if class name is different
+     */
+    public boolean analyseClassName(ClassInfo info)
+    {
+        String newName = info.getName();
+
+        if ((newName == null) || (newName.length() == 0)) {
+            return false;
+        }
+
+        return (!getBaseName().equals(newName));
+    }
+
+    /**
+     * Check whether the package name has been changed by comparing the package
+     * name in the information from the parser with the current package name
+     */
+    public boolean analysePackageName(ClassInfo info)
+    {
+        String newName = info.getPackage();
+
+        return (!getPackage().getQualifiedName().equals(newName));
+    }
+
+    /**
+     * Analyse the current dependencies in the source code and update the
+     * dependencies in the graphical display accordingly.
+     */
+    public void analyseDependencies(ClassInfo info)
+    {
+        // currently we don't remove uses dependencies, but just warn
+
+        //removeAllOutDependencies();
+        removeInheritDependencies();
+        unflagAllOutDependencies();
+
+        String pkgPrefix = getPackage().getQualifiedName();
+        pkgPrefix = (pkgPrefix.length() == 0) ? pkgPrefix : pkgPrefix + ".";
+        
+        // handle superclass dependency
+        if (info.getSuperclass() != null) {
+            setSuperClass(info.getSuperclass());
+        }
+
+        // handle implemented interfaces
+        List<String> vect = info.getImplements();
+        for (Iterator<String> it = vect.iterator(); it.hasNext();) {
+            String name = it.next();
+            addInterface(name);
+        }
+
+        // handle used classes
+        vect = info.getUsed();
+        for (Iterator<String> it = vect.iterator(); it.hasNext();) {
+            String name = it.next();
+            DependentTarget used = getPackage().getDependentTarget(name);
+            if (used != null) {
+                if (used.getAssociation() == this || this.getAssociation() == used) {
+                    continue;
+                }
+
+                getPackage().addDependency(new UsesDependency(getPackage(), this, used), true);
+            }
+        }
+
+        // check for inconsistent use dependencies
+        for (Iterator<UsesDependency> it = usesDependencies(); it.hasNext();) {
+            UsesDependency usesDep = ((UsesDependency) it.next());
+            if (!usesDep.isFlagged()) {
+                getPackage().setStatus(usesArrowMsg + usesDep);
+            }
+        }
+    }
+
+    /**
+     * Analyse the current dependencies in the compiled class and update the
+     * dependencies in the graphical display accordingly.
+     */
+    public void analyseDependencies(Class<?> cl)
+    {
+        if (cl != null) {
+            removeInheritDependencies();
+
+            Class<?> superClass = cl.getSuperclass();
+            if (superClass != null) {
+                setSuperClass(superClass.getName());
+            }
+
+            Class<?> [] interfaces = cl.getInterfaces();
+            for (int i = 0; i < interfaces.length; i++) {
+                addInterface(interfaces[i].getName());
+            }
+        }
+    }
+    
+    
+    /**
+     * Set the superclass. This adds an extends dependency to the appropriate class.
+     * The old extends dependency (if any) must be removed separately.
+     * 
+     * @param superName  the fully-qualified name of the superclass
+     */
+    private void setSuperClass(String superName)
+    {
+        String pkgPrefix = getPackage().getQualifiedName();
+        if (superName.startsWith(pkgPrefix)) {
+            // Must account for the final "." in the fully qualified name, if the package is
+            // not the default package:
+            int prefixLen = pkgPrefix.length();
+            prefixLen = prefixLen == 0 ? 0 : prefixLen + 1;
+            
+            superName = superName.substring(prefixLen);
+            DependentTarget superclass = getPackage().getDependentTarget(superName);
+            if (superclass != null) {
+                getPackage().addDependency(new ExtendsDependency(getPackage(), this, superclass), false);
+                if (superclass.getState() != S_NORMAL) {
+                    setState(S_INVALID);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Add an interface. This adds an implements dependency to the appropriate interface.
+     */
+    private void addInterface(String interfaceName)
+    {
+        String pkgPrefix = getPackage().getQualifiedName();
+        if (interfaceName.startsWith(pkgPrefix)) {
+            int dotlen = pkgPrefix.length();
+            // If not the default package, we must account for the extra '.'
+            dotlen = (dotlen == 0) ? 0 : (dotlen + 1);
+            interfaceName = interfaceName.substring(dotlen);
+            DependentTarget interfce = getPackage().getDependentTarget(interfaceName);
+
+            if (interfce != null) {
+                getPackage().addDependency(new ImplementsDependency(getPackage(), this, interfce), false);
+                if (interfce.getState() != S_NORMAL) {
+                    setState(S_INVALID);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Notification that the class represented by this class target has changed name.
+     */
+    private boolean doClassNameChange(String newName)
+    {
+        //need to check that class does not already exist
+        if (getPackage().getTarget(newName) != null) {
+            getPackage().showError("duplicate-name");
+            return false;
+        }
+
+        File newSourceFile = new File(getPackage().getPath(), newName + ".java");
+        File oldSourceFile = getSourceFile();
+        
+        try {
+            FileUtility.copyFile(oldSourceFile, newSourceFile);
+            
+            getPackage().updateTargetIdentifier(this, getIdentifierName(), newName);
+            
+            String filename = newSourceFile.getAbsolutePath();
+            String docFilename = getPackage().getProject().getDocumentationFile(filename);
+            getEditor().changeName(newName, filename, docFilename);
+
+            oldSourceFile.delete();
+            getClassFile().delete();
+            getContextFile().delete();
+            getDocumentationFile().delete();
+
+            // this is extremely dangerous code here.. must track all
+            // variables which are set when ClassTarget is first
+            // constructed and fix them up for new class name
+            String oldName = getIdentifierName();
+            setIdentifierName(newName);
+            setDisplayName(newName);
+            updateSize();
+            
+            // Update the BClass object
+            BClass bClass = getBClass();
+            ExtensionBridge.ChangeBClassName(bClass, getQualifiedName());
+            
+            // Update the BClassTarget object
+            BClassTarget bClassTarget = getBClassTarget();
+            ExtensionBridge.changeBClassTargetName(bClassTarget, getQualifiedName());
+            
+            // Update all BDependency objects related to this target
+            for (Iterator<? extends Dependency> iterator = dependencies(); iterator.hasNext();) {
+                Dependency outgoingDependency = iterator.next();
+                BDependency bDependency = outgoingDependency.getBDependency();
+                ExtensionBridge.changeBDependencyOriginName(bDependency, getQualifiedName());
+            }
+            
+            for (Iterator<? extends Dependency> iterator = dependents(); iterator.hasNext();) {
+                Dependency incomingDependency = iterator.next();
+                BDependency bDependency = incomingDependency.getBDependency();
+                ExtensionBridge.changeBDependencyTargetName(bDependency, getQualifiedName());
+            }
+            
+            // Inform all listeners about the name change
+            ClassEvent event = new ClassEvent(ClassEvent.CHANGED_NAME, getPackage(), getBClass(), oldName);
+            ExtensionsManager.getInstance().delegateEvent(event);
+
+            return true;
+        }
+        catch (IOException ioe) {
+            return false;
+        }
+    }
+
+    /**
+     * Checks for ClassTarget name equality if case is ignored.
+     * 
+     * 
+     * @param newName
+     * @return true if name is equal ignoring case.
+     */
+    private boolean nameEqualsIgnoreCase(String newName)
+    {
+        return (getBaseName().equalsIgnoreCase(newName));
+    }
+
+    /**
+     * Change the package of a class target to something else.
+     * 
+     * 
+     * @param newName the new fully qualified package name
+     */
+    private void doPackageNameChange(String newName)
+    {
+        Project proj = getPackage().getProject();
+
+        Package dstPkg = proj.getPackage(newName);
+
+        if (dstPkg == null) {
+            DialogManager.showError(null, "package-name-invalid");
+        }
+        else {
+            // fix for bug #382. Potentially could clash with a package
+            // in the destination package with the same name
+            if (dstPkg.getTarget(getBaseName()) != null) {
+                DialogManager.showError(null, "package-name-clash");
+                // fall through to enforcePackage, below.
+            }
+            else if (DialogManager.askQuestion(null, "package-name-changed") == 0) {
+                dstPkg.importFile(getSourceFile());
+                prepareForRemoval();
+                getPackage().removeTarget(this);
+                close();
+                return;
+            }
+        }
+
+        // all non working paths lead here.. lets fix the package line
+        // up so it is back to what we expect
+        try {
+            enforcePackage(getPackage().getQualifiedName());
+            getEditor().reloadFile();
+        }
+        catch (IOException ioe) {}
+    }
+
+    /**
+     * Resizes the class so the entire classname + type parameter are visible
+     *  
+     */
+    private void updateSize()
+    {
+        int width = calculateWidth(getDisplayName());
+        setSize(width, getHeight());
+        repaint();
+    }
+
+    /**
+     * Construct a popup menu for the class target, including caching of
+     * results.
+     */
+    protected JPopupMenu menu = null;
+    boolean compiledMenu = false;
+
+    /**
+     * Post the context menu for this target.
+     * 
+     * @param x  the x coordinate for the menu, relative to graph editor
+     * @param y  the y coordinate for the menu, relative to graph editor
+     */
+    @Override
+    public void popupMenu(int x, int y, GraphEditor graphEditor)
+    {
+        Class<?> cl = null;
+
+        if (state == S_NORMAL) {
+            // handle error causes when loading classes which are compiled
+            // but not loadable in the current VM. (Eg if they were compiled
+            // for a later VM).
+            // we detect the error, remove the class file, and invalidate
+            // to allow them to be recompiled
+            cl = getPackage().loadClass(getQualifiedName());
+            if (cl == null) {
+                // trouble loading the class
+                // remove the class file and invalidate the target
+                if (hasSourceCode()) {
+                    getClassFile().delete();
+                    invalidate();
+                }
+            }
+        }
+
+        // check that the class loading hasn't changed out state
+        if (state == S_NORMAL) {
+            menu = createMenu(cl);
+            // editor.add(menu);
+        }
+        else {
+            menu = createMenu(null);
+            // editor.add(menu);
+        }
+
+        if (menu != null) {
+            menu.show(graphEditor, x, y);
+        }
+    }
+
+    /**
+     * Creates a popup menu for this class target.
+     * 
+     * @param cl class object associated with this class target
+     * @return the created popup menu object
+     */
+    protected JPopupMenu createMenu(Class<?> cl)
+    {
+        JPopupMenu menu = new JPopupMenu(getBaseName() + " operations");
+
+        // call on role object to add any options needed at top
+        role.createRoleMenu(menu, this, cl, state);
+
+        if (cl != null) {
+            if (role.createClassConstructorMenu(menu, this, cl)) {
+                menu.addSeparator();
+            }
+        }
+
+        if (cl != null) {
+            if (role.createClassStaticMenu(menu, this, cl)) {
+                menu.addSeparator();
+            }
+        }
+        boolean sourceOrDocExists = hasSourceCode() || getDocumentationFile().exists();
+        role.addMenuItem(menu, new EditAction(), sourceOrDocExists);
+        role.addMenuItem(menu, new CompileAction(), hasSourceCode());
+        role.addMenuItem(menu, new InspectAction(), cl != null);
+        role.addMenuItem(menu, new RemoveAction(), true);
+
+        // call on role object to add any options needed at bottom
+        role.createRoleMenuEnd(menu, this, state);
+
+        MenuManager menuManager = new MenuManager(menu);
+        menuManager.setAttachedObject(new ClassMenuObject(this));
+        menuManager.addExtensionMenu(getPackage().getProject());
+
+        return menu;
+    }
+
+    /**
+     * Action which creates a test
+     */
+    public class CreateTestAction extends AbstractAction
+    {
+        /**
+         * Constructor for the CreateTestAction object
+         */
+        public CreateTestAction()
+        {
+            putValue(NAME, createTestStr);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+            PkgMgrFrame pmf = PkgMgrFrame.findFrame(getPackage());
+
+            if (pmf != null) {
+                String testClassName = getIdentifierName() + "Test";
+                pmf.createNewClass(testClassName, "unittest", true);
+                // we want to check that the previous called actually
+                // created a unit test class as a name clash with an existing
+                // class would not. This prevents a non unit test becoming
+                // associated with a class unintentionally
+                Target target = getPackage().getTarget(testClassName);
+                ClassTarget ct = null;
+                if (target instanceof ClassTarget) {
+                    ct = (ClassTarget) target;
+                    if (ct != null && ct.isUnitTest()) {
+                        setAssociation((DependentTarget) getPackage().getTarget(getIdentifierName() + "Test"));
+                    }
+                }
+                updateAssociatePosition();
+                getPackage().getEditor().revalidate();
+                getPackage().getEditor().repaint();
+
+            }
+        }
+    }
+
+    /**
+     * Action to open the editor for a classtarget
+     */
+    private class EditAction extends AbstractAction
+    {
+        public EditAction()
+        {
+            putValue(NAME, editStr);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+            open();
+        }
+    }
+
+    /**
+     * Action to compile a classtarget
+     */
+    private class CompileAction extends AbstractAction
+    {
+        public CompileAction()
+        {
+            putValue(NAME, compileStr);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+            getPackage().compile(ClassTarget.this);
+        }
+    }
+
+    /**
+     * Action to remove a classtarget from its package
+     */
+    private class RemoveAction extends AbstractAction
+    {
+        public RemoveAction()
+        {
+            putValue(NAME, removeStr);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+            PkgMgrFrame pmf = PkgMgrFrame.findFrame(getPackage());
+            if (pmf.askRemoveClass()) {
+                getPackage().getEditor().raiseRemoveTargetEvent(ClassTarget.this);
+            }
+        }
+    }
+
+    /**
+     * Action to inspect the static members of a class
+     */
+    private class InspectAction extends AbstractAction
+    {
+        public InspectAction()
+        {
+            putValue(NAME, inspectStr);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+            if (checkDebuggerState()) {
+                inspect();
+            }
+        }
+    }
+
+    /**
+     * Process a double click on this target. That is: open its editor.
+     * 
+     * @param evt Description of the Parameter
+     */
+    @Override
+    public void doubleClick(MouseEvent evt)
+    {
+        open();
+    }
+
+    /**
+     * @return Returns the ghostX.
+     */
+    @Override
+    public int getGhostX()
+    {
+        return ghostX;
+    }
+
+    /**
+     * @return Returns the ghostX.
+     */
+    @Override
+    public int getGhostY()
+    {
+        return ghostY;
+    }
+
+    /**
+     * @return Returns the ghostX.
+     */
+    public int getGhostWidth()
+    {
+        return ghostWidth;
+    }
+
+    /**
+     * @return Returns the ghostX.
+     */
+    public int getGhostHeight()
+    {
+        return ghostHeight;
+    }
+
+    /**
+     * Set the position of the ghost image given a delta to the real size.
+     * 
+     * @param deltaX The new ghostPosition value
+     * @param deltaY The new ghostPosition value
+     */
+    @Override
+    public void setGhostPosition(int deltaX, int deltaY)
+    {
+        this.ghostX = getX() + deltaX;
+        this.ghostY = getY() + deltaY;
+    }
+
+    /**
+     * Set the size of the ghost image given a delta to the real size.
+     * 
+     * @param deltaX The new ghostSize value
+     * @param deltaY The new ghostSize value
+     */
+    @Override
+    public void setGhostSize(int deltaX, int deltaY)
+    {
+        ghostWidth = Math.max(getWidth() + deltaX, MIN_WIDTH);
+        ghostHeight = Math.max(getHeight() + deltaY, MIN_HEIGHT);
+    }
+
+    /**
+     * Set the target's position to its ghost position.
+     */
+    @Override
+    public void setPositionToGhost()
+    {
+        super.setPos(ghostX, ghostY);
+        setSize(ghostWidth, ghostHeight);
+        isDragging = false;
+    }
+
+    /**
+     * Ask whether we are currently dragging.
+     * 
+     * @return The dragging value
+     */
+    @Override
+    public boolean isDragging()
+    {
+        return isDragging;
+    }
+
+    /**
+     * Set whether or not we are currently dragging this class (either moving or
+     * resizing).
+     * 
+     * @param isDragging The new dragging value
+     */
+    @Override
+    public void setDragging(boolean isDragging)
+    {
+        this.isDragging = isDragging;
+    }
+
+    /**
+     * Set the position of this target.
+     * 
+     * @param x The new pos value
+     * @param y The new pos value
+     */
+    @Override
+    public void setPos(int x, int y)
+    {
+        super.setPos(x, y);
+        setGhostPosition(0, 0);
+    }
+
+    /**
+     * Set the size of this target.
+     * 
+     * @param width The new size value
+     * @param height The new size value
+     */
+    @Override
+    public void setSize(int width, int height)
+    {
+        super.setSize(Math.max(width, MIN_WIDTH), Math.max(height, MIN_HEIGHT));
+        setGhostSize(0, 0);
+    }
+    
+    @Override
+    public void setVisible(boolean visible)
+    {
+        if (visible != isVisible()) {
+            super.setVisible(visible);
+            
+            // Inform all listeners about the visibility change
+            ClassTargetEvent event = new ClassTargetEvent(this, getPackage(), visible);
+            ExtensionsManager.getInstance().delegateEvent(event);
+        }
+    }
+
+    /**
+     * Prepares this ClassTarget for removal from a Package. It removes
+     * dependency arrows and calls prepareFilesForRemoval() to remove applicable
+     * files.
+     */
+    private void prepareForRemoval()
+    {
+        if (editor != null) {
+            editor.close();
+        }
+
+        // if this target is the assocation for another Target, remove
+        // the association
+        Iterator<? extends Vertex> it = getPackage().getVertices();
+        while (it.hasNext()) {
+            Object o = it.next();
+            if (o instanceof DependentTarget) {
+                DependentTarget d = (DependentTarget) o;
+                if (this.equals(d.getAssociation())) {
+                    d.setAssociation(null);
+                }
+            }
+        }
+
+        // flag dependent Targets as invalid
+        invalidate();
+
+        removeAllInDependencies();
+        removeAllOutDependencies();
+
+        // remove associated files (.class, .java and .ctxt)
+        prepareFilesForRemoval();
+    }
+
+    /**
+     * Removes applicable files (.class, .java and .ctxt) prior to this
+     * ClassTarget being removed from a Package.
+     */
+    public void prepareFilesForRemoval()
+    {
+        if (getSourceFile().exists()) {
+            // remove all inner class files starting with the same name as
+            // sourceFile$
+            File[] files = getPackage().getPath().listFiles(new InnerClassFileFilter());
+
+            if (files != null) {
+                for (int i = 0; i < files.length; i++) {
+                    files[i].delete();
+                }
+            }
+        }
+
+        List<File> allFiles = getRole().getAllFiles(this);
+        for(Iterator<File> i = allFiles.iterator(); i.hasNext(); ) {
+            i.next().delete();
+        }
+    }
+
+    @Override
+    public void generateDoc()
+    {
+        getPackage().generateDocumentation(this);
+    }
+
+    @Override
+    public void remove()
+    {
+        prepareForRemoval();
+        getPackage().removeTarget(this);
+    }
+
+    @Override
+    public boolean isMoveable()
+    {
+        return isMoveable;
+    }
+
+    /**
+     * Set whether this ClassTarget can be moved by the user (dragged around).
+     * This is set false for unit tests which are associated with another class.
+     * 
+     * @see bluej.graph.Moveable#setIsMoveable(boolean)
+     */
+    @Override
+    public void setIsMoveable(boolean isMoveable)
+    {
+        this.isMoveable = isMoveable;
+    }
+    
+    /**
+     * perform interactive method call
+     */
+    @Override
+    public void executeMethod(MethodView mv)
+    {
+        getPackage().getEditor().raiseMethodCallEvent(this, mv);
+    }
+    
+    /**
+     * interactive constructor call
+     */
+    @Override
+    public void callConstructor(ConstructorView cv)
+    {
+        getPackage().getEditor().raiseMethodCallEvent(this, cv);
+    }
+    
+    /**
+     * Method to check state of debug VM (currently running may cause problems)
+     * and then give options accordingly. 
+     * Returns a value from user about how to continue i.e should the original requested be executed.
+     * 
+     * @return Whether the original request should be executed (dependent on how the user wants to proceed)
+     */
+    private boolean checkDebuggerState()
+    {
+        return PkgMgrFrame.createFrame(getPackage()).checkDebuggerState();
+    }
+
+    /**
+     * Returns the naviview expanded value from the properties file
+     * @return 
+     */
+    public boolean isNaviviewExpanded() 
+    {
+        return isNaviviewExpanded;
+    }
+
+    /**
+     * Sets the naviview expanded value from the properties file to this local variable
+     * @param isNaviviewExpanded
+     */
+    public void setNaviviewExpanded(boolean isNaviviewExpanded) 
+    {
+        this.isNaviviewExpanded=isNaviviewExpanded;  
+    }
+
+    /**
+     * Retrieves a property from the editor
+     */
+    @Override
+    public String getProperty(String key) 
+    {
+        return (String)properties.get(key);
+    }
+
+    /**
+     * Sets a property for the editor
+     */
+    @Override
+    public void setProperty(String key, String value) 
+    {
+        properties.put(key, value);
+    }
+    
+    @Override
+    public String getTooltipText()
+    {
+        if (!getSourceInfo().isValid()) {
+            return Config.getString("graph.tooltip.classBroken");
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/DependentTarget.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/DependentTarget.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa71be32a56ed24247c8793d7af3e6eea7e29caf
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/DependentTarget.java
@@ -0,0 +1,501 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+import bluej.graph.Moveable;
+import bluej.pkgmgr.*;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.dependency.*;
+import bluej.utility.MultiIterator;
+
+/**
+ * A target that has relationships to other targets
+ *
+ * @author   Michael Cahill
+ * @author   Michael Kolling
+ */
+public abstract class DependentTarget extends EditableTarget
+{
+    /** States * */
+    public static final int S_NORMAL = 0;
+    public static final int S_INVALID = 1;
+    public static final int S_COMPILING = 2;
+
+    protected int state = S_INVALID;
+
+    private List<UsesDependency> inUses;
+    private List<UsesDependency> outUses;
+    private List<Dependency> parents;
+    private List<Dependency> children;
+
+    protected DependentTarget assoc;
+
+    /**
+     * Create a new target belonging to the specified package.
+     */
+    public DependentTarget(Package pkg, String identifierName)
+    {
+        super(pkg, identifierName);
+
+        inUses = new ArrayList<UsesDependency>();
+        outUses = new ArrayList<UsesDependency>();
+        parents = new ArrayList<Dependency>();
+        children = new ArrayList<Dependency>();
+
+        assoc = null;
+    }
+    
+    @Override
+    public void setPos(int x, int y)
+    {
+        super.setPos(x,y);
+        recalcDependentPositions();
+    }
+
+    @Override
+    public void setSize(int width, int height)
+    {
+        super.setSize(width, height);
+        recalcDependentPositions();
+    }
+
+    /**
+     * Save association information about this class target
+     * @param props the properties object to save to
+     * @param prefix an internal name used for this target to identify
+     */
+    @Override
+    public void save(Properties props, String prefix)
+    {
+        super.save(props, prefix);
+
+        if (getAssociation() != null) {
+            String assocName = getAssociation().getIdentifierName(); 
+            props.put(prefix + ".association", assocName);
+        }
+    }
+
+    public void setAssociation(DependentTarget t)
+    {
+        assoc = t;
+        //assoiated classes are not allowed to move on their own
+        if (assoc instanceof Moveable){
+            ((Moveable)assoc).setIsMoveable(false);
+        }
+    }
+
+    public DependentTarget getAssociation()
+    {
+        return assoc;
+    }
+
+    public void addDependencyOut(Dependency d, boolean recalc)
+    {
+        if(d instanceof UsesDependency) {
+            outUses.add((UsesDependency) d);
+            if(recalc)
+                recalcOutUses();
+        }
+        else if((d instanceof ExtendsDependency)
+                || (d instanceof ImplementsDependency)) {
+            parents.add(d);
+        }
+
+        if(recalc) {
+            setState(S_INVALID);
+        }
+    }
+
+    public void addDependencyIn(Dependency d, boolean recalc)
+    {
+        if(d instanceof UsesDependency) {
+            inUses.add((UsesDependency) d);
+            if(recalc)
+                recalcInUses();
+        }
+        else if((d instanceof ExtendsDependency)
+                || (d instanceof ImplementsDependency)) {
+            children.add(d);
+        }
+    }
+
+    public void removeDependencyOut(Dependency d, boolean recalc)
+    {
+        if(d instanceof UsesDependency) {
+            outUses.remove(d);
+            if(recalc)
+                recalcOutUses();
+        }
+        else if((d instanceof ExtendsDependency)
+                || (d instanceof ImplementsDependency)) {
+            parents.remove(d);
+        }
+        
+        if(recalc)
+            setState(S_INVALID);
+    }
+
+    public void removeDependencyIn(Dependency d, boolean recalc)
+    {
+        if(d instanceof UsesDependency) {
+            inUses.remove(d);
+            if(recalc) {
+                recalcInUses();
+            }
+        }
+        else if((d instanceof ExtendsDependency)
+                || (d instanceof ImplementsDependency)) {
+            children.remove(d);
+        }
+    }
+
+    public Iterator<? extends Dependency> dependencies()
+    {
+        List<Iterator<? extends Dependency>> v = new ArrayList<Iterator<? extends Dependency>>(2);
+        v.add(parents.iterator());
+        v.add(outUses.iterator());
+        return new MultiIterator<Dependency>(v);
+    }
+
+    public Iterator<? extends Dependency> dependents()
+    {
+        List<Iterator<? extends Dependency>> v = new ArrayList<Iterator<? extends Dependency>>(2);
+        v.add(children.iterator());
+        v.add(inUses.iterator());
+        return new MultiIterator<Dependency>(v);
+    }
+    
+    /**
+     * Get the dependencies between this target and its parent(s).
+     * The returned list should not be modified and may be a view or a copy.
+     */
+    public List<Dependency> getParents()
+    {
+        return Collections.unmodifiableList(parents);
+    }
+    
+    /**
+     * Get the dependencies between this target and its children.
+     * 
+     * @return
+     */
+    public List<Dependency> getChildren()
+    {
+        return Collections.unmodifiableList(children);
+    }
+    
+    public List<Dependency> dependentsAsList()
+    {
+        List<Dependency> list = new LinkedList<Dependency>();
+        list.addAll(inUses);
+        list.addAll(outUses);
+        list.addAll(children);
+        list.addAll(parents);
+        return list;
+    }
+
+    public Iterator<UsesDependency> usesDependencies()
+    {
+        return Collections.unmodifiableList(outUses).iterator();
+    }
+    
+    /**
+     *  Remove all outgoing dependencies. Also updates the package. (Don't
+     *  call from package remove method - this will cause infinite recursion.)
+     */
+    protected void removeAllOutDependencies()
+    {
+        // While removing the dependencies the dependency list must be
+        // copied since the original is modified during this operation.
+        // Enumerations over the original would go wrong.
+
+        // delete outgoing uses dependencies
+        if(!outUses.isEmpty()) {
+            Dependency[] outUsesArray = new Dependency[outUses.size()];
+            outUses.toArray(outUsesArray);
+            for(int i = 0; i < outUsesArray.length ; i++) {
+                getPackage().removeDependency(outUsesArray[i], false);
+            }
+        }
+
+        removeInheritDependencies();
+    }
+
+    /**
+     *  Remove inheritance dependencies.
+     */
+    protected void removeInheritDependencies()
+    {
+        // While removing the dependencies the dependency list must be
+        // copied since the original is modified during this operation.
+        // Enumerations over the original would go wrong.
+
+        if(!parents.isEmpty()) {
+            Dependency[] parentsArray = new Dependency[ parents.size() ];
+            parents.toArray(parentsArray);
+            for(int i = 0; i < parentsArray.length ; i++)
+                getPackage().removeDependency(parentsArray[i], false);
+        }
+    }
+
+    /**
+     *  Remove all incoming dependencies. Also updates the package. (Don't
+     *  call from package remove method - this will cause infinite recursion.)
+     */
+    protected void removeAllInDependencies()
+    {
+        // While removing the dependencies the dependency list must be
+        // copied since the original is modified during this operation.
+        // Enumerations over the original would go wrong.
+
+        // delete incoming uses dependencies
+        if(!inUses.isEmpty()) {
+            Dependency[] inUsesArray = new Dependency[ inUses.size() ];
+            inUses.toArray(inUsesArray);
+            for(int i = 0; i < inUsesArray.length ; i++)
+                getPackage().removeDependency(inUsesArray[i], false);
+        }
+
+        // delete dependencies to child classes
+        if(!children.isEmpty()) {
+            Dependency[] childrenArray = new Dependency[ children.size() ];
+            children.toArray(childrenArray);
+            for(int i = 0; i < childrenArray.length ; i++)
+                getPackage().removeDependency(childrenArray[i], false);
+        }
+    }
+
+    public void recalcOutUses()
+    {
+        // Determine the visible outgoing uses dependencies
+        List<UsesDependency> visibleOutUses = getVisibleUsesDependencies(outUses);
+
+        // Order the arrows by quadrant and then appropriate coordinate
+        Collections.sort(visibleOutUses, new LayoutComparer(this, false));
+
+        // Count the number of arrows into each quadrant
+        int cy = getY() + getHeight() / 2;
+        int n_top = 0, n_bottom = 0;
+        for(int i = visibleOutUses.size() - 1; i >= 0; i--) {
+            Target to = ((Dependency) visibleOutUses.get(i)).getTo();
+            int to_cy = to.getY() + to.getHeight() / 2;
+            if(to_cy < cy)
+                ++n_top;
+            else
+                ++n_bottom;
+        }
+
+        // Assign source coordinates to each arrow
+        int top_left = getX() + (getWidth() - (n_top - 1) * ARR_HORIZ_DIST) / 2;
+        int bottom_left = getX() + (getWidth() - (n_bottom - 1) * ARR_HORIZ_DIST) / 2;
+        for(int i = 0; i < n_top + n_bottom; i++) {
+            UsesDependency d = (UsesDependency) visibleOutUses.get(i);
+            int to_cy = d.getTo().getY() + d.getTo().getHeight() / 2;
+            if(to_cy < cy) {
+                d.setSourceCoords(top_left, getY() - 4, true);
+                top_left += ARR_HORIZ_DIST;
+            }
+            else {
+                d.setSourceCoords(bottom_left, getY() + getHeight() + 4, false);
+                bottom_left += ARR_HORIZ_DIST;
+            }
+        }
+    }
+
+    /**
+     * Re-layout arrows into this target
+     */
+    public void recalcInUses()
+    {
+        // Determine the visible incoming uses dependencies
+        List<UsesDependency> visibleInUses = getVisibleUsesDependencies(inUses);
+
+        // Order the arrows by quadrant and then appropriate coordinate
+        Collections.sort(visibleInUses, new LayoutComparer(this, true));
+
+        // Count the number of arrows into each quadrant
+        int cx = getX() + getWidth() / 2;
+        int n_left = 0, n_right = 0;
+        for(int i = visibleInUses.size() - 1; i >= 0; i--)
+        {
+            Target from = ((Dependency) visibleInUses.get(i)).getFrom();
+            int from_cx = from.getX() + from.getWidth() / 2;
+            if(from_cx < cx)
+                ++n_left;
+            else
+                ++n_right;
+        }
+
+        // Assign source coordinates to each arrow
+        int left_top = getY() + (getHeight() - (n_left - 1) * ARR_VERT_DIST) / 2;
+        int right_top = getY() + (getHeight() - (n_right - 1) * ARR_VERT_DIST) / 2;
+        for(int i = 0; i < n_left + n_right; i++)
+        {
+            UsesDependency d = (UsesDependency) visibleInUses.get(i);
+            int from_cx = d.getFrom().getX() + d.getFrom().getWidth() / 2;
+            if(from_cx < cx)
+            {
+                d.setDestCoords(getX() - 4, left_top, true);
+                left_top += ARR_VERT_DIST;
+            }
+            else
+            {
+                d.setDestCoords(getX() + getWidth() + 4, right_top, false);
+                right_top += ARR_VERT_DIST;
+            }
+        }
+    }
+
+    /**
+     * Returns from the specified {@link List} all uses dependencies which are
+     * currently visible.
+     * 
+     * @param usesDependencies
+     *            A {@link List} of uses dependencies.
+     * @return A {@link List} containing all visible uses dependencies from the
+     *         input list.
+     */
+    private List<UsesDependency> getVisibleUsesDependencies(List<UsesDependency> usesDependencies)
+    {
+        List<UsesDependency> result = new ArrayList<UsesDependency>();
+
+        for (UsesDependency incomingUsesDependency : usesDependencies) {
+            if (incomingUsesDependency.isVisible()) {
+                result.add(incomingUsesDependency);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     *  Clear the flag in a outgoing uses dependencies
+     */
+    protected void unflagAllOutDependencies()
+    {
+        for(int i = 0; i < outUses.size(); i++)
+            ((UsesDependency)outUses.get(i)).setFlag(false);
+    }
+
+    public Point getAttachment(double angle)
+    {
+        double radius;
+        double sin = Math.sin(angle);
+        double cos = Math.cos(angle);
+        double tan = sin / cos;
+        double m = (double) getHeight() / getWidth();
+
+        if(Math.abs(tan) < m)   // side
+            radius = 0.5 * getWidth() / Math.abs(cos);
+        else    // top
+            radius = 0.5 * getHeight() / Math.abs(sin);
+
+        Point p = new Point(getX() + getWidth() / 2 + (int)(radius * cos),
+                            getY() + getHeight() / 2 - (int)(radius * sin));
+
+        // Correct for shadow
+        if((-m < tan) && (tan < m) && (cos > 0))    // right side
+            p.x += SHAD_SIZE;
+        if((Math.abs(tan) > m) && (sin < 0) && (p.x > getX() + SHAD_SIZE))  // bottom
+            p.y += SHAD_SIZE;
+
+        return p;
+    }
+    
+    
+    /**
+     * The user may have moved or resized the target. If so, recalculate the
+     * dependency arrows associated with this target.
+     * @param editor
+     */
+    public void recalcDependentPositions() 
+    {
+        // Recalculate arrows
+        recalcInUses();
+        recalcOutUses();
+
+        // Recalculate neighbours' arrows
+        for(Iterator<UsesDependency> it = inUses.iterator(); it.hasNext(); ) {
+            Dependency d = it.next();
+            d.getFrom().recalcOutUses();
+        }
+        for(Iterator<UsesDependency> it = outUses.iterator(); it.hasNext(); ) {
+            Dependency d = it.next();
+            d.getTo().recalcInUses();
+        }
+
+        updateAssociatePosition();
+    }
+
+    protected void updateAssociatePosition()
+    {
+        DependentTarget t = getAssociation();
+
+        if (t != null) {
+            //TODO magic numbers. Should also take grid size in to account.
+            t.setPos(getX() + 30, getY() - 30);
+            t. recalcDependentPositions();
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return getDisplayName();
+    }
+    
+    /**
+     * Return the current state of the target (one of S_NORMAL, S_INVALID,
+     * S_COMPILING)
+     */
+    public int getState()
+    {
+        return state;
+    }
+
+    public boolean isInvalidState()
+    {
+        return getState() == S_INVALID;
+    }
+
+    public void setInvalidState()
+    {
+        setState(S_INVALID);
+    }
+    
+    /**
+     * Change the state of this target. The target will be repainted to show the
+     * new state.
+     * 
+     * @param newState The new state value
+     */
+    public void setState(int newState)
+    {
+        state = newState;
+        repaint();
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/EditableTarget.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/EditableTarget.java
new file mode 100644
index 0000000000000000000000000000000000000000..78cc758eac9343df7126ee41db769cd6dab2ba61
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/EditableTarget.java
@@ -0,0 +1,154 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target;
+
+import java.awt.Rectangle;
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+
+import bluej.editor.*;
+import bluej.pkgmgr.Package;
+
+/**
+ * A target in a package that can be edited as text
+ *
+ * @author  Michael Cahill
+ */
+public abstract class EditableTarget extends Target
+    implements EditorWatcher
+{
+    protected Editor editor;
+    protected Rectangle editorBounds;
+
+    protected EditableTarget(Package pkg, String name)
+    {
+        super(pkg, name);
+    }
+
+    /**
+     * @return the name of the (text) file this target corresponds to.
+     */
+    protected abstract File getSourceFile();
+
+    /**
+     * @return the editor object associated with this target
+     */
+    public abstract Editor getEditor();
+
+    /**
+     * Ensure that the source file of this target is up-to-date (i.e.
+     * that any possible unsaved changes in an open editor window are 
+     * saved).
+     */
+    public void ensureSaved() throws IOException
+    {
+        if(editor != null) {
+            editor.save();
+        }
+    }
+    
+    /**
+     * Called to open the editor for this target
+     */
+    public void open()
+    {
+        Editor editor = getEditor();
+
+        if(editor == null)
+            getPackage().showError("error-open-source");
+        else
+            editor.setVisible(true);
+    }
+
+    /**
+     * Close the editor for this target.
+     */
+    protected void close()
+    {
+        getEditor().close();
+    }
+
+    /**
+     * Return true if this editor has been opened at some point since this project was opened.
+     */
+    public boolean editorOpen()
+    {
+        return (editor!=null);
+    }
+    
+    public void load(Properties props, String prefix) throws NumberFormatException
+    {
+        super.load(props, prefix);
+        if(props.getProperty(prefix + ".editor.x") != null) {
+            editorBounds = new Rectangle(Integer.parseInt(props.getProperty(prefix + ".editor.x")),
+                    Integer.parseInt(props.getProperty(prefix + ".editor.y")), 
+                    Integer.parseInt(props.getProperty(prefix + ".editor.width")),
+                    Integer.parseInt(props.getProperty(prefix + ".editor.height")));
+        }
+    }
+
+    public void save(Properties props, String prefix)
+    {
+        super.save(props, prefix);
+        if (editor != null) {
+            editorBounds = editor.getBounds();            
+        } 
+        if(editorBounds!=null) {
+            props.put(prefix + ".editor.x", String.valueOf((int) editorBounds.getX()));
+            props.put(prefix + ".editor.y", String.valueOf((int) editorBounds.getY()));
+            props.put(prefix + ".editor.width", String.valueOf((int) editorBounds.getWidth()));
+            props.put(prefix + ".editor.height", String.valueOf((int) editorBounds.getHeight()));
+        }
+    }
+    
+    // --- EditorWatcher interface ---
+    // (The EditorWatcher methods are typically redefined in subclasses)
+
+    /*
+     * Called by Editor when a file is changed
+     */
+    public void modificationEvent(Editor editor) {}
+
+    /*
+     * Called by Editor when a file is saved
+     */
+    public void saveEvent(Editor editor) {}
+
+    /*
+     * Called by Editor when a file is closed
+     */
+    public void closeEvent(Editor editor) {}
+
+    /*
+     * Called by Editor when a breakpoint is been set/cleared
+     */
+    public String breakpointToggleEvent(Editor editor, int lineNo, boolean set)
+    { return null; }
+
+    /*
+     * The "compile" function was invoked in the editor
+     */
+    public void compile(Editor editor) {}
+
+    // --- end of EditorWatcher interface ---
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/PackageTarget.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/PackageTarget.java
new file mode 100644
index 0000000000000000000000000000000000000000..a55b1b7a6d8ea70b25f652405264d372dd62eaa5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/PackageTarget.java
@@ -0,0 +1,357 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.lang.reflect.Array;
+import java.util.Properties;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import bluej.Config;
+import bluej.graph.GraphEditor;
+import bluej.graph.Moveable;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.Debug;
+
+/**
+ * A sub package (or parent package)
+ * 
+ * @author Michael Cahill
+ */
+public class PackageTarget extends Target
+    implements Moveable
+{
+    static final int MIN_WIDTH = 60;
+    static final int MIN_HEIGHT = 40;
+
+    private static final int TAB_HEIGHT = 12;
+
+    static String openStr = Config.getString("pkgmgr.packagemenu.open");
+    static String removeStr = Config.getString("pkgmgr.packagemenu.remove");
+
+    static final Color envOpColour = Config.ENV_COLOUR;
+
+    static final BasicStroke normalStroke = new BasicStroke(1);
+    static final BasicStroke selectedStroke = new BasicStroke(3);
+
+    private int ghostX;
+    private int ghostY;
+    private int ghostWidth;
+    private int ghostHeight;
+    private boolean isDragging;
+    private boolean isMoveable = true;
+
+    public PackageTarget(Package pkg, String baseName)
+    {
+        super(pkg, baseName);
+
+        setSize(calculateWidth(baseName), DEF_HEIGHT + TAB_HEIGHT);
+    }
+
+    /**
+     * Return the target's base name (ie the name without the package name). eg.
+     * Target
+     */
+    public String getBaseName()
+    {
+        return getIdentifierName();
+    }
+
+    /**
+     * Return the target's name, including the package name. eg. bluej.pkgmgr
+     */
+    public String getQualifiedName()
+    {
+        return getPackage().getQualifiedName(getBaseName());
+    }
+
+    @Override
+    public void load(Properties props, String prefix)
+        throws NumberFormatException
+    {
+        super.load(props, prefix);
+    }
+
+    @Override
+    public void save(Properties props, String prefix)
+    {
+        super.save(props, prefix);
+
+        props.put(prefix + ".type", "PackageTarget");
+    }
+
+    /**
+     * Deletes applicable files (directory and ALL contentes) prior to this
+     * PackageTarget being removed from a Package.
+     */
+    public void deleteFiles()
+    {
+        deleteDir(new File(getPackage().getPath(), getBaseName()));
+    }
+
+    /**
+     * Delete a directory recursively.
+     * This method will delete all files and subdirectories in any
+     * directory without asking questions. Use with care.
+     *
+     * @param directory   The directory that will be deleted.
+     */
+    private void deleteDir(File directory)
+    {
+        File[] fileList = directory.listFiles();
+
+        // If it is a file or an empty directory, delete
+        if (fileList == null) {
+            try{
+                directory.delete();
+            } catch (SecurityException se){
+                Debug.message("Trouble deleting: "+directory+se);
+            }
+        }
+        else {
+            if (getPackage().getProject().prepareDeleteDir(directory)) {
+                // delete all subdirectories
+                for(int i=0;i<Array.getLength(fileList);i++) {
+                    deleteDir(fileList[i]);
+                }
+
+                // then delete the directory (when it is empty)
+                directory.delete();
+            }
+        }
+    }
+    
+    /**
+     * Called when a package icon in a GraphEditor is double clicked. Creates a
+     * new PkgFrame when a package is drilled down on.
+     */
+    @Override
+    public void doubleClick(MouseEvent evt)
+    {
+        getPackage().getEditor().raiseOpenPackageEvent(this, getPackage().getQualifiedName(getBaseName()));
+    }
+
+    /**
+     * Disply the context menu.
+     */
+    @Override
+    public void popupMenu(int x, int y, GraphEditor graphEditor)
+    {
+        JPopupMenu menu = createMenu();
+        if (menu != null) {
+            menu.show(graphEditor, x, y);
+        }
+    }
+
+    /**
+     * Construct a popup menu which displays all our parent packages.
+     */
+    private JPopupMenu createMenu()
+    {
+        JPopupMenu menu = new JPopupMenu(getBaseName());
+
+        Action openAction = new OpenAction(openStr, this, getPackage().getQualifiedName(getBaseName()));
+        addMenuItem(menu, openAction);
+        
+        Action removeAction = new RemoveAction(removeStr, this);
+        addMenuItem(menu, removeAction);
+
+        return menu;
+    }
+
+    private void addMenuItem(JPopupMenu menu, Action action)
+    {
+        JMenuItem item = menu.add(action);
+        item.setFont(PrefMgr.getPopupMenuFont());
+        item.setForeground(envOpColour);
+    }
+
+    private class OpenAction extends AbstractAction
+    {
+        private Target t;
+        private String pkgName;
+
+        public OpenAction(String menu, Target t, String pkgName)
+        {
+            super(menu);
+            this.t = t;
+            this.pkgName = pkgName;
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+            getPackage().getEditor().raiseOpenPackageEvent(t, pkgName);
+        }
+    }
+
+    private class RemoveAction extends AbstractAction
+    {
+        private Target t;
+
+        public RemoveAction(String menu, Target t)
+        {
+            super(menu);
+            this.t = t;
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+            getPackage().getEditor().raiseRemoveTargetEvent(t);
+        }
+    }
+
+    @Override
+    public void remove()
+    {
+        PkgMgrFrame pmf = PkgMgrFrame.findFrame(getPackage());
+        if (pmf.askRemovePackage(this)) {
+            deleteFiles();
+            getPackage().getProject().removePackage(getQualifiedName());
+            getPackage().removeTarget(this);
+        }
+    }
+
+    /**
+     * Removes the package associated with this target unconditionally.
+     */
+    public void removeImmediate()
+    {
+        deleteFiles();
+        getPackage().removeTarget(this);
+        getPackage().getProject().removePackage(getQualifiedName());
+    }
+
+    @Override
+    public void setSize(int width, int height)
+    {
+        super.setSize(Math.max(width, MIN_WIDTH), Math.max(height, MIN_HEIGHT));
+        setGhostSize(0, 0);
+    }
+
+    @Override
+    public void setPos(int x, int y)
+    {
+        super.setPos(x, y);
+        setGhostPosition(0, 0);
+    }
+
+    /**
+     * @return Returns the ghostX.
+     */
+    public int getGhostX()
+    {
+        return ghostX;
+    }
+
+    /**
+     * @return Returns the ghostX.
+     */
+    public int getGhostY()
+    {
+        return ghostY;
+    }
+
+    /**
+     * @return Returns the ghostX.
+     */
+    public int getGhostWidth()
+    {
+        return ghostWidth;
+    }
+
+    /**
+     * @return Returns the ghostX.
+     */
+    public int getGhostHeight()
+    {
+        return ghostHeight;
+    }
+
+    /**
+     * Set the position of the ghost image given a delta to the real size.
+     */
+    public void setGhostPosition(int deltaX, int deltaY)
+    {
+        this.ghostX = getX() + deltaX;
+        this.ghostY = getY() + deltaY;
+    }
+
+    /**
+     * Set the size of the ghost image given a delta to the real size.
+     */
+    public void setGhostSize(int deltaX, int deltaY)
+    {
+        ghostWidth = Math.max(getWidth() + deltaX, MIN_WIDTH);
+        ghostHeight = Math.max(getHeight() + deltaY, MIN_HEIGHT);
+    }
+
+    /**
+     * Set the target's position to its ghost position.
+     */
+    public void setPositionToGhost()
+    {
+        super.setPos(ghostX, ghostY);
+        setSize(ghostWidth, ghostHeight);
+        isDragging = false;
+    }
+
+    /** 
+     * Ask whether we are currently dragging. 
+     */
+    public boolean isDragging()
+    {
+        return isDragging;
+    }
+
+    /**
+     * Set whether or not we are currently dragging this class
+     * (either moving or resizing).
+     */
+    public void setDragging(boolean isDragging)
+    {
+        this.isDragging = isDragging;
+    }
+
+    @Override
+    public boolean isMoveable()
+    {
+        return isMoveable;
+    }
+
+    @Override
+    public void setIsMoveable(boolean isMoveable)
+    {
+        this.isMoveable = isMoveable;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/ParentPackageTarget.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/ParentPackageTarget.java
new file mode 100644
index 0000000000000000000000000000000000000000..b0a42ae81918e87ea2d1798f40f6daca9dc9ed8f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/ParentPackageTarget.java
@@ -0,0 +1,167 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target;
+
+import java.awt.event.*;
+import java.util.Properties;
+
+import javax.swing.*;
+
+import bluej.Config;
+import bluej.graph.GraphEditor;
+import bluej.pkgmgr.Package;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.JavaNames;
+
+/**
+ * A parent package
+ *
+ * @author  Andrew Patterson
+ */
+public class ParentPackageTarget extends PackageTarget
+{
+    final static String openStr = Config.getString("pkgmgr.parentpackagetarget.open");
+    final static String openUnamedStr = Config.getString("pkgmgr.parentpackagetarget.openunamed");
+
+    public ParentPackageTarget(Package pkg)
+    {
+        super(pkg, "<go up>");
+    }
+
+    public void load(Properties props, String prefix)
+    {
+    }
+
+    public void save(Properties props, String prefix)
+    {
+    }
+
+    /**
+     * Deletes applicable files (directory and ALL contentes) prior to
+     * this PackageTarget being removed from a Package. For safety (it
+     * should never be called on this target) we override this to do
+     * nothing
+     */
+    public void deleteFiles()
+    {
+    }
+
+    /**
+     * Copy all the files belonging to this target to a new location.
+     * For package targets, this has not yet been implemented.
+     *
+     * @arg directory The directory to copy into (ending with "/")
+     */
+    public boolean copyFiles(String directory)
+    {
+        return true;
+    }
+
+    public boolean isResizable()
+    {
+        return false;
+    }
+
+    public boolean isMoveable()
+    {
+        return false;
+    }
+
+    public boolean isSaveable()
+    {
+        return false;
+    }
+
+    /**
+     * Called when a package icon in a GraphEditor is double clicked.
+     * Creates a new PkgFrame when a package is drilled down on.
+     */
+    public void doubleClick(MouseEvent evt)
+    {
+        getPackage().getEditor().raiseOpenPackageEvent(this,
+                JavaNames.getPrefix(getPackage().getQualifiedName()));
+    }
+
+    /**
+     * Disply the context menu.
+     */
+    public void popupMenu(int x, int y, GraphEditor graphEditor)
+    {
+        JPopupMenu menu = createMenu(null);
+        if (menu != null) {
+            menu.show(graphEditor, x, y);
+        }
+    }
+
+    /**
+     * Construct a popup menu which displays all our parent packages.
+     */
+    private JPopupMenu createMenu(Class<?> cl)
+    {
+        JPopupMenu menu = new JPopupMenu(getBaseName());
+
+        String item = JavaNames.getPrefix(getPackage().getQualifiedName());
+
+        while(!item.equals("")) {
+            addMenuItem(menu, openStr + " " + item, item);
+            item = JavaNames.getPrefix(item);
+        }
+
+        addMenuItem(menu, openUnamedStr, "");
+
+        return menu;
+    }
+
+    private void addMenuItem(JPopupMenu menu, String itemString, String pkgName)
+    {
+        JMenuItem item;
+
+        Action openAction = new OpenAction(itemString, this, pkgName);
+
+        item = menu.add(openAction);
+        item.setFont(PrefMgr.getPopupMenuFont());
+        item.setForeground(envOpColour);
+    }
+
+    private class OpenAction extends AbstractAction
+    {
+        private Target t;
+        private String pkgName;
+
+        public OpenAction(String menu, Target t, String pkgName)
+        {
+            super(menu);
+            this.t = t;
+            this.pkgName = pkgName;
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            getPackage().getEditor().raiseOpenPackageEvent(t, pkgName);
+        }
+    }
+    public void remove(){
+            // The user is not permitted to remove a paretnPackage
+    }
+    
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/ReadmeTarget.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/ReadmeTarget.java
new file mode 100644
index 0000000000000000000000000000000000000000..22874d4e5146009e897e9e36e9911f266ec7c177
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/ReadmeTarget.java
@@ -0,0 +1,230 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import bluej.Config;
+import bluej.editor.Editor;
+import bluej.editor.EditorManager;
+import bluej.graph.GraphEditor;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.graphPainter.ReadmeTargetPainter;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.Debug;
+
+/**
+ * A parent package
+ *
+ * @author  Andrew Patterson
+ */
+public class ReadmeTarget extends EditableTarget
+{
+    private static final int WIDTH = ReadmeTargetPainter.getMaxImageWidth();
+    private static final int HEIGHT = ReadmeTargetPainter.getMaxImageHeight();
+    private static String openStr = Config.getString("pkgmgr.packagemenu.open");
+    private static final Color envOpColour = Config.ENV_COLOUR;
+    
+    public static final String README_ID = "@README";
+
+    public ReadmeTarget(Package pkg)
+    {
+        // create the target with an identifier name that cannot be
+        // a valid java name
+        super(pkg, README_ID);
+        
+        setPos(10, 10);
+        setSize(WIDTH, HEIGHT);
+    }
+
+    @Override
+    public void load(Properties props, String prefix) throws NumberFormatException
+    {
+        if(props.getProperty(prefix + ".editor.x") != null) {
+            editorBounds = new Rectangle(Integer.parseInt(props.getProperty(prefix + ".editor.x")),
+                    Integer.parseInt(props.getProperty(prefix + ".editor.y")), 
+                    Integer.parseInt(props.getProperty(prefix + ".editor.width")),
+                    Integer.parseInt(props.getProperty(prefix + ".editor.height")));
+        }        
+    }
+
+    @Override
+    public void save(Properties props, String prefix)
+    {   
+        if (editor != null) {
+            editorBounds = editor.getBounds();            
+        } 
+        if(editorBounds!=null) {
+            props.put(prefix + ".editor.x", String.valueOf((int) editorBounds.getX()));
+            props.put(prefix + ".editor.y", String.valueOf((int) editorBounds.getY()));
+            props.put(prefix + ".editor.width", String.valueOf((int) editorBounds.getWidth()));
+            props.put(prefix + ".editor.height", String.valueOf((int) editorBounds.getHeight()));
+        }
+    }    
+
+    /*
+     * @return the name of the (text) file this target corresponds to.
+     */
+    @Override
+    public File getSourceFile()
+    {
+        return new File(getPackage().getPath(), Package.readmeName);
+    }
+
+    @Override
+    public boolean isResizable()
+    {
+        return false;
+    }
+    
+    /*
+     * Although we do save some information (the editor position) about a Readme
+     * this is not done via the usual target save mechanism. If the normal save
+     * mechanism was used, the readme target would appear as a normal target.
+     * This would result in not being able to open a project saved in a newer
+     * BlueJ version with an older BlueJ version.
+     */
+    @Override
+    public boolean isSaveable()
+    {
+        return false;
+    }
+
+    @Override
+    public Editor getEditor()
+    {
+        if(editor == null) {
+            editor = EditorManager.getEditorManager().openText(
+                                                 getSourceFile().getPath(),
+                                                 getPackage().getProject().getProjectCharset(),
+                                                 Package.readmeName, editorBounds);
+        }
+        return editor;
+    }
+
+
+    private void openEditor()
+    {
+        if (editor == null) {
+            if (! getSourceFile().exists()) {
+                try {
+                    getSourceFile().createNewFile();
+                }
+                catch (IOException ioe) {
+                    Debug.reportError("Couldn't open README", ioe);
+                }
+            }
+        }
+        
+       // now try again to open it
+       if(getEditor() != null) {
+           editor.setVisible(true);
+       }
+    }
+
+    /*
+     * Called when a package icon in a GraphEditor is double clicked.
+     * Creates a new PkgFrame when a package is drilled down on.
+     */
+    @Override
+    public void doubleClick(MouseEvent evt)
+    {
+        openEditor();
+    }
+
+    /*
+     * Post the context menu for this target.
+     */
+    @Override
+    public void popupMenu(int x, int y, GraphEditor editor)
+    {
+        JPopupMenu menu = createMenu(null);
+        if (menu != null) {
+            // editor.add(menu);
+            menu.show(editor, x, y);
+        }
+    }
+    
+    /**
+     * Construct a popup menu which displays all our parent packages.
+     */
+    private JPopupMenu createMenu(Class<?> cl)
+    {
+        JPopupMenu menu = new JPopupMenu();
+        JMenuItem item;
+           
+        Action openAction = new OpenAction(openStr);
+
+        item = menu.add(openAction);
+        item.setFont(PrefMgr.getPopupMenuFont());
+        item.setForeground(envOpColour);
+        return menu;
+    }
+
+    private class OpenAction extends AbstractAction
+    {
+        public OpenAction(String menu)
+        {
+            super(menu);
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            openEditor();
+        }
+    }
+    
+    @Override
+    public void remove()
+    {
+        // The user is not permitted to remove the readmefile
+    }
+    
+    @Override
+    public void generateDoc()
+    {
+        // meaningless
+    }
+
+    @Override
+    public String getProperty(String key) 
+    {
+        return null;
+    }
+
+    @Override
+    public void setProperty(String key, String value) 
+    {
+        
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/Target.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/Target.java
new file mode 100644
index 0000000000000000000000000000000000000000..56ce4652681859e73965112027292313e659cb77
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/Target.java
@@ -0,0 +1,303 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target;
+
+import bluej.pkgmgr.Package;
+import bluej.prefmgr.PrefMgr;
+import bluej.graph.Vertex;
+import bluej.graph.GraphEditor;
+
+import java.util.Properties;
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.*;
+
+/**
+ * A general target in a package
+ * 
+ * @author Michael Cahill
+ * @version $Id: Target.java 6963 2010-01-05 05:41:50Z davmac $
+ */
+public abstract class Target extends Vertex
+    implements Comparable<Target>
+{
+    static final int DEF_WIDTH = 80;
+    static final int DEF_HEIGHT = 50;
+    static final int ARR_HORIZ_DIST = 5;
+    static final int ARR_VERT_DIST = 10;
+    static final int HANDLE_SIZE = 20;
+    static final int TEXT_HEIGHT = 16;
+    static final int TEXT_BORDER = 4;
+    static final int SHAD_SIZE = 4;
+
+    private String identifierName; // the name handle for this target within
+    // this package (must be unique within this
+    // package)
+    private String displayName; // displayed name of the target
+    private Package pkg; // the package this target belongs to
+
+    protected boolean disabled;
+
+    protected boolean selected;
+    protected boolean queued;
+
+    // the following fields are needed to correctly calculate the width of
+    // a target in dependence of its name and the font used to display it
+    static FontRenderContext FRC = new FontRenderContext(new AffineTransform(), false, false);
+
+    /**
+     * Create a new target with default size.
+     */
+    public Target(Package pkg, String identifierName)
+    {
+        super(0, 0, calculateWidth(identifierName), DEF_HEIGHT);
+
+        if (pkg == null)
+            throw new NullPointerException();
+
+        this.pkg = pkg;
+        this.identifierName = identifierName;
+        this.displayName = identifierName;
+    }
+
+    /**
+     * Calculate the width of a target depending on the length of its name and
+     * the font used for displaying the name. The size returned is a multiple of
+     * 10 (to fit the interactive resizing behaviour).
+     * 
+     * @param name
+     *            the name of the target (may be null).
+     * @return the width the target should have to fully display its name.
+     */
+    protected static int calculateWidth(String name)
+    {
+        int width = 0;
+        if (name != null)
+            width = (int) PrefMgr.getTargetFont().getStringBounds(name, FRC).getWidth();
+        if ((width + 20) <= DEF_WIDTH)
+            return DEF_WIDTH;
+        else
+            return (width + 29) / GraphEditor.GRID_SIZE * GraphEditor.GRID_SIZE;
+    }
+    
+    /**
+     * This target has been removed from its package.
+     */
+    public void setRemoved()
+    {
+        // This can be used to detect that a class target has been removed.
+        pkg = null;
+    }
+
+    /**
+     * Load this target's properties from a properties file. The prefix is an
+     * internal name used for this target to identify its properties in a
+     * properties file used by multiple targets.
+     */
+    public void load(Properties props, String prefix)
+        throws NumberFormatException
+    {
+        // No super.load, but need to get Vertex properties:
+        int xpos = 0;
+        int ypos = 0;
+        int width = 20; // arbitrary fallback values
+        int height = 10;
+        
+        // Try to get the positional properties in a robust manner.
+        try {
+            xpos = Math.max(Integer.parseInt(props.getProperty(prefix + ".x")), 0);
+            ypos = Math.max(Integer.parseInt(props.getProperty(prefix + ".y")), 0);
+            width = Math.max(Integer.parseInt(props.getProperty(prefix + ".width")), 1);
+            height = Math.max(Integer.parseInt(props.getProperty(prefix + ".height")), 1);
+        }
+        catch (NumberFormatException nfe) {}
+        
+        setPos(xpos, ypos);
+        setSize(width, height);
+    }
+
+    /**
+     * Save the target's properties to 'props'.
+     */
+    public void save(Properties props, String prefix)
+    {
+        props.put(prefix + ".x", String.valueOf(getX()));
+        props.put(prefix + ".y", String.valueOf(getY()));
+        props.put(prefix + ".width", String.valueOf(getWidth()));
+        props.put(prefix + ".height", String.valueOf(getHeight()));
+
+        props.put(prefix + ".name", getIdentifierName());
+    }
+
+    /**
+     * Return this target's package (ie the package that this target is
+     * currently shown in)
+     */
+    public Package getPackage()
+    {
+        return pkg;
+    }
+
+    /**
+     * Change the text which the target displays for its label
+     */
+    public void setDisplayName(String name)
+    {
+        displayName = name;
+    }
+
+    /**
+     * Returns the text which the target is displaying as its label
+     */
+    public String getDisplayName()
+    {
+        return displayName;
+    }
+
+    public String getIdentifierName()
+    {
+        return identifierName;
+    }
+
+    public void setIdentifierName(String newName)
+    {
+        identifierName = newName;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see bluej.graph.Selectable#setSelected(boolean)
+     */
+    public void setSelected(boolean selected)
+    {
+        this.selected = selected;
+        repaint();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see bluej.graph.Selectable#isSelected()
+     */
+    public boolean isSelected()
+    {
+        return selected;
+    }
+
+    /**
+     * Return a bounding box for this target.
+     */
+    public Rectangle getBoundingBox()
+    {
+        return getRectangle();
+    }
+
+    public void toggleSelected()
+    {
+        selected = !selected;
+        repaint();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see bluej.graph.Selectable#isHandle(int, int)
+     */
+    public boolean isHandle(int x, int y)
+    {
+        return (x - this.getX() + y - this.getY() >= getWidth() + getHeight() - HANDLE_SIZE);
+    }
+
+    public boolean isQueued()
+    {
+        return queued;
+    }
+
+    public void setQueued(boolean queued)
+    {
+        this.queued = queued;
+    }
+
+    public boolean isResizable()
+    {
+        return true;
+    }
+
+    public boolean isSaveable()
+    {
+        return true;
+    }
+
+    public boolean isSelectable()
+    {
+        return true;
+    }
+
+    public void repaint()
+    {
+        if (pkg != null && pkg.getEditor() != null) {
+            pkg.getEditor().repaint(getX(), getY(), getWidth(), getHeight());
+        }
+    }
+
+    /**
+     * We have a notion of equality that relates solely to the identifierName.
+     * If the identifierNames's are equal then the Target's are equal.
+     */
+    public boolean equals(Object o)
+    {
+        if (o instanceof Target) {
+            Target t = (Target) o;
+            return this.identifierName.equals(t.identifierName);
+        }
+        return false;
+    }
+
+    public int hashCode()
+    {
+        return identifierName.hashCode();
+    }
+
+    public int compareTo(Target t)
+    {
+        if (equals(t))
+            return 0;
+
+        if (this.getY() < t.getY())
+            return -1;
+        else if (this.getY() > t.getY())
+            return 1;
+
+        if (this.getX() < t.getX())
+            return -1;
+        else if (this.getX() > t.getX())
+            return 1;
+
+        return this.identifierName.compareTo(t.getIdentifierName());
+    }
+
+    public String toString()
+    {
+        return getDisplayName();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/TargetCollection.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/TargetCollection.java
new file mode 100644
index 0000000000000000000000000000000000000000..4eaa42786f7c7d0d109e15d21ffa7d43289474d4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/TargetCollection.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target;
+
+import java.util.*;
+
+/**
+ * A collection of targets. 
+ *
+ * @author Andrew Patterson
+ */
+public class TargetCollection
+{
+    /** all the targets in a package */
+    protected HashMap<String,Target> targets = new HashMap<String,Target>();
+
+    public Iterator<Target> iterator()
+    {
+        return targets.values().iterator();
+    }
+
+    public Iterator<Target> sortediterator()
+    {
+        return new TreeSet<Target>(targets.values()).iterator();
+    }
+
+    public Target get(String identifierName)
+    {
+        return (Target) targets.get(identifierName);
+    }
+
+    public Target remove(String identifierName)
+    {
+        return (Target) targets.remove(identifierName);
+    }
+
+    public void add(String identifierName, Target target)
+    {
+        targets.put(identifierName, target);
+    }
+    
+    public String toString()
+    {
+        return targets.toString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/AbstractClassRole.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/AbstractClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..51452aed54632b87f96beee0205c6447d1cad493
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/AbstractClassRole.java
@@ -0,0 +1,83 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target.role;
+
+import javax.swing.*;
+import java.awt.*;
+
+import bluej.Config;
+import bluej.pkgmgr.target.*;
+
+/**
+ * A role object to represent the behaviour of abstract classes.
+ *
+ * @author  Andrew Patterson 
+ * @version $Id: AbstractClassRole.java 8123 2010-08-20 04:29:01Z davmac $
+ */
+public class AbstractClassRole extends ClassRole
+{
+    public final static String ABSTRACT_ROLE_NAME = "AbstractTarget";
+    private static final Color abstractbg = Config.getOptionalItemColour("colour.class.bg.abstract");
+    
+    /**
+     * Create the abstract class role.
+     */
+    public AbstractClassRole()
+    {
+    }
+
+    public String getRoleName()
+    {
+        return ABSTRACT_ROLE_NAME;
+    }
+
+    public String getStereotypeLabel()
+    {
+        return "abstract";
+    }
+
+    /**
+     * Return the intended background colour for this type of target.
+     */
+    public Paint getBackgroundPaint(int width, int height)
+    {
+        if (abstractbg != null) {
+            return abstractbg;
+        } else {
+            return super.getBackgroundPaint(width, height);
+        }
+    }
+
+    /**
+     * Creates a class menu containing any constructors.
+     *
+     * <p>Because we are an abstract class we cannot have any constructors
+     * so we override this method to do nothing.
+     *
+     * @param menu the popup menu to add the class menu items to
+     * @param cl Class object associated with this class target
+     */
+    public boolean createClassConstructorMenu(JPopupMenu menu, ClassTarget ct, Class<?> cl)
+    {
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/AppletClassRole.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/AppletClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..a73e9ac0a854bb21fabfde65cf65b6ae66d07f29
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/AppletClassRole.java
@@ -0,0 +1,419 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target.role;
+
+import java.awt.Color;
+import java.awt.Paint;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.nio.charset.Charset;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Properties;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFrame;
+import javax.swing.JPopupMenu;
+
+import bluej.Config;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PackageEditor;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.RunAppletDialog;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.Target;
+import bluej.utility.BlueJFileReader;
+import bluej.utility.Debug;
+import bluej.utility.FileUtility;
+import bluej.utility.Utility;
+
+/**
+ * An Applet class role in a package, i.e. a target that is a Applet class file
+ * built from Java source code.
+ *
+ * @author Bruce Quig
+ */
+public class AppletClassRole extends StdClassRole
+{
+    public static final String APPLET_ROLE_NAME = "AppletTarget";
+    
+    private RunAppletDialog dialog;
+
+    private static final Color appletbg = Config.getOptionalItemColour("colour.class.bg.applet");
+    static final String runAppletStr = Config.getString("pkgmgr.classmenu.runApplet");
+    static final String htmlComment = Config.getString("pkgmgr.runApplet.htmlComment");
+
+    static final String APPLETVIEWER_COMMAND =
+        Config.getJDKExecutablePath("appletViewer.command", "appletviewer");
+
+    public static final String HTML_EXTENSION = ".html";
+    private static final int DEFAULT_APPLET_WIDTH = 500;
+    private static final int DEFAULT_APPLET_HEIGHT = 500;
+
+    private String[] appletParams;
+    private int appletHeight;
+    private int appletWidth;
+
+    /**
+     * Create the class role.
+     */
+    public AppletClassRole()
+    {
+        appletHeight = DEFAULT_APPLET_HEIGHT;
+        appletWidth = DEFAULT_APPLET_WIDTH;
+    }
+
+    public String getRoleName()
+    {
+        return APPLET_ROLE_NAME;
+    }
+
+    public String getStereotypeLabel()
+    {
+        return "applet";
+    }
+
+    /**
+     * Return the intended background colour for this type of target.
+     */
+    public Paint getBackgroundPaint(int width, int height)
+    {
+        if (appletbg != null) {
+            return appletbg;
+        } else {
+            return super.getBackgroundPaint(width, height);
+        }
+    }
+
+    /**
+     * Save this AppletClassRole details to file
+     * @param props the properties object that stores target information
+     * @param prefix prefix for this target for identification
+     */
+    public void save(Properties props, int modifiers, String prefix)
+    {
+        super.save(props, modifiers, prefix);
+        if(dialog != null) {
+            appletParams = dialog.getAppletParameters();
+            props.put(prefix + ".numberAppletParameters", String.valueOf(appletParams.length));
+            for(int i = 0; i < appletParams.length; i++) {
+                props.put(prefix + ".appletParameter" + (i + 1), appletParams[i]);
+            }
+
+        }
+        else
+            props.put(prefix + ".numberAppletParameters", String.valueOf(0));
+
+        props.put(prefix + ".appletHeight", String.valueOf(appletHeight));
+        props.put(prefix + ".appletWidth", String.valueOf(appletWidth));
+    }
+
+
+    /**
+     * load existing information about this applet class role
+     * @param props the properties object to read
+     * @param prefix an internal name used for this target to identify
+     * its properties in a properties file used by multiple targets.
+     */
+    public void load(Properties props, String prefix) throws NumberFormatException
+    {
+        String value = props.getProperty(prefix + ".numberAppletParameters");
+
+        int numberParameters = 0;
+        if(value != null)
+            numberParameters = Integer.parseInt(value);
+        if(numberParameters > 0) {
+            appletParams = new String[numberParameters];
+            for(int i = 0; i < numberParameters; i++)
+                appletParams[i] = props.getProperty(prefix + ".appletParameter" + (i + 1));
+        }
+
+        value = props.getProperty(prefix + ".appletHeight");
+        if(value != null)
+            appletHeight = Integer.parseInt(value);
+
+        value = props.getProperty(prefix + ".appletWidth");
+        if(value != null)
+            appletWidth = Integer.parseInt(value);
+    }
+
+    /**
+     * Generate a popup menu for this class role.
+     *
+     * @param   menu    the menu to add items to
+     * @param   ct      the ClassTarget we are constructing the role for
+     * @param   state   whether the target is COMPILED etc.
+     * @return  true if we added any menu tiems, false otherwise
+     */
+    public boolean createRoleMenu(JPopupMenu menu, ClassTarget ct, Class<?> cl, int state)
+    {
+        // add run applet option
+        addMenuItem(menu, new AppletAction(ct.getPackage().getEditor(),ct),
+                     (state == ClassTarget.S_NORMAL));
+        menu.addSeparator();
+
+        return true;
+    }
+
+    private class AppletAction extends AbstractAction
+    {
+        private Target t;
+        private PackageEditor ped;
+
+        public AppletAction(PackageEditor ped, Target t)
+        {
+            super(runAppletStr);
+            this.ped = ped;
+            this.t = t;
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            ped.raiseRunTargetEvent(t, null);
+        }
+    }
+
+    /**
+     * Runs the applet using options provided by user RunAppletDialog dialog
+     * choices.  Options are:
+     *     - generate a package independent HTML page only
+     *     - run applet in JDK appletviewer
+     *     _ run in web browser
+     *
+     * @param ct the class target that is represented by this applet class
+     *
+     */
+    public void run(PkgMgrFrame parent, ClassTarget ct, String param)
+    {
+        String name = ct.getQualifiedName();
+        Package pkg = ct.getPackage();
+
+        if(dialog == null) {
+            dialog = new RunAppletDialog(parent, name);
+            // add params that originated from pkg properties
+            if(appletParams != null)
+                dialog.setAppletParameters(appletParams);
+            dialog.setAppletHeight(appletHeight);
+            dialog.setAppletWidth(appletWidth);
+        }
+        
+        if(dialog.display()) {  // if OK was clicked
+            // TODO: check is the class path handling can be simplified.
+            File[] libs = parent.getProject().getClassLoader().getClassPathAsFiles();
+
+            int execOption = dialog.getAppletExecutionOption();
+            if(execOption == RunAppletDialog.GENERATE_PAGE_ONLY) {
+                // generate HTML page for Applet using selected path and file name
+                File generatedFile = chooseWebPage(parent);
+                if(generatedFile != null) {
+                    createWebPage(generatedFile, name, pkg.getPath().getPath(), libs);
+                }
+            }
+            else {
+                String fname = name + HTML_EXTENSION;
+                File destFile = new File(pkg.getProject().getProjectDir(), name + HTML_EXTENSION);
+                
+                createWebPage(destFile, name, ".", libs);
+
+                // Run applet as an external process
+                if(execOption == RunAppletDialog.EXEC_APPLETVIEWER) {
+                    try {
+                        String[] execCommand = {APPLETVIEWER_COMMAND, fname};
+                        PkgMgrFrame.displayMessage(Config.getString("pkgmgr.appletInViewer"));
+
+                        Process applet = Runtime.getRuntime().exec(execCommand, null,
+                                pkg.getProject().getProjectDir());
+                        
+                        new StreamReader(applet.getErrorStream()).start();
+                        new StreamReader(applet.getInputStream()).start();
+                    } catch (Exception e) {
+                        pkg.showError("appletviewer-error");
+                        Debug.reportError("Exception thrown in execution of appletviewer");
+                        e.printStackTrace();
+                    }
+                }
+                else {
+                    // start in Browser
+                    PkgMgrFrame.displayMessage(Config.getString("pkgmgr.appletInBrowser"));
+                    Utility.openWebBrowser(destFile);
+                }
+            }
+        }
+    }
+
+    /**
+     * A utility class to mop up all the output that an applet might vomit.
+     */
+    private class StreamReader extends Thread
+    {
+        private InputStream stream;
+        
+        public StreamReader(InputStream stream)
+        {
+            this.stream = stream;
+        }
+        
+        @Override
+        public void run()
+        {
+            byte [] buf = new byte[1024];
+            try {
+                int len;
+                do {
+                    len = stream.read(buf);
+                }
+                while (len != -1);
+            }
+            catch (IOException ioe) {}
+        }
+    }
+
+    /**
+     * Use a file chooser to select a web page name and location.
+     *
+     * @param frame the parent frame for the file chooser
+     * @return the full file name for the web page or null
+     *         if cancel selected in file chooser
+     */
+    private File chooseWebPage(JFrame frame)
+    {
+        String fullFileName = FileUtility.getFileName(frame,
+                                Config.getString("pkgmgr.chooseWebPage.title"),
+                                Config.getString("pkgmgr.chooseWebPage.buttonLabel"), 
+                                null, false);
+
+        if (fullFileName == null) {
+            return null;
+        }
+        
+        if(! fullFileName.endsWith(HTML_EXTENSION)) {
+            fullFileName += HTML_EXTENSION;
+        }
+
+        return new File(fullFileName);
+    }
+
+    /**
+     * Read the applet parameters (width, height, params) from the
+     * dialog and store them.
+     */
+    private void updateAppletProperties()
+    {
+        try{
+            appletHeight = Integer.parseInt(dialog.getAppletHeight());
+            appletWidth = Integer.parseInt(dialog.getAppletWidth());
+        } catch (NumberFormatException nfe) {
+            // add exception handling
+        }
+        appletParams = dialog.getAppletParameters();
+    }
+
+    /**
+     * Create a HTML page that contains this JApplet using
+     * parameters input by user in RunAppletDialog class.
+     *
+     * @param fileName fileName for HTML file to house Applet
+     */
+    private void createWebPage(File outputFile, String appletName, String appletCodeBase, File[] libs)
+    {
+        updateAppletProperties();
+        generateHTMLSkeleton(outputFile, appletName, appletCodeBase, libs, 
+                             dialog.getAppletWidth(), dialog.getAppletHeight(), appletParams);
+    }
+
+    /**
+     * Creates a HTML Skeleton that contains this JApplet using
+     * parameters input by user in RunAppletDialog class.
+     *
+     * @param name              the fully qualified name of the applet class
+     * @param outputFileName    the name of the generated HTML file
+     * @param appletCodeBase    code base to be included in applet tag (canot be null)
+     * @param width             specified width of applet
+     * @param height            specified height of applet
+     * @param parameters        optional applet parameters
+     */
+    private void generateHTMLSkeleton(File outputFile, String appletName, String appletCodeBase, File[] libs,
+                                      String width, String height, String[] parameters)
+    {
+        Hashtable<String,String> translations = new Hashtable<String,String>();
+
+        translations.put("TITLE", appletName);
+        translations.put("COMMENT", htmlComment);
+        translations.put("CLASSFILE", appletName + ".class");
+        // whilst it would be nice to be able to have no codebase, it is in the
+        // HTML template file and hence even if we define no CODEBASE here, it
+        // will appear in the resulting HTML anyway (as CODEBASE=$CODEBASE)
+        translations.put("CODEBASE", appletCodeBase);
+        translations.put("APPLETWIDTH", width);
+        translations.put("APPLETHEIGHT", height);
+        
+        // add libraries from <project>/+libs/ to archives
+        String archives = "";
+        try{
+            for(int i=0; i < libs.length; i++) {
+                if(archives.length() == 0) {
+                    archives = libs[i].toURI().toURL().toString();
+                }
+                else {
+                    archives += "," + libs[i].toURI().toURL();
+                }
+            }
+        }
+        catch(MalformedURLException e) {}
+        
+        translations.put("ARCHIVE", archives);
+
+        StringBuffer allParameters = new StringBuffer();
+        for(int index = 0; index < parameters.length; index++)
+            allParameters.append("\t" + parameters[index] + "\n");
+
+        translations.put("PARAMETERS", allParameters.toString());
+
+        File tmplFile = Config.getTemplateFile("html");
+
+        try {
+            Charset utf8 = Charset.forName("UTF-8");
+            BlueJFileReader.translateFile(tmplFile, outputFile, translations, utf8, utf8);
+        } catch(IOException e) {
+            Debug.reportError("Exception during file translation from " +
+                              tmplFile + " to " + outputFile);
+            e.printStackTrace();
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see bluej.pkgmgr.target.role.ClassRole#getAllFiles(bluej.pkgmgr.target.ClassTarget)
+     */
+    public List<File> getAllFiles(ClassTarget ct)
+    {
+        List<File> rlist = super.getAllFiles(ct);
+
+        File htmlFile = new File(ct.getPackage().getProject().getProjectDir(), 
+                ct.getQualifiedName() + HTML_EXTENSION);
+        rlist.add(htmlFile);
+        
+        return rlist;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/ClassRole.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/ClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..325b238b093e208c28e3bf3d4875f60a185b24f8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/ClassRole.java
@@ -0,0 +1,341 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target.role;
+
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Paint;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Properties;
+
+import javax.swing.Action;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import bluej.Config;
+import bluej.debugmgr.ConstructAction;
+import bluej.debugmgr.objectbench.InvokeAction;
+import bluej.debugmgr.objectbench.InvokeListener;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.BlueJFileReader;
+import bluej.utility.Debug;
+import bluej.views.CallableView;
+import bluej.views.ConstructorView;
+import bluej.views.MethodView;
+import bluej.views.View;
+import bluej.views.ViewFilter;
+
+/**
+ * A class role in a class target, providing behaviour specific to particular
+ * class types
+ * 
+ * @author Bruce Quig
+ */
+public abstract class ClassRole
+{
+    public final static String CLASS_ROLE_NAME = null;
+
+    private final Color defaultbg = Config.getOptionalItemColour("colour.class.bg.default");
+    protected final Color envOpColour = Config.ENV_COLOUR;
+
+    public String getRoleName()
+    {
+        return CLASS_ROLE_NAME;
+    }
+
+    /**
+     * save details about the class target variant this role represents.
+     * 
+     * @param props
+     *            the properties object associated with this target and role
+     * @param modifiers
+     *            modifiers for
+     * @param prefix
+     *            prefix to identifiy this role's target
+     */
+    public void save(Properties props, int modifiers, String prefix)
+    {
+    }
+
+    /**
+     * load existing information about this class role
+     * 
+     * @param props
+     *            the properties object to read
+     * @param prefix
+     *            an internal name used for this target to identify its
+     *            properties in a properties file used by multiple targets.
+     */
+    public void load(Properties props, String prefix)
+        throws NumberFormatException
+    {
+
+    }
+
+    /**
+     * Return the default background colour for targets that don't want to
+     * define their own colour.
+     * @param width Width of total area to paint
+     * @param height Height of total area to paint
+     */
+    public Paint getBackgroundPaint(int width, int height)
+    {
+        if (defaultbg != null) {
+            return defaultbg;
+        } else {
+            return new GradientPaint(
+                0, 0, new Color(246,221,192),
+                0, height, new Color(245,204,155)); 
+        }
+    }
+
+    /**
+     * Get the "stereotype label" for this class role. This will be displayed
+     * on classes in the UML diagram along with the class name. It may return
+     * null if there is no stereotype label.
+     */
+    public String getStereotypeLabel()
+    {
+        return null;
+    }
+
+    /**
+     * Generates a source code skeleton for this class.
+     * 
+     * @param template
+     *            the name of the particular class template (just the base name
+     *            without path and suffix)
+     * @param pkg
+     *            the package that the class target resides in
+     * @param name
+     *            the name of the class
+     * @param sourceFile
+     *            the name of the source file to be generated
+     */
+    public boolean generateSkeleton(String template, Package pkg, String name, String sourceFile)
+    {
+        Hashtable<String,String> translations = new Hashtable<String,String>();
+        translations.put("CLASSNAME", name);
+
+        if (pkg.isUnnamedPackage()) {
+            translations.put("PKGLINE", "");
+        }
+        else {
+            translations.put("PKGLINE", "package " + pkg.getQualifiedName() + ";" + Config.nl + Config.nl);
+        }
+
+        try {
+            // Check for existing file. Normally this won't happen (the check for duplicate
+            // target occurs prior to this) but on Windows filenames are case insensitive.
+            File dest = new File(sourceFile);
+            if (dest.exists()) {
+                pkg.showError("duplicate-name");
+                return false;
+            }
+            BlueJFileReader.translateFile(Config.getClassTemplateFile(template),
+                    new File(sourceFile), translations,
+                    Charset.forName("UTF-8"), pkg.getProject().getProjectCharset());
+            return true;
+        }
+        catch (IOException e) {
+            pkg.showError("skeleton-error");
+            Debug.reportError("The default skeleton for the class could not be generated");
+            Debug.reportError("Exception: " + e);
+            return false;
+        }
+    }
+
+    /**
+     * Adds a single item to this roles popup menu.
+     * 
+     * This method is used by ClassTarget to add some standard menus as well as
+     * by the roles to add menus. It should be overridden with caution.
+     * 
+     * @param menu
+     *            the popup menu the item is to be added to
+     * @param action
+     *            the action to be registered with this menu item
+     * @param itemString
+     *            the String to be displayed on menu item
+     * @param enabled
+     *            boolean value representing whether item should be enabled
+     *  
+     */
+    public void addMenuItem(JPopupMenu menu, Action action, boolean enabled)
+    {
+        JMenuItem item;
+
+        item = new JMenuItem();
+        item.setAction(action);
+        item.setFont(PrefMgr.getPopupMenuFont());
+        item.setForeground(envOpColour);
+        item.setEnabled(enabled);
+
+        menu.add(item);
+    }
+
+    /**
+     * Adds role specific items at the top of the popup menu for this class
+     * target.
+     * 
+     * @param menu
+     *            the menu object to add to
+     * @param ct
+     *            ClassTarget object associated with this class role
+     * @param state
+     *            the state of the ClassTarget
+     * 
+     * @return true if any menu items have been added
+     */
+    public boolean createRoleMenu(JPopupMenu menu, ClassTarget ct, Class<?> cl, int state)
+    {
+        return false;
+    }
+
+    /**
+     * Adds role specific items at the bottom of the popup menu for this class
+     * target.
+     * 
+     * @param menu
+     *            the menu object to add to
+     * @param ct
+     *            ClassTarget object associated with this class role
+     * @param state
+     *            the state of the ClassTarget
+     * 
+     * @return true if any menu items have been added
+     */
+    public boolean createRoleMenuEnd(JPopupMenu menu, ClassTarget ct, int state)
+    {
+        return false;
+    }
+
+    /**
+     * Creates a class menu containing the constructors.
+     * 
+     * @param menu
+     *            the popup menu to add the class menu items to
+     * @param cl
+     *            Class object associated with this class target
+     */
+    public boolean createClassConstructorMenu(JPopupMenu menu, ClassTarget ct, Class<?> cl)
+    {
+        ViewFilter filter;
+        View view = View.getView(cl);
+
+        if (!java.lang.reflect.Modifier.isAbstract(cl.getModifiers())) {
+            filter = new ViewFilter(ViewFilter.INSTANCE | ViewFilter.PACKAGE);
+            ConstructorView[] constructors = view.getConstructors();
+
+            if (createMenuItems(menu, constructors, filter, 0, constructors.length, "new ", ct))
+                return true;
+        }
+
+        return false;
+    }
+
+    public boolean createClassStaticMenu(JPopupMenu menu, ClassTarget ct, Class<?> cl)
+    {
+        ViewFilter filter;
+        View view = View.getView(cl);
+
+        filter = new ViewFilter(ViewFilter.STATIC | ViewFilter.PACKAGE);
+        MethodView[] allMethods = view.getAllMethods();
+        if (createMenuItems(menu, allMethods, filter, 0, allMethods.length, "", ct))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Create the menu items for the given members (constructors or methods).
+     * @return  true if any items were created
+     */
+    public static boolean createMenuItems(JPopupMenu menu, CallableView[] members, ViewFilter filter, int first, int last,
+            String prefix, InvokeListener il)
+    {
+        // Debug.message("Inside ClassTarget.createMenuItems\n first = " + first
+        // + " last = " + last);
+        boolean hasEntries = false;
+        JMenuItem item;
+
+        for (int i = first; i < last; i++) {
+            try {
+                CallableView m = members[last - i - 1];
+                if (!filter.accept(m))
+                    continue;
+                // Debug.message("createSubMenu - creating MenuItem");
+
+                Action callAction = null;
+                if (m instanceof MethodView)
+                    callAction = new InvokeAction((MethodView) m, il, prefix + m.getLongDesc());
+                else if (m instanceof ConstructorView)
+                    callAction = new ConstructAction((ConstructorView) m, il, prefix + m.getLongDesc());
+
+                if (callAction != null) {
+                    item = menu.add(callAction);
+                    item.setFont(PrefMgr.getPopupMenuFont());
+                    hasEntries = true;
+                }
+            }
+            catch (Exception e) {
+                Debug.reportError("Exception accessing methods: " + e);
+                e.printStackTrace();
+            }
+        }
+        return hasEntries;
+    }
+
+    public void run(PkgMgrFrame pmf, ClassTarget ct, String param)
+    {}
+    
+    /**
+     * Get all the files belonging to a class target - source, class, ctxt, docs
+     * @param ct  The class target
+     * @return  A list of File objects
+     */
+    public List<File> getAllFiles(ClassTarget ct)
+    {
+        // Source, .class, .ctxt, and doc (.html)
+        List<File> rlist = new ArrayList<File>();
+        
+        rlist.add(ct.getClassFile());
+        rlist.add(ct.getSourceFile());
+        rlist.add(ct.getContextFile());
+        rlist.add(ct.getDocumentationFile());
+        
+        File [] innerClasses = ct.getInnerClassFiles();
+        for (int i = 0; i < innerClasses.length; i++) {
+            rlist.add(innerClasses[i]);
+        }
+        
+        return rlist;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/EnumClassRole.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/EnumClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..b66a278efdc02dcfa7c7838140a2b4c3280395f4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/EnumClassRole.java
@@ -0,0 +1,106 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target.role;
+
+import java.awt.Color;
+import java.awt.Paint;
+
+import javax.swing.JPopupMenu;
+import bluej.Config;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.prefmgr.PrefMgr;
+
+/**
+ * A role object to represent the behaviour of enums.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class EnumClassRole extends ClassRole
+{
+    public final static String ENUM_ROLE_NAME = "EnumTarget";
+    private static final Color enumbg = Config.getOptionalItemColour("colour.class.bg.enum");
+    
+    /**
+     * Create the enum class role.
+     */
+    public EnumClassRole()
+    {
+    }
+
+    public String getRoleName()
+    {
+        return ENUM_ROLE_NAME;
+    }
+
+    public String getStereotypeLabel()
+    {
+        return "enum";
+    }
+
+    /**
+     * Return the intended background colour for this type of target.
+     */
+    public Paint getBackgroundPaint(int width, int height)
+    {
+        if (enumbg != null) {
+            return enumbg;
+        } else {
+            return super.getBackgroundPaint(width, height);
+        }
+    }
+
+    /**
+     * Creates a class menu containing any constructors.
+     *
+     * Because we are an enum class we cannot have any constructors
+     * so we override this method to do nothing.
+     *
+     * @param menu the popup menu to add the class menu items to
+     * @param cl Class object associated with this class target
+     */
+    public boolean createClassConstructorMenu(JPopupMenu menu, ClassTarget ct, Class<?> cl)
+    {
+        return false;
+    }
+    
+    /**
+     * Adds role specific items at the bottom of the popup menu for this class target.
+     *
+     * @param menu the menu object to add to
+     * @param ct ClassTarget object associated with this class role
+     * @param state the state of the ClassTarget
+     *
+     * @return true if any menu items have been added
+     */
+    public boolean createRoleMenuEnd(JPopupMenu menu, ClassTarget ct, int state)
+    {
+        if(PrefMgr.getFlag(PrefMgr.SHOW_TEST_TOOLS)) {
+            if (ct.getAssociation() == null) {
+                menu.addSeparator();
+                addMenuItem(menu, ct.new CreateTestAction(), true);
+            }
+        }
+        return true;
+    }
+    
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/InterfaceClassRole.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/InterfaceClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..4653e68eb4c62d9fef4de45c72599aea585ff22d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/InterfaceClassRole.java
@@ -0,0 +1,68 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target.role;
+
+import java.awt.*;
+
+import bluej.Config;
+
+/**
+ * A role object to represent the behaviour of interfaces.
+ *
+ * @author  Andrew Patterson 
+ * @version $Id: InterfaceClassRole.java 7594 2010-05-18 14:39:08Z nccb $
+ */
+public class InterfaceClassRole extends ClassRole
+{
+    public final static String INTERFACE_ROLE_NAME = "InterfaceTarget";
+    private static final Color interfacebg = Config.getOptionalItemColour("colour.class.bg.interface");
+
+    /**
+     * Create the interface class role.
+     */
+    public InterfaceClassRole()
+    {
+    }
+
+    public String getRoleName()
+    {
+        return INTERFACE_ROLE_NAME;
+    }
+
+    public String getStereotypeLabel()
+    {
+        return "interface";
+    }
+
+    /**
+     * Return the intended background colour for this type of target.
+     */
+    public Paint getBackgroundPaint(int width, int height)
+    {
+        if (interfacebg != null) {
+            return interfacebg;
+        } else {
+            return super.getBackgroundPaint(width, height);
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/MIDletClassRole.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/MIDletClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..1d75fcb99549beb2501e28ed3f2bb4a2da7421c6
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/MIDletClassRole.java
@@ -0,0 +1,61 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target.role;
+
+import java.awt.Color;
+import java.awt.Paint;
+import bluej.Config;
+
+/**
+ * A MIDlet class role in a package, i.e. a target that is a MIDlet class file
+ * built from Java source code.
+ *
+ * @author Cecilia Vargas
+ */
+public class MIDletClassRole extends ClassRole
+{
+    public static final String MIDLET_ROLE_NAME = "MIDletTarget";
+    
+    private static final Color bckgrndColor = Config.getOptionalItemColour("colour.class.bg.midlet");
+
+    
+    public MIDletClassRole()  { }
+
+    public String getRoleName()
+    {
+        return MIDLET_ROLE_NAME;
+    }
+
+    public String getStereotypeLabel()
+    {
+        return "MIDlet";
+    }
+    
+    public Paint getBackgroundPaint(int width, int height)
+    {
+        if (bckgrndColor != null) {
+            return bckgrndColor;
+        } else {
+            return super.getBackgroundPaint(width, height);
+        }
+    }
+ }
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/StdClassRole.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/StdClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ff1eba1b716cd4c897f8f719616bc0e2f30d9fa
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/StdClassRole.java
@@ -0,0 +1,81 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target.role;
+
+import javax.swing.JPopupMenu;
+
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.prefmgr.PrefMgr;
+
+/**
+ * A role object which a class target uses to delegate behaviour to.
+ * StdClassRole is used to represent standard Java classes.
+ *
+ * @author Bruce Quig
+ */
+public class StdClassRole extends ClassRole
+{
+    /**
+     * Create the class role.
+     */
+    public StdClassRole()
+    {
+    }
+
+    public String getRoleName()
+    {
+        return "ClassTarget";
+    }
+ 
+    /**
+     * Generate a popup menu for this class role.
+     *
+     * @param   menu    the menu to add items to
+     * @param   ct      the ClassTarget we are constructing the role for
+     * @param   state   whether the target is COMPILED etc.
+     * @return  true if we added any menu tiems, false otherwise
+     */
+    public boolean createRoleMenu(JPopupMenu menu, ClassTarget ct, Class<?> cl, int state)
+    {
+        return false;
+    }
+
+    /**
+     * Adds role specific items at the bottom of the popup menu for this class target.
+     *
+     * @param menu the menu object to add to
+     * @param ct ClassTarget object associated with this class role
+     * @param state the state of the ClassTarget
+     *
+     * @return true if any menu items have been added
+     */
+    public boolean createRoleMenuEnd(JPopupMenu menu, ClassTarget ct, int state)
+    {
+        if(PrefMgr.getFlag(PrefMgr.SHOW_TEST_TOOLS)) {
+            if (ct.getAssociation() == null) {
+                menu.addSeparator();
+                addMenuItem(menu, ct.new CreateTestAction(), true);
+            }
+        }
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/UnitTestClassRole.java b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/UnitTestClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..4887996359a1d19e7c572613f1d7a5b90727ce1c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/pkgmgr/target/role/UnitTestClassRole.java
@@ -0,0 +1,771 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.pkgmgr.target.role;
+
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.awt.GradientPaint;
+import java.awt.Paint;
+import java.awt.event.ActionEvent;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import org.junit.Test;
+
+import bluej.Config;
+import bluej.debugger.DebuggerObject;
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.editor.Editor;
+import bluej.parser.SourceLocation;
+import bluej.parser.SourceSpan;
+import bluej.parser.UnitTestAnalyzer;
+import bluej.pkgmgr.PackageEditor;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.TestRunnerThread;
+import bluej.pkgmgr.target.ClassTarget;
+import bluej.pkgmgr.target.Target;
+import bluej.prefmgr.PrefMgr;
+import bluej.testmgr.TestDisplayFrame;
+import bluej.testmgr.record.ExistingFixtureInvokerRecord;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.JavaNames;
+import bluej.utility.JavaUtils;
+
+/**
+ * A role object for Junit unit tests.
+ *
+ * @author  Andrew Patterson
+ */
+public class UnitTestClassRole extends ClassRole
+{
+    public static final String UNITTEST_ROLE_NAME = "UnitTestTarget";
+    public static final String UNITTEST_ROLE_NAME_JUNIT4 = "UnitTestTargetJunit4";
+
+    private final Color unittestbg = Config.getOptionalItemColour("colour.class.bg.unittest");
+
+    private static final String testAll = Config.getString("pkgmgr.test.popup.testAll");
+    private static final String createTest = Config.getString("pkgmgr.test.popup.createTest");
+    private static final String benchToFixture = Config.getString("pkgmgr.test.popup.benchToFixture");
+    private static final String fixtureToBench = Config.getString("pkgmgr.test.popup.fixtureToBench");
+    
+    /** Whether this is a Junit 4 test class. If false, it's a Junit 3 test class. */
+    private boolean isJunit4;
+    
+    /**
+     * Create the unit test class role.
+     */
+    public UnitTestClassRole(boolean isJunit4)
+    {
+        this.isJunit4 = isJunit4;
+    }
+
+    @Override
+    public String getRoleName()
+    {
+        if (isJunit4) {
+            return UNITTEST_ROLE_NAME_JUNIT4;
+        }
+        else {
+            return UNITTEST_ROLE_NAME;
+        }
+    }
+
+    @Override
+    public String getStereotypeLabel()
+    {
+        return "unit test";
+    }
+
+    /**
+     * Return the intended background colour for this type of target.
+     */
+    @Override
+    public Paint getBackgroundPaint(int width, int height)
+    {
+        if (unittestbg != null) {
+            return unittestbg;
+        } else {
+            return new GradientPaint(
+                    0, 0, new Color(197,211,165),
+                    0, height, new Color(170,190,140)); 
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private boolean isJUnitTestMethod(Method m)
+    {
+        if (isJunit4) {
+            Class<?> cl = m.getDeclaringClass();
+            ClassLoader classLoader = cl.getClassLoader();
+            try {
+                Class<Test> testClass;
+                if (classLoader == null) {
+                    testClass = org.junit.Test.class;
+                }
+                else {
+                    testClass = (Class<Test>) classLoader.loadClass("org.junit.Test");
+                }
+
+                if (m.getAnnotation(testClass) != null) {
+                    if (!Modifier.isPublic(m.getModifiers())) return false;
+                    if (m.getParameterTypes().length != 0) return false;
+                    return true;
+                }
+            }
+            catch (ClassNotFoundException cnfe) {}
+            catch (LinkageError le) {}
+
+            // No suitable annotations found, so not a test class
+            return false;
+        }
+        else {
+            // look for reasons to not include this method as a test case
+            if (!m.getName().startsWith("test")) return false;
+            if (!Modifier.isPublic(m.getModifiers())) return false;
+            if (m.getParameterTypes().length != 0) return false;
+            if (!m.getReturnType().equals(Void.TYPE)) return false;
+            return true;
+        }
+    }
+    
+    /**
+     * Generate a popup menu for this TestClassRole.
+     * @param cl the class object that is represented by this target
+     * @param editorFrame the frame in which this targets package is displayed
+     * @return the generated JPopupMenu
+     */
+    @Override
+    public boolean createRoleMenu(JPopupMenu menu, ClassTarget ct, Class<?> cl, int state)
+    {
+        boolean enableTestAll = false;
+
+        if (state == ClassTarget.S_NORMAL && cl != null && ! ct.isAbstract()) {
+            Method[] allMethods = cl.getMethods();
+
+            for (int i=0; i < allMethods.length; i++) {
+                Method m = allMethods[i];
+
+                if (isJUnitTestMethod(m)) {
+                    enableTestAll = true;
+                    break;
+                }
+            }
+        }
+
+        // add run all tests option
+        addMenuItem(menu, new TestAction(testAll, ct.getPackage().getEditor(),ct), enableTestAll);
+        menu.addSeparator();
+
+        return false;
+    }
+
+    /**
+     * creates a class menu containing any constructors and static methods etc.
+     *
+     * @param menu the popup menu to add the class menu items to
+     * @param cl Class object associated with this class target
+     */
+    @Override
+    public boolean createClassConstructorMenu(JPopupMenu menu, ClassTarget ct, Class<?> cl)
+    {
+        boolean hasEntries = false;
+
+        Method[] allMethods = cl.getMethods();
+        
+        if (! ct.isAbstract()) {
+            for (int i=0; i < allMethods.length; i++) {
+                Method m = allMethods[i];
+                
+                if (!isJUnitTestMethod(m)) {
+                    continue;
+                }
+                
+                String rtype;
+                try {
+                    rtype = JavaUtils.getJavaUtils().getReturnType(m).toString(true);
+                }
+                catch (ClassNotFoundException cnfe) {
+                    rtype = m.getReturnType().getName();
+                }
+                Action testAction = new TestAction(rtype + " " + m.getName() + "()",
+                        ct.getPackage().getEditor(), ct, m.getName());
+                
+                JMenuItem item = new JMenuItem();
+                item.setAction(testAction);
+                item.setFont(PrefMgr.getPopupMenuFont());
+                menu.add(item);
+                hasEntries = true;
+            }
+            if (!hasEntries) {
+                JMenuItem item = new JMenuItem(Config.getString("pkgmgr.test.popup.noTests"));
+                item.setFont(PrefMgr.getPopupMenuFont());
+                item.setEnabled(false);
+                menu.add(item);
+            }
+        }
+        else {
+            JMenuItem item = new JMenuItem(Config.getString("pkgmgr.test.popup.abstract"));
+            item.setFont(PrefMgr.getPopupMenuFont());
+            item.setEnabled(false);
+            menu.add(item);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean createClassStaticMenu(JPopupMenu menu, ClassTarget ct, Class<?> cl)
+    {
+        boolean enable = !ct.getPackage().getProject().inTestMode() && ct.hasSourceCode() && ! ct.isAbstract();
+            
+        addMenuItem(menu, new MakeTestCaseAction(createTest,
+                                                    ct.getPackage().getEditor(), ct), enable);
+        addMenuItem(menu, new BenchToFixtureAction(benchToFixture,
+                                                    ct.getPackage().getEditor(), ct), enable);
+        addMenuItem(menu, new FixtureToBenchAction(fixtureToBench,
+                                                    ct.getPackage().getEditor(), ct), enable);
+
+        return true;
+    }
+
+    @Override
+    public void run(final PkgMgrFrame pmf, final ClassTarget ct, final String param)
+    {
+        if (param != null) {
+            // Only running a single test
+            TestDisplayFrame.getTestDisplay().startTest(pmf.getProject(), 1);
+        }
+        
+        new TestRunnerThread(pmf, ct, param).start();
+    }
+    
+    /**
+     * Set up a test run. This just involves going through the methods in the class
+     * and creating a list of those which are test methods.
+     * 
+     * @param pmf   The package manager frame
+     * @param ct    The class target
+     * @param trt   The test runner thread
+     */
+    public void doRunTest(PkgMgrFrame pmf, ClassTarget ct, TestRunnerThread trt)
+    {
+        Class<?> cl = pmf.getPackage().loadClass(ct.getQualifiedName());
+        
+        if (cl == null)
+            return;
+        
+        // Test the whole class
+        Method[] allMethods = cl.getMethods();
+        
+        ArrayList<String> testMethods = new ArrayList<String>();
+        
+        int testCount = 0;
+        
+        for (int i=0; i < allMethods.length; i++) {
+            if (isJUnitTestMethod(allMethods[i])) {
+                testCount++;
+                testMethods.add(allMethods[i].getName());
+            }
+        }
+        
+        String [] testMethodsArr = (String []) testMethods.toArray(new String[testCount]);
+        trt.setMethods(testMethodsArr);
+        TestDisplayFrame.getTestDisplay().startTest(pmf.getProject(), testCount);
+    }
+    
+    /**
+     * Get the count of tests in the test class.
+     * @param ct  The ClassTarget of the unit test class
+     * @return    the number of tests in the unit test class
+     */
+    public int getTestCount(ClassTarget ct)
+    {
+        if (! ct.isCompiled()) {
+            return 0;
+        }
+        
+        Class<?> cl = ct.getPackage().loadClass(ct.getQualifiedName());
+        if (cl == null) {
+            return 0;
+        }
+        
+        Method[] allMethods = cl.getMethods();
+
+        int testCount = 0;
+
+        for (int i=0; i < allMethods.length; i++) {
+            if (isJUnitTestMethod(allMethods[i])) {
+                testCount++;
+            }
+        }
+        
+        return testCount;
+    }
+    
+    /**
+     * Start the construction of a test method.
+     * 
+     * This method prompts the user for a test method name and then sets up
+     * all the variables for constructing a new test method.
+     * 
+     * @param pmf  the PkgMgrFrame this is all occurring in
+     * @param ct   the ClassTarget of the unit test class
+     */
+    public void doMakeTestCase(final PkgMgrFrame pmf, final ClassTarget ct)
+    {
+        // prompt for a new test name
+        String newTestName = DialogManager.askString(pmf, "unittest-new-test-method");
+
+        if (newTestName == null) {
+            return;
+        }
+
+        if (newTestName.length() == 0) {
+            pmf.setStatus(Config.getString("pkgmgr.test.noTestName"));
+            return;
+        }
+
+        // Junit 3 test methods must start with the word "test"
+        if(!isJunit4 && !newTestName.startsWith("test")) {
+            newTestName = "test" + Character.toTitleCase(newTestName.charAt(0)) + newTestName.substring(1);
+        }
+
+        // and they must be a valid Java identifier
+        if (!JavaNames.isIdentifier(newTestName)) {
+            pmf.setStatus(Config.getString("pkgmgr.test.invalidTestName"));
+            return;
+        }
+
+        // find out if the method already exists in the unit test src
+        try {
+            Charset charset = pmf.getProject().getProjectCharset();
+            UnitTestAnalyzer uta = analyzeUnitTest(ct, charset);
+
+            SourceSpan existingSpan = uta.getMethodBlockSpan(newTestName);
+
+            if (existingSpan != null) {
+                if (DialogManager.askQuestion(null, "unittest-method-present") == 1) {
+                    return;
+                }
+            }
+        }
+        catch (IOException ioe) { 
+            DialogManager.showErrorWithText(null, "unittest-io-error", ioe.getLocalizedMessage());
+            Debug.reportError("Error reading unit test source", ioe);
+        }
+
+        pmf.testRecordingStarted(Config.getString("pkgmgr.test.recording") + " "
+                + ct.getBaseName() + "." + newTestName + "()");
+
+        pmf.getProject().removeClassLoader();
+
+        runTestSetup(pmf, ct, false);
+        
+        pmf.getObjectBench().resetRecordingInteractions();
+        pmf.setTestInfo(newTestName, ct);
+    }
+    
+    /**
+     * Analyze a unit test file.
+     * @param ct  The classtarget representing the unit test class to analyze
+     * @return  A UnitTestAnalyzer object with information about the unit test class
+     * @throws IOException  if the source file can't be saved or read
+     */
+    private UnitTestAnalyzer analyzeUnitTest(ClassTarget ct, Charset fileEncoding) throws IOException
+    {
+        ct.ensureSaved();
+        
+        UnitTestAnalyzer uta = null;
+        FileInputStream fis = null;
+        try {
+            fis = new FileInputStream(ct.getSourceFile());
+            Reader reader = new InputStreamReader(fis, fileEncoding);
+            uta = new UnitTestAnalyzer(reader);
+        }
+        catch (FileNotFoundException fnfe) {
+            throw fnfe;
+        }
+        finally {
+            if (fis != null) {
+                try {
+                    fis.close();
+                }
+                catch (IOException ioe) {
+                    // shouldn't happen
+                    Debug.reportError(ioe);
+                }
+            }
+        }
+        
+        return uta;
+    }
+    
+    /**
+     * Run the test setup.
+     * @param pmf  The package manager frame to run the setup in
+     * @param ct   The classtarget for the test class
+     */
+    private void runTestSetup(final PkgMgrFrame pmf, final ClassTarget ct, final boolean recordAsFixtureToBench)
+    {
+        // Avoid running test setup (which is user code) on the event thread.
+        // Run it on a new thread instead.
+        new Thread() {
+            public void run() {
+                
+                final Map<String,DebuggerObject> dobs = pmf.getProject().getDebugger().runTestSetUp(ct.getQualifiedName());
+                
+                EventQueue.invokeLater(new Runnable() {
+                    public void run() {
+                        Iterator<Map.Entry<String,DebuggerObject>> it = dobs.entrySet().iterator();
+                        
+                        while(it.hasNext()) {
+                            Map.Entry<String,DebuggerObject> mapent = it.next();
+                            DebuggerObject objVal = mapent.getValue();
+                            
+                            if (! objVal.isNullObject()) {
+                                pmf.putObjectOnBench(mapent.getKey(), objVal, objVal.getGenType(), null);
+                            }
+                        }
+                    }
+                });
+            }
+        }.start();
+    }
+
+    private static final String spaces = "                                 ";
+    
+    /**
+     * Get a string of whitespace corresponding to an indentation.
+     */
+    private String getIndentString()
+    {
+        int ts = Math.min(Config.getPropInteger("bluej.editor.tabsize", 4), spaces.length());
+        return spaces.substring(0, ts);
+    }
+    
+    /**
+     * End the construction of a test method.
+     * <p>
+     * This method is responsible for actually created the source code for a
+     * just-recorded test method.
+     * 
+     * @param pmf   the PkgMgrFrame this is all occurring in
+     * @param ct    the ClassTarget of the unit test class
+     * @param name  the name of the test method we are writing out
+     */
+    public void doEndMakeTestCase(PkgMgrFrame pmf, ClassTarget ct, String name)
+    {
+        Editor ed = ct.getEditor();
+        String ts = getIndentString();
+        try {
+            Charset charset = pmf.getProject().getProjectCharset();
+            UnitTestAnalyzer uta = analyzeUnitTest(ct, charset);
+
+            SourceSpan existingSpan = uta.getMethodBlockSpan(name);
+
+            if (existingSpan != null) {
+                // replace this method (don't replace the method header!)
+                ed.setSelection(existingSpan.getStartLine(), existingSpan.getStartColumn(),
+                                  existingSpan.getEndLine(), existingSpan.getEndColumn());
+                ed.insertText("{\n" + pmf.getObjectBench().getTestMethod(ts + ts) + ts + "}", false);
+            }
+            else {
+                // insert a complete method
+                SourceLocation methodInsert = uta.getNewMethodInsertLocation();
+
+                if (methodInsert != null) {
+                    ed.setSelection(methodInsert.getLine(), methodInsert.getColumn(), 1);
+                    if (isJunit4) {
+                        ed.insertText("\n" + ts + "@Test\n" + ts + "public void " + name + "()\n" + ts + "{\n"
+                                + pmf.getObjectBench().getTestMethod(ts + ts) + ts + "}\n}\n", false);
+                    }
+                    else {
+                        ed.insertText("\n" + ts + "public void " + name + "()\n" + ts + "{\n"
+                                + pmf.getObjectBench().getTestMethod(ts + ts) + ts + "}\n}\n", false);
+                    }
+                }
+            }
+            
+            ed.save();
+        }
+        catch (IOException ioe) {
+            PkgMgrFrame.showMessageWithText(pmf.getPackage(), "generic-file-save-error", ioe.getLocalizedMessage());
+        }
+    }
+    
+    /**
+     * Turn the fixture declared in a unit test class into a set of
+     * objects on the object bench.
+     * 
+     * @param pmf  the PkgMgrFrame that will hold the object bench
+     * @param ct   the ClassTarget of the unit test class
+     */
+    public void doFixtureToBench(PkgMgrFrame pmf, ClassTarget ct)
+    {
+        Editor ed = ct.getEditor();
+
+        // our first step is to save all the existing code that creates the
+        // fixture into a special invoker record
+        // this can then be used to recreate this fixture from the object
+        // bench if needed
+        ExistingFixtureInvokerRecord existing = new ExistingFixtureInvokerRecord();
+        
+        try {
+            Charset charset = pmf.getProject().getProjectCharset();
+            UnitTestAnalyzer uta = analyzeUnitTest(ct, charset);
+
+            // iterate through all the declarations of fields (fixture items) in the class
+            List<SourceSpan> fixtureSpans = uta.getFieldSpans();
+            ListIterator<SourceSpan> it = fixtureSpans.listIterator();
+                
+            while(it.hasNext()) {
+                SourceSpan variableSpan = it.next();
+                String fieldDecl = ed.getText(variableSpan.getStartLocation(), variableSpan.getEndLocation()); 
+                existing.addFieldDeclaration(fieldDecl);
+            }
+
+            // find the source code of the "setUp" method
+            SourceSpan setUpSpan = uta.getMethodBlockSpan("setUp");
+
+            if (setUpSpan != null) {
+                String setUpWithBrackets = ed.getText(setUpSpan.getStartLocation(), setUpSpan.getEndLocation());
+                // copy everything between the opening { and the final }
+                String setUpWithoutBrackets = 
+                        setUpWithBrackets.substring(setUpWithBrackets.indexOf('{') + 1,
+                                                    setUpWithBrackets.lastIndexOf('}')).trim();
+                existing.setSetupMethod(setUpWithoutBrackets);
+            }
+            
+        }
+        catch (IOException ioe) {
+            PkgMgrFrame.showMessageWithText(pmf.getPackage(), "generic-file-save-error", ioe.getLocalizedMessage());
+        }
+        
+        runTestSetup(pmf, ct, true);
+        
+        pmf.getObjectBench().addInteraction(existing);
+    }   
+    
+    /**
+     * Convert the objects on the object bench into a test fixture.
+     */
+    public void doBenchToFixture(PkgMgrFrame pmf, ClassTarget ct)
+    {
+        if(pmf.getObjectBench().getObjectCount() == 0) {
+            return;
+        }
+                
+        Editor ed = ct.getEditor();
+        try {
+            Charset charset = pmf.getProject().getProjectCharset();
+            UnitTestAnalyzer uta = analyzeUnitTest(ct, charset);
+
+            // find all the fields declared in this unit test class
+            List<SourceSpan> variables = uta.getFieldSpans();
+            
+            // if we already have fields, ask if we are sure we want to get rid of them
+            if (variables != null && variables.size() > 0) {
+                if (DialogManager.askQuestion(null, "unittest-fixture-present") == 1) {
+                    return;
+                }
+            }
+
+            // if we have fields, we need to nuke them
+            // we need to make sure we delete these in reverse order (from the last
+            // field to the first) or else when we delete them, we change the line
+            // numbers for the following ones
+            if (variables != null) {
+                // start iterating from the last element
+                ListIterator<SourceSpan> it = variables.listIterator(variables.size());
+                
+                while(it.hasPrevious()) {
+                    SourceSpan variableSpan = (SourceSpan) it.previous();
+                    
+                    ed.setSelection(variableSpan.getStartLine(), variableSpan.getStartColumn(),
+                                     variableSpan.getEndLine(), variableSpan.getEndColumn());
+                    ed.insertText("", false);
+                }
+                
+                // to get correct locations for rewriting setUp(), we need to reparse
+                uta = analyzeUnitTest(ct, charset);
+            }
+
+            // find a location to insert new methods
+            SourceLocation fixtureInsertLocation = uta.getFixtureInsertLocation();
+            
+            // sanity check.. this shouldn't ever be null but if it is, lets not
+            // make it worse by trying to edit the source
+            if (fixtureInsertLocation == null) {
+                return;
+            }
+            
+            {
+                List<String> names = new ArrayList<String>();
+                for (ObjectWrapper obj : pmf.getObjectBench().getObjects())
+                {
+                    names.add(obj.getName());
+                }
+            }
+            
+            // find the curly brackets for the setUp() method
+            SourceSpan setupSpan = uta.getMethodBlockSpan("setUp");
+
+            String ts = getIndentString();
+            
+            // rewrite the setUp() method of the unit test (if it exists)
+            if (setupSpan != null) {
+                ed.setSelection(setupSpan.getStartLine(), setupSpan.getStartColumn(),
+                                 setupSpan.getEndLine(), setupSpan.getEndColumn());
+            } else {
+                // otherwise, we will be inserting a brand new setUp() method
+                ed.setSelection(fixtureInsertLocation.getLine(),
+                                fixtureInsertLocation.getColumn(), 1);
+                if (isJunit4) {
+                    ed.insertText("{\n" + ts + "@Before\n" + ts + "public void setUp()\n" + ts, false);
+                }
+                else {
+                    ed.insertText("{\n" + ts + "public void setUp()\n" + ts, false);
+                }
+            }
+            
+            // insert the code for our setUp() method
+            ed.insertText("{\n" + pmf.getObjectBench().getFixtureSetup(ts + ts)
+                                + ts + "}", false);
+
+            // insert our new fixture declarations
+            ed.setSelection(fixtureInsertLocation.getLine(),
+                             fixtureInsertLocation.getColumn(), 1);
+                
+            ed.insertText("{\n" + pmf.getObjectBench().getFixtureDeclaration(ts), false);
+            ed.save();
+        }
+        catch (IOException ioe) {
+            PkgMgrFrame.showMessageWithText(pmf.getPackage(),
+                    "generic-file-save-error", ioe.getLocalizedMessage());
+        }
+        
+        pmf.getPackage().compileQuiet(ct);
+        
+        pmf.getProject().removeClassLoader();
+        pmf.getProject().newRemoteClassLoaderLeavingBreakpoints();
+    }
+    
+    /**
+     * A base class for all our actions that run on targets.
+     */
+    private abstract class TargetAbstractAction extends AbstractAction
+    {
+        protected Target t;
+        protected PackageEditor ped;
+
+        public TargetAbstractAction(String name, PackageEditor ped, Target t)
+        {
+            super(name);
+            this.ped = ped;
+            this.t = t;
+        }
+    }
+
+    /**
+     * A TestAction is an action that causes a JUnit test to be run on a class.
+     * If testName is not provided, it is set to null which means that the whole
+     * test class is run; otherwise it refers to a test method that should be run
+     * individually.
+     */
+    private class TestAction extends TargetAbstractAction
+    {
+        private String testName;
+
+        public TestAction(String actionName, PackageEditor ped, Target t)
+        {
+            super(actionName, ped, t);
+            this.testName = null;
+        }
+                    
+        public TestAction(String actionName, PackageEditor ped, Target t, String testName)
+        {
+            super(actionName, ped, t);
+            this.testName = testName;
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            ped.raiseRunTargetEvent(t, testName);
+        }
+    }
+
+    private class MakeTestCaseAction extends TargetAbstractAction
+    {
+        public MakeTestCaseAction(String name, PackageEditor ped, Target t)
+        {
+            super(name, ped, t);
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            ped.raiseMakeTestCaseEvent(t);
+        }
+    }
+
+    private class BenchToFixtureAction extends TargetAbstractAction
+    {
+        public BenchToFixtureAction(String name, PackageEditor ped, Target t)
+        {
+            super(name, ped, t);
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            ped.raiseBenchToFixtureEvent(t);
+        }
+    }
+
+    private class FixtureToBenchAction extends TargetAbstractAction
+    {
+        public FixtureToBenchAction(String name, PackageEditor ped, Target t)
+        {
+            super(name, ped, t);
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            ped.raiseFixtureToBenchEvent(t);
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/InterfacePanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/InterfacePanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..28f84c5c2fcd83794f2d932165e96d0d9604e35c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/InterfacePanel.java
@@ -0,0 +1,451 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.prefmgr;
+
+import java.awt.BorderLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.utility.filefilter.DirectoryFilter;
+
+/**
+ * "Interface" preference panel. Settings for what to show (teamwork, testing tools etc)
+ * and interface language.
+ * 
+ * @author Davin McCall
+ */
+public class InterfacePanel extends JPanel
+        implements PrefPanelListener, ActionListener, ItemListener
+{
+    private static final String toolkitDir = "bluej.javame.toolkit.dir";
+
+    private JCheckBox showTestBox;
+    private JCheckBox showTeamBox;
+    private JCheckBox showJavaMEBox;
+    private JLabel toolkitDirLabel;
+    private JTextField toolkitDirField;
+    private JButton toolkitBrowseButton;
+    
+    private ArrayList<String> allLangsInternal;
+    private JComboBox langDropdown;
+    
+    public InterfacePanel()
+    {
+        JPanel box = new JPanel();
+        box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
+        add(box);
+        
+        setBorder(BlueJTheme.generalBorder);
+
+        box.add(Box.createVerticalGlue());
+
+        if(!Config.isGreenfoot()) {
+            box.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+
+            JPanel testPanel = new JPanel(new GridLayout(0,1,0,0));
+            {
+                testPanel.setBorder(BorderFactory.createCompoundBorder(
+                                              BorderFactory.createTitledBorder(
+                                                     Config.getString("prefmgr.misc.tools.title")),
+                                              BlueJTheme.generalBorder));
+                testPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                showTestBox = new JCheckBox(Config.getString("prefmgr.misc.showTesting"));
+                testPanel.add(showTestBox);
+
+                showTeamBox = new JCheckBox(Config.getString("prefmgr.misc.showTeam"));
+                testPanel.add(showTeamBox);
+                
+                showJavaMEBox = new JCheckBox(Config.getString("prefmgr.misc.showJavaME"));
+                testPanel.add(showJavaMEBox);
+                
+                JPanel toolkitPanel = new JPanel( new BorderLayout( 5, 0 ) );
+                {
+                    toolkitDirLabel = new JLabel( Config.getString( "prefmgr.misc.wtk.dir.label" ) );
+                    toolkitDirField = new JTextField(15);
+                    toolkitBrowseButton = new JButton( Config.getString( "prefmgr.misc.wtk.button" ) );
+                    toolkitPanel.add( toolkitDirLabel,     BorderLayout.WEST   );
+                    toolkitPanel.add( toolkitDirField,     BorderLayout.CENTER );
+                    toolkitPanel.add( toolkitBrowseButton, BorderLayout.EAST   );                   
+                }
+                testPanel.add( toolkitPanel );
+            }
+            box.add(testPanel);
+
+            box.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+            
+            showJavaMEBox.addItemListener( this ); 
+            toolkitBrowseButton.addActionListener( this );
+        }
+        
+        JPanel langPanel = new JPanel();
+        {
+            langPanel.setBorder(BorderFactory.createCompoundBorder(
+                    BorderFactory.createTitledBorder(
+                            Config.getString("prefmgr.interface.language.title")),
+                            BlueJTheme.generalBorder)
+                    );
+            langPanel.setAlignmentX(LEFT_ALIGNMENT);
+            langPanel.setLayout(new BoxLayout(langPanel, BoxLayout.Y_AXIS));
+            
+            Box langSelBox = new Box(BoxLayout.X_AXIS);
+            {
+                langSelBox.add(new JLabel(Config.getString("prefmgr.interface.language") + ":"));
+                langSelBox.add(Box.createHorizontalStrut(BlueJTheme.componentSpacingSmall));
+
+                allLangsInternal = new ArrayList<String>();
+                List<String> allLangsReadable = new ArrayList<String>();
+                
+                for (int i = 1; ; i++) {
+                    String langString = Config.getPropString("bluej.language" + i, null);
+                    if (langString == null) {
+                        break;
+                    }
+                    
+                    int colonIndex = langString.indexOf(':');
+                    if (colonIndex == -1) {
+                        continue; // don't understand this one
+                    }
+                    
+                    allLangsInternal.add(langString.substring(0, colonIndex));
+                    allLangsReadable.add(langString.substring(colonIndex + 1));
+                }
+                
+                String [] langs = new String[allLangsReadable.size()];
+                allLangsReadable.toArray(langs);
+                
+
+                langDropdown = new JComboBox(langs);
+                langSelBox.add(langDropdown);
+            }
+            langSelBox.setAlignmentX(0.0f);
+            langPanel.add(langSelBox);
+            
+            langPanel.add(Box.createVerticalStrut(BlueJTheme.componentSpacingSmall));
+            
+            JLabel t = new JLabel(Config.getString("prefmgr.interface.language.restart"));
+            t.setAlignmentX(0.0f);
+            langPanel.add(t);
+        }
+        box.add(langPanel);        
+    }
+    
+    @Override
+    public void beginEditing()
+    {
+        if(!Config.isGreenfoot()) {
+            showTestBox.setSelected(PrefMgr.getFlag(PrefMgr.SHOW_TEST_TOOLS));
+            showTeamBox.setSelected(PrefMgr.getFlag(PrefMgr.SHOW_TEAM_TOOLS));
+            showJavaMEBox.setSelected(PrefMgr.getFlag(PrefMgr.SHOW_JAVAME_TOOLS));
+                        
+            if ( showJavaMEBox.isSelected( ) ) {
+                toolkitDirField.setText( Config.getPropString( toolkitDir, "" ) );
+                enableToolkitPanel( true ); 
+            } else {
+                toolkitDirField.setText( "" );
+                enableToolkitPanel( false );   
+            }
+        }
+
+        String currentLang = Config.getPropString("bluej.language", "english");
+        int curLangIndex = allLangsInternal.indexOf(currentLang);
+        if (curLangIndex == -1) {
+            curLangIndex = 0;
+        }
+        langDropdown.setSelectedIndex(curLangIndex);
+    }
+
+    /**
+     * Gray out or not the components in the toolkit panel depending on the argument passed.
+     */    
+    private void enableToolkitPanel( boolean b ) 
+    {
+        toolkitDirLabel.setEnabled( b );
+        toolkitDirField.setEnabled( b );
+        toolkitBrowseButton.setEnabled( b );
+    }
+
+    @Override
+    public void commitEditing()
+    {
+        if(!Config.isGreenfoot()) {
+            PrefMgr.setFlag(PrefMgr.SHOW_TEST_TOOLS, showTestBox.isSelected());
+            PrefMgr.setFlag(PrefMgr.SHOW_TEAM_TOOLS, showTeamBox.isSelected());
+            PrefMgr.setFlag(PrefMgr.SHOW_JAVAME_TOOLS, showJavaMEBox.isSelected());            
+
+            PkgMgrFrame.updateTestingStatus();
+            PkgMgrFrame.updateTeamStatus();
+            PkgMgrFrame.updateJavaMEstatus(); 
+            
+            String tkDir = toolkitDirField.getText(); 
+            if (! tkDir.equals( "" )) {
+                Config.putPropString(toolkitDir, tkDir);
+            }
+        }
+        
+        Config.putPropString("bluej.language", allLangsInternal.get(langDropdown.getSelectedIndex()));
+    }
+    
+    @Override
+    public void revertEditing()
+    {
+    }
+    
+    /**
+     * Called when user ticks or unticks the 'Show Java ME controls' checkbox. 
+     * When ticked, we automatically try to find the location of the Toolkit, 
+     * and if we can't find it we pop up a file chooser. When unticked, we
+     * gray out the Wireless Toolkit panel.
+     */
+    @Override
+    public void itemStateChanged( ItemEvent event )
+    {
+        if ( event.getStateChange( ) == ItemEvent.SELECTED ) 
+        {       
+            enableToolkitPanel( true );
+            String toolkitDirectory = tryToFindToolkit( );
+            if ( toolkitDirectory.equals( "" ) )
+            {
+                letUserChooseToolkitDir();
+                toolkitDirectory = toolkitDirField.getText().trim();
+            }
+            else
+            {   //we found a toolkit
+                toolkitDirField.setText( toolkitDirectory );
+            }
+
+            /* Check that names of core library Jar files are valid.
+             * Interim fix for #266. We should really provide a GUI to
+             * select needed libraries by API-name on a per-project basis.
+             */
+            checkCoreLibraryJars(toolkitDirectory);
+        } 
+        else  //checkbox was deselected
+        {
+            enableToolkitPanel( false );
+            toolkitDirField.setText( "" );  
+        }
+    }
+    
+    /**
+     * Find the Wireless Toolkit. In Windows we search all the filesystem roots.
+     * In other systems (Linux, that is) we search the directories in the
+     * initializer list of array 'roots' listed below. Note that we search only 
+     * one level down from each root. That is, we can find C:\WTK2.5.1 but not
+     * C:\someDirectory\WTK2.5.1, or /usr/local/WTK2.5.1 but not
+     * /usr/local/mydir/WTK2.5.1
+     * 
+     * @return String containing our first guess or "" if toolkit not found.
+     */    
+    private String tryToFindToolkit( )
+    {  
+        File[] roots = { new File( System.getProperty( "user.home" ) ),
+                         new File( "/usr/local"                      ),
+                         new File( "/usr/lib"                        ), 
+                        };   
+        
+        if (Config.isWinOS()) {
+            roots = File.listRoots( );
+        }
+
+        File[] dirs;
+        for (int i = 0; i < roots.length ; i++)
+        {
+            dirs = roots[i].listFiles(new DirectoryFilter());
+            if ( dirs != null) {
+                for ( int j = 0; j < dirs.length ; j++ ) { 
+                    if (isToolkitDirectory(dirs[j])) {
+                        return dirs[j].toString();
+                    }
+                }
+            }
+        }
+        return "";   
+    }
+    
+    /**
+     * Check whether a directory fulfills the requirements of being a Wireless
+     * Toolkit. The requirements are:
+     *   1. That the bin, lib, and docs directories be all present.
+     *   2. That there is an emulator file under the bin directory.
+     * These were taken from the Unified Emulator Interface specification, 
+     * version 1.0.2, dated Apr 2006, http://java.sun.com/j2me/docs/uei_specs.pdf
+     * 
+     * @param  dirToCheck   directory to check
+     * @return true if it fulfills requirements false otherwise
+     */ 
+    private boolean isToolkitDirectory(File dirToCheck)
+    {  
+         File file = new File(dirToCheck, "bin");
+         if (file.isDirectory())
+         {   
+             File emulatorInLinux   = new File(file, "emulator");
+             File emulatorInWindows = new File(file, "emulator.exe");
+             if ((! emulatorInWindows.exists())  &&  (! emulatorInLinux.exists())) {
+                 return false; 
+             }
+         }
+         else {
+             return false;
+         }
+             
+         file = new File(dirToCheck, "lib");
+         File anotherFile = new File(dirToCheck, "docs");
+         return file.isDirectory() && anotherFile.isDirectory();
+    }    
+    
+    /**
+     * Check that the Jar files named in the Java ME corelibraries property
+     * actually exist in the selected toolkit (the names vary with toolkit). If
+     * they don't exist, use the Jar files' Manifest properties to find the Jar
+     * containing the MIDP 2.0 and CLDC 1.1 libraries, which are the documented
+     * default core libraries, and write the Jar file names back into the property.
+     * @param tkdir The root folder name for the Wireless toolkit
+     */
+    private void checkCoreLibraryJars(String tkdir)
+    {
+        String libs = Config.getPropString("bluej.javame.corelibraries", null);
+
+        // Check to see that all of the Jar files named in the
+        // corelibraries property exist
+        String libDir = tkdir + File.separator + "lib" + File.separator;
+        StringTokenizer st = new StringTokenizer( libs );
+        boolean allFilesExist = true; // so far
+        while ( st.hasMoreTokens( ) && allFilesExist) {
+            allFilesExist = new File( libDir + st.nextToken( ) ).exists();
+        }
+
+        // If they do, assume that they are correct
+        if(allFilesExist) return;
+
+        // Look at all the Jar files in the toolkit's lib folder
+        // To find the ones which implement CLDC 1.1 and MIDP 2.0
+
+        File [] list = new File(libDir).listFiles(
+            new FileFilter() {
+                public boolean accept(File pathname) { return pathname.getName().endsWith(".jar"); }
+            }
+        );
+
+        File theCLDCJar = null;
+        File theMIDPJar = null;
+        for(File f : list) {
+            Attributes manifest;
+            try {
+                manifest = new JarFile(f).getManifest().getMainAttributes();
+            } catch (IOException ex) {
+                continue;   // Malformed Jar?
+            }
+            String API = manifest.getValue("API");
+            String version = manifest.getValue("API-Specification-Version");
+            if(API == null || version == null) continue;
+
+            if(API.equals("CLDC") && version.equals("1.1"))
+            {
+                theCLDCJar = f;
+                if(theMIDPJar != null) break;
+            }
+            else if(API.equals("MIDP") && version.equals("2.0"))
+            {
+                theMIDPJar = f;
+                if(theCLDCJar != null) break;
+            }
+        }
+
+        if(theMIDPJar == null || theCLDCJar == null)
+        {
+            /* Oops. Can't find the needed Jars. Just leave things as they are
+             * so that the (wrong) names in the property are the thing that needs
+             * fixing-by-hand.
+             */
+            return;
+        }
+
+        /* Write the newly discovered names back into the property string
+         * Anyone caching these values won't get the update, but that's currently
+         * only the BPClassLoader, and hence only open projects. That's acceptable
+         * as this action is a global setting.
+         */
+        String prop = theCLDCJar.getName() + " " + theMIDPJar.getName();
+        Config.putPropString("bluej.javame.corelibraries", prop);
+    }
+    
+    /**
+     * Called when the Browse button is pressed.
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        letUserChooseToolkitDir();
+    }
+    
+    /**
+     * Pop up a file chooser to let user specify Toolkit location. 
+     */
+    private void letUserChooseToolkitDir()
+    {
+        String toolkitDirectory = "";  
+        JFileChooser chooser = new JFileChooser();                   
+        chooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY );
+        chooser.setDialogTitle( Config.getString( "prefmgr.misc.filechooser.title" ) );
+                
+        int returnVal = chooser.showOpenDialog( getParent( ) ); 
+        if (returnVal == JFileChooser.APPROVE_OPTION)
+        {
+            toolkitDirectory = chooser.getSelectedFile().toString();
+            toolkitDirField.setText(toolkitDirectory);  
+        }
+        else if (returnVal == JFileChooser.CANCEL_OPTION) 
+        {
+            String s = toolkitDirField.getText().trim();
+            if (s.equals(""))
+            {
+                showJavaMEBox.setSelected(false);
+                enableToolkitPanel(false);
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/MiscPrefPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/MiscPrefPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..650babea94155d45172ab15de50e9e637660fa73
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/MiscPrefPanel.java
@@ -0,0 +1,237 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.prefmgr;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.event.KeyEvent;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * A PrefPanel subclass to allow the user to interactively edit
+ * various miscellaneous settings
+ *
+ * @author  Andrew Patterson
+ */
+public class MiscPrefPanel extends JPanel 
+                           implements PrefPanelListener
+{
+    private static final String bluejJdkURL = "bluej.url.javaStdLib";
+    private static final String greenfootJdkURL = "greenfoot.url.javaStdLib";
+   
+    private JTextField jdkURLField;
+    private JCheckBox linkToLibBox;
+    private JCheckBox showUncheckedBox; // show "unchecked" compiler warning
+    private String jdkURLPropertyName;
+    private JTextField playerNameField;
+     
+    /**
+     * Setup the UI for the dialog and event handlers for the buttons.
+     */
+    public MiscPrefPanel()
+    {
+        if(Config.isGreenfoot()) {
+            jdkURLPropertyName = greenfootJdkURL;
+        }
+        else {
+            jdkURLPropertyName = bluejJdkURL;
+        }
+        JPanel box = new JPanel();
+        box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
+        add(box);
+        
+        setBorder(BlueJTheme.generalBorder);
+
+        box.add(Box.createVerticalGlue());
+
+        box.add(makeDocumentationPanel());
+        
+        if (Config.isGreenfoot()) {
+            box.add(makePlayerNamePanel());
+        }
+        else {
+            box.add(makeVMPanel());
+        }
+        box.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+    }
+
+    private JPanel makeVMPanel()
+    {
+        JPanel vmPanel = new JPanel(new GridLayout(0,1,0,0));
+        {
+            vmPanel.setBorder(BorderFactory.createCompoundBorder(
+                                          BorderFactory.createTitledBorder(
+                                                 Config.getString("prefmgr.misc.vm.title")),
+                                          BlueJTheme.generalBorder));
+            vmPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+            showUncheckedBox = new JCheckBox(Config.getString("prefmgr.misc.showUnchecked"));
+            if (Config.isJava15()) {
+                // "unchecked" warnings only occur in Java 5.
+                vmPanel.add(showUncheckedBox);
+            }
+        }
+        return vmPanel;
+    }
+
+    private JPanel makePlayerNamePanel()
+    {
+        JPanel playerNamePanel = new JPanel();
+                  
+        playerNamePanel.setLayout(new BoxLayout(playerNamePanel, BoxLayout.Y_AXIS));
+        String playerNameTitle = Config.getString("prefmgr.misc.playername.title");
+        playerNamePanel.setBorder(BorderFactory.createCompoundBorder(
+                                    BorderFactory.createTitledBorder(playerNameTitle),
+                                    BlueJTheme.generalBorder));
+        playerNamePanel.setAlignmentX(LEFT_ALIGNMENT);
+        
+        // get Accelerator text
+        String shortcutText = " ";
+        KeyStroke accelerator = Config.GREENFOOT_SET_PLAYER_NAME_SHORTCUT;
+        if (accelerator != null) {
+            int modifiers = accelerator.getModifiers();
+            if (modifiers > 0) {
+                shortcutText += KeyEvent.getKeyModifiersText(modifiers);
+                shortcutText += Config.isMacOS() ? "" : "+";
+            }
+
+            int keyCode = accelerator.getKeyCode();
+            if (keyCode != 0) {
+                shortcutText += KeyEvent.getKeyText(keyCode);
+            } else {
+                shortcutText += accelerator.getKeyChar();
+            }
+        }
+        
+        playerNamePanel.add(new JLabel(Config.getString("playername.dialog.help")));
+        
+        playerNameField = new JTextField(Config.getPropString("extensions.rmiextension.RMIExtension.settings.greenfoot.player.name", "Player"), 20);
+        playerNameField.setMaximumSize(playerNameField.getPreferredSize());
+        JPanel namePanel = new JPanel();
+        namePanel.setLayout(new BoxLayout(namePanel, BoxLayout.X_AXIS));
+        namePanel.add(playerNameField);
+        namePanel.add(Box.createHorizontalGlue());
+        playerNamePanel.add(namePanel);
+        
+        
+        JLabel playerNameNote = new JLabel(
+                Config.getString("prefmgr.misc.playerNameNote") + shortcutText);
+        Font smallFont = playerNameNote.getFont().deriveFont(10);
+        playerNameNote.setFont(smallFont);
+        playerNamePanel.add(playerNameNote);
+        return playerNamePanel;
+    }
+
+    private JPanel makeDocumentationPanel()
+    {
+        JPanel docPanel = new JPanel();
+        {
+            docPanel.setLayout(new BoxLayout(docPanel, BoxLayout.Y_AXIS));
+            String docTitle = Config.getString("prefmgr.misc.documentation.title");
+            docPanel.setBorder(BorderFactory.createCompoundBorder(
+                                        BorderFactory.createTitledBorder(docTitle),
+                                        BlueJTheme.generalBorder));
+            docPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+            JPanel urlPanel = new JPanel(new BorderLayout(5, 0));
+            {
+                urlPanel.add(new JLabel(Config.getString("prefmgr.misc.jdkurlpath")), 
+                             BorderLayout.WEST);
+                jdkURLField = new JTextField(32);
+                urlPanel.add(jdkURLField, BorderLayout.CENTER);
+            }
+            urlPanel.setAlignmentX(LEFT_ALIGNMENT);
+            docPanel.add(urlPanel);
+
+            docPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+
+            linkToLibBox = new JCheckBox(Config.getString("prefmgr.misc.linkToLib"));
+            linkToLibBox.setAlignmentX(LEFT_ALIGNMENT);
+            docPanel.add(linkToLibBox);
+
+            docPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+
+            JLabel linkToLibNoteLine1 = new JLabel(
+                              Config.getString("prefmgr.misc.linkToLibNoteLine1"));
+            Font smallFont = linkToLibNoteLine1.getFont().deriveFont(10);
+            linkToLibNoteLine1.setFont(smallFont);
+            linkToLibNoteLine1.setAlignmentX(LEFT_ALIGNMENT);
+            docPanel.add(linkToLibNoteLine1);
+
+            JLabel linkToLibNoteLine2 = new JLabel(
+                              Config.getString("prefmgr.misc.linkToLibNoteLine2"));
+            linkToLibNoteLine2.setFont(smallFont);
+            linkToLibNoteLine2.setAlignmentX(LEFT_ALIGNMENT);
+            docPanel.add(linkToLibNoteLine2);
+        }
+        return docPanel;
+    }
+
+    public void beginEditing()
+    {
+        linkToLibBox.setSelected(PrefMgr.getFlag(PrefMgr.LINK_LIB));
+        jdkURLField.setText(Config.getPropString(jdkURLPropertyName));
+        if(!Config.isGreenfoot()) {
+            showUncheckedBox.setSelected(PrefMgr.getFlag(PrefMgr.SHOW_UNCHECKED));
+        }
+        else
+        {
+            playerNameField.setText(Config.getPropString("extensions.rmiextension.RMIExtension.settings.greenfoot.player.name", "Player"));
+        }
+    }
+
+    public void revertEditing()
+    {
+    }
+
+    public void commitEditing()
+    {
+        PrefMgr.setFlag(PrefMgr.LINK_LIB, linkToLibBox.isSelected());
+        if(!Config.isGreenfoot()) {
+            PrefMgr.setFlag(PrefMgr.SHOW_UNCHECKED, showUncheckedBox.isSelected());
+
+            PkgMgrFrame.updateTestingStatus();
+            PkgMgrFrame.updateTeamStatus();
+            PkgMgrFrame.updateJavaMEstatus(); 
+        }
+        
+        String jdkURL = jdkURLField.getText();
+        Config.putPropString(jdkURLPropertyName, jdkURL);
+
+        if (Config.isGreenfoot()) {
+            Config.putPropString("extensions.rmiextension.RMIExtension.settings.greenfoot.player.name", playerNameField.getText());
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/PrefMgr.java b/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/PrefMgr.java
new file mode 100644
index 0000000000000000000000000000000000000000..493a024bf524c4ac725ceed48eff5cf18e413d3d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/PrefMgr.java
@@ -0,0 +1,374 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.prefmgr;
+
+import java.awt.*;
+import java.util.List;
+import java.util.*;
+
+import bluej.Config;
+import bluej.editor.EditorManager;
+import bluej.editor.moe.BlueJSyntaxView;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.pkgmgr.Project;
+
+/**
+ * A class to manage the user editable preferences
+ * settings.
+ *
+ * <p>Note that this is a singleton class. There can be only one
+ * instance of PrefMgr at any time.
+ *
+ * @author  Andrew Patterson
+ */
+public class PrefMgr
+{
+    // publicly accessible names for flags
+    public static final String HILIGHTING = "bluej.editor.syntaxHilighting";
+    public static final String AUTO_INDENT = "bluej.editor.autoIndent";
+    public static final String LINENUMBERS = "bluej.editor.displayLineNumbers";
+    public static final String MAKE_BACKUP = "bluej.editor.makeBackup";
+    public static final String MATCH_BRACKETS = "bluej.editor.matchBrackets";
+    public static final String LINK_LIB = "doctool.linkToStandardLib";
+    public static final String SHOW_TEST_TOOLS = "bluej.testing.showtools";
+    public static final String SHOW_TEAM_TOOLS = "bluej.teamwork.showtools";
+    public static final String SHOW_JAVAME_TOOLS = "bluej.javame.showtools";   
+    public static final String SHOW_TEXT_EVAL = "bluej.startWithTextEval";
+    public static final String SHOW_UNCHECKED = "bluej.compiler.showunchecked";
+    public static final String SCOPE_HIGHLIGHTING_STRENGTH = "bluej.editor.scopeHilightingStrength";
+    public static final String NAVIVIEW_EXPANDED="bluej.naviviewExpanded.default";
+    
+    public static final String USE_THEMES = "bluej.useTheme";
+    // font property names
+    private static final String editorFontPropertyName = "bluej.editor.font";
+    private static final String editorMacFontPropertyName = "bluej.editor.MacOS.font";
+    private static final String editorFontSizePropertyName = "bluej.editor.fontsize";
+
+    // other constants
+    private static final int NUM_RECENT_PROJECTS = Config.getPropInteger("bluej.numberOfRecentProjects", 12);
+    
+    // preference variables: FONTS
+    private static int fontSize;
+    private static int targetFontSize;
+
+    private static Font normalFont;
+    private static Font targetFont;
+
+    // initialised by a call to setMenuFontSize()
+    private static int menuFontSize;
+    private static Font menuFont;
+    private static Font popupMenuFont;
+    private static Font italicMenuFont;
+
+    // initialised by a call to setEditorFontSize()
+    private static int editorFontSize;
+    private static Font editorStandardFont;
+
+    // preference variables: (other than fonts)
+    
+    /** transparency of the scope highlighting */
+    private static int highlightStrength; 
+    
+    // last value of naviviewExpanded
+    private static boolean isNaviviewExpanded=true;
+    
+    // the current project directory
+    private static String projectDirectory;
+
+    // list of recently used projects
+    private static List<String> recentProjects;
+    
+    // flags are all boolean preferences
+    private static HashMap<String,String> flags = new HashMap<String,String>();
+
+    /**
+     * Initialise the preference manager. Font information is loaded from bluej.defs,
+     * defaults for other prefs are loaded from bluej.defs.
+     */
+    static {
+        //set up fonts
+        initEditorFontSize(Config.getPropInteger(editorFontSizePropertyName, 12));
+
+        //bluej menu font
+        menuFontSize = Config.getPropInteger("bluej.menu.fontsize", 12);
+        menuFont = Config.getFont("bluej.menu.font", "SansSerif", menuFontSize);
+        
+        // popup menus are not permitted to be bold (MIK style guide) at present
+        // make popup menus same font as drop down menus
+        italicMenuFont = menuFont.deriveFont(Font.ITALIC);
+        popupMenuFont = menuFont.deriveFont(Font.PLAIN);
+
+        //standard font for UI components
+        fontSize = Config.getPropInteger("bluej.fontsize", 12);
+        normalFont = Config.getFont("bluej.font", "SansSerif", fontSize);
+
+        targetFontSize = Config.getPropInteger("bluej.target.fontsize", 12);
+        targetFont = Config.getFont("bluej.target.font", "SansSerif-bold", targetFontSize);
+        
+        // preferences other than fonts:
+        highlightStrength = Config.getPropInteger(SCOPE_HIGHLIGHTING_STRENGTH, 20);
+        isNaviviewExpanded=Boolean.parseBoolean(Config.getPropString(NAVIVIEW_EXPANDED, "true"));
+        
+        projectDirectory = Config.getPropString("bluej.projectPath");
+        recentProjects = readRecentProjects();
+        
+        flags.put(HILIGHTING, Config.getPropString(HILIGHTING, "true"));
+        flags.put(AUTO_INDENT, Config.getPropString(AUTO_INDENT, "false"));
+        flags.put(LINENUMBERS, Config.getPropString(LINENUMBERS, "false"));
+        flags.put(MAKE_BACKUP, Config.getPropString(MAKE_BACKUP, "false"));
+        flags.put(MATCH_BRACKETS, Config.getPropString(MATCH_BRACKETS, "true"));
+        flags.put(LINK_LIB, Config.getPropString(LINK_LIB, "true"));
+        flags.put(USE_THEMES, Config.getPropString(USE_THEMES, "false"));
+        flags.put(SHOW_TEST_TOOLS, Config.getPropString(SHOW_TEST_TOOLS, "false"));
+        flags.put(SHOW_TEAM_TOOLS, Config.getPropString(SHOW_TEAM_TOOLS, "false"));
+        flags.put(SHOW_JAVAME_TOOLS, Config.getPropString(SHOW_JAVAME_TOOLS, "false"));        
+        flags.put(SHOW_TEXT_EVAL, Config.getPropString(SHOW_TEXT_EVAL, "false"));
+        flags.put(SHOW_UNCHECKED, Config.getPropString(SHOW_UNCHECKED, "true"));
+    }
+
+    /**
+     * Private constructor to prevent instantiation
+     */
+    private PrefMgr()
+    {
+        
+    }
+    
+    // ----- system interface to read or set prefences: -----
+
+    public static String getProjectDirectory()
+    {
+        return projectDirectory;
+    }
+
+    public static void setProjectDirectory(String newDir)
+    {
+        projectDirectory = newDir;
+        Config.putPropString("bluej.projectPath", newDir);
+    }
+
+    public static List<String> getRecentProjects()
+    {
+        return recentProjects;
+    }
+    
+    public static void addRecentProject(String projectName)
+    {
+        if(projectName == null)
+            return;
+            
+        recentProjects.remove(projectName);
+        
+        if(recentProjects.size() == NUM_RECENT_PROJECTS)
+            recentProjects.remove(NUM_RECENT_PROJECTS-1);
+        
+        recentProjects.add(0, projectName);
+        
+        for(int i = 0; i < recentProjects.size(); i++) {
+            Config.putPropString("bluej.recentProject" + i, (String)recentProjects.get(i));
+        }
+    }
+    
+    public static Font getStandardFont()
+    {
+        return normalFont;
+    }
+
+    public static Font getStandoutFont()
+    {
+        return normalFont;
+    }
+
+    public static Font getStandardMenuFont()
+    {
+        return menuFont;
+    }
+
+    public static Font getStandoutMenuFont()
+    {
+        return italicMenuFont;
+    }
+    
+    public static Font getPopupMenuFont()
+    {
+        return popupMenuFont;   
+    }
+
+    public static Font getTargetFont()
+    {
+        return targetFont;        
+    }
+    
+    public static Font getStandardEditorFont()
+    {
+        return editorStandardFont;
+    }
+
+    /**
+     * Get the value for a flag. Flags are boolean preferences.
+     * 'flag' must be one of the flag names defined as public
+     * constants in this class.
+     */
+    public static boolean getFlag(String flag)
+    {
+        String value = (String)flags.get(flag);
+        if(value == null){
+            return false;
+        }
+        else
+            return value.equals("true");
+    }
+
+    /**
+     * Set a users preference flag (a boolean preference).
+     *
+     * @param flag    The name of the flag to set
+     * @param enabled The new value of the flag
+     */
+    public static void setFlag(String flag, boolean enabled)
+    {
+        String value = String.valueOf(enabled);
+        String systemDefault = Config.getDefaultPropString(flag, "");
+
+        if ((systemDefault.length() > 0) &&
+                (Boolean.valueOf(systemDefault).booleanValue() == enabled))
+            Config.removeProperty(flag);  // remove from user defaults
+        else
+            Config.putPropString(flag, value);
+
+        flags.put(flag, value);
+    }
+
+    // ----- end of system preference interface -----
+    
+    private static List<String> readRecentProjects()
+    {
+        List<String> projects = new ArrayList<String>(NUM_RECENT_PROJECTS);
+        
+        for(int i = 0; i < NUM_RECENT_PROJECTS; i++) {
+            String projectName = Config.getPropString("bluej.recentProject" + i, "");
+            if(projectName.length() > 0)
+                projects.add(projectName);
+        }
+        return projects;
+    }
+    
+    /**
+     * The following methods are protected and should only be accessed by the
+     * code which implements the various preferences dialog panels
+     */
+
+    /**
+     * Set the editor font size preference to a particular point size
+     *
+     * @param size  the size of the font
+     */
+    public static void setEditorFontSize(int size)
+    {
+        if (size > 0) {
+            initEditorFontSize(size);
+            EditorManager.getEditorManager().refreshAll();
+            Collection<Project> projects = Project.getProjects();
+            Iterator<Project> i = projects.iterator();
+            while (i.hasNext()) {
+                Project project = i.next();
+                if (project.hasTerminal()) {
+                    project.getTerminal().resetFont();
+                }
+            }
+            PkgMgrFrame [] frames = PkgMgrFrame.getAllFrames();
+            for (int j = 0; j < frames.length; j++) {
+                if(frames[j].getCodePad() != null) {
+                    frames[j].getCodePad().resetFontSize();
+                }
+            }
+        }
+    }
+    
+    /**
+     * Set up the editor font size, without informing various dependent components
+     * of a size change.
+     */
+    private static void initEditorFontSize(int size)
+    {
+        if (size > 0 && size != editorFontSize) {
+            editorFontSize = size;
+
+            Config.putPropInteger(editorFontSizePropertyName, size);
+
+            Font font;
+            if(Config.isMacOS()) {
+                font = Config.getFont(editorMacFontPropertyName, "Monaco", size);
+            }
+            else {
+                font = Config.getFont(editorFontPropertyName, "Monospaced", size);
+            }
+            editorStandardFont = font;
+        }
+    }
+    
+    /**
+     * Return the editor font size as an integer size
+     * (use getStandardEditorFont() if access to the actual font is required)
+     */
+    public static int getEditorFontSize()
+    {
+        return editorFontSize;
+    }
+    
+    public static int getScopeHighlightStrength()
+    {
+        return highlightStrength;
+    }
+
+    /**
+     * Sets the highlight strength in the configs
+     * @param strength representing light<->dark
+     */
+    public static void setScopeHighlightStrength(int strength)
+    {
+        highlightStrength = strength;
+        BlueJSyntaxView.setHighlightStrength(strength);
+        Config.putPropInteger(SCOPE_HIGHLIGHTING_STRENGTH, strength);
+    }
+    
+    /**
+     * Sets the value of the naviview to expanded/collapsed 
+     * to the local variable and to the configs
+     * @param expanded true if expanded; false if not
+     */
+    public static void setNaviviewExpanded(boolean expanded)
+    {
+        isNaviviewExpanded=expanded;
+        Config.putPropString(NAVIVIEW_EXPANDED, String.valueOf(expanded));
+    }
+    
+    /**
+     * Returns the value of whether the naviview is expanded/collapsed
+     * @return true if expanded; false if not
+     */
+    public static boolean getNaviviewExpanded()
+    {   
+        return isNaviviewExpanded;            
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/PrefMgrDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/PrefMgrDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8934f76046709b9920d7946cda7b49c90cf975e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/PrefMgrDialog.java
@@ -0,0 +1,268 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.prefmgr;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.ListIterator;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.classmgr.ClassMgrPrefPanel;
+import bluej.editor.moe.EditorPrefPanel;
+import bluej.editor.moe.KeyBindingsPanel;
+import bluej.extmgr.ExtensionPrefManager;
+import bluej.extmgr.ExtensionsManager;
+import bluej.utility.DialogManager;
+
+/**
+ * A JDialog subclass to allow the user to interactively edit
+ * preferences.
+ *
+ * <p>A singleton.
+ *
+ * @author  Andrew Patterson
+ * @author  Michael Kolling
+ */
+public class PrefMgrDialog extends JFrame
+{
+    private static PrefMgrDialog dialog = null;
+    
+    /** Indicates whether the dialog has been prepared for display. */
+    private boolean prepared = false;
+    
+    private KeyBindingsPanel kbPanel;
+
+    /**
+     * Show the preferences dialog.  The first argument should
+     * be null if you want the dialog to come up in the center
+     * of the screen.  Otherwise, the argument should be the
+     * component on top of which the dialog should appear.
+     *
+     * @param comp the parent component for the dialog.
+     */
+    public static void showDialog() {
+        getInstance().prepareDialog();
+        dialog.setVisible(true);
+    }
+
+  /**
+     * Show the preferences dialog.  The first argument should
+     * be null if you want the dialog to come up in the center
+     * of the screen.  Otherwise, the argument should be the
+     * component on top of which the dialog should appear.
+     *
+     * @param comp the parent component for the dialog.
+     * @param actiontable 
+     * @param categories 
+     * @param categoryIndex 
+     */
+    public static void showDialog(int paneNumber) {
+        dialog.prepareDialog();
+        dialog.selectTab(paneNumber);
+        dialog.setVisible(true);
+    }
+    /**
+     * Prepare this dialog for display.
+     */
+    private synchronized void prepareDialog() {
+        if (!prepared) {
+            makeDialog();
+            prepared = true;
+        }
+        dialog.startEditing();
+    }
+
+    /**
+     * Returns the current instance of the dialog, can be null.
+     * @return the current instance of the dialog, can be null.
+     */
+    public static final PrefMgrDialog getInstance ()
+    {
+        if (dialog == null) {
+            dialog = new PrefMgrDialog();
+        }
+        return dialog;
+    }
+
+
+    private ArrayList<PrefPanelListener> listeners = new ArrayList<PrefPanelListener>();
+    private ArrayList<JPanel> tabs = new ArrayList<JPanel>();
+    private ArrayList<String> titles = new ArrayList<String>();
+
+    private JTabbedPane tabbedPane = null;
+
+    private ClassMgrPrefPanel userConfigLibPanel;
+    /**
+     * Setup the UI for the dialog and event handlers for the dialog's buttons.
+     *
+     * @param title the title of the dialog
+     */
+    private PrefMgrDialog()
+    {
+        createPrefPanes();
+    }
+
+    /**
+     * Create all known preference panes.
+     */
+    private void createPrefPanes()
+    {
+        EditorPrefPanel panel = new EditorPrefPanel();
+        add(panel, Config.getString("prefmgr.edit.prefpaneltitle"), panel); 
+        kbPanel=new KeyBindingsPanel();
+        add(kbPanel.makePanel(), Config.getString("prefmgr.edit.keybindingstitle"), kbPanel);
+        MiscPrefPanel panel2 = new MiscPrefPanel();
+        add(panel2, Config.getString("prefmgr.misc.prefpaneltitle"), panel2);
+        InterfacePanel panel3 = new InterfacePanel();
+        add(panel3, Config.getString("prefmgr.interface.title"), panel3);
+        userConfigLibPanel = new ClassMgrPrefPanel();
+        add(userConfigLibPanel, Config.getString("classmgr.prefpaneltitle"), userConfigLibPanel);
+        if(!Config.isGreenfoot()) {
+            ExtensionPrefManager mgr = ExtensionsManager.getInstance().getPrefManager();
+            add(mgr.getPanel(), Config.getString("extmgr.extensions"), mgr);
+        }
+
+    }
+
+    /**
+     * Returns the instance of the UserConfigLibPanel.
+     * It is possible to retrieve the current list of libraries from it.
+     * @return a user config lib panel.
+     */
+    public ClassMgrPrefPanel getUserConfigLibPanel ()
+    {
+        return userConfigLibPanel;
+    }
+
+    /**
+     * Register a panel to be shown in the preferences dialog
+     *
+     * @param panel     the panel to add
+     * @param title     a string describing the panel
+     * @param listener  an object which will be notified of events concerning the
+     *                  preferences dialog
+     */
+    public void add(JPanel panel, String title, PrefPanelListener listener)
+    {
+        tabs.add(panel);
+        listeners.add(listener);
+        titles.add(title);
+    }
+
+    private void startEditing()
+    {
+        for (Iterator<PrefPanelListener> i = listeners.iterator(); i.hasNext(); ) {
+            PrefPanelListener ppl = i.next();
+            ppl.beginEditing();
+        }        
+    }
+
+    private void selectTab(int tabNumber)
+    {
+        tabbedPane.setSelectedIndex(tabNumber);
+    }
+
+    private void makeDialog()
+    {
+        Image icon = BlueJTheme.getIconImage();
+        if (icon != null) {
+            setIconImage(icon);
+        }
+        setTitle(Config.getApplicationName() + ": " + Config.getString("prefmgr.title"));
+
+        tabbedPane = new JTabbedPane();
+
+        for (ListIterator<JPanel> i = tabs.listIterator(); i.hasNext(); ) {
+            int index = i.nextIndex();
+            JPanel p = i.next();
+            tabbedPane.addTab(titles.get(index), null, p);
+        }
+
+        JPanel contentPanel = (JPanel)getContentPane();
+        {
+            contentPanel.setLayout(new BorderLayout());
+            contentPanel.setBorder(BlueJTheme.dialogBorder);
+
+            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+            {
+                buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                JButton okButton = BlueJTheme.getOkButton();
+                {
+                    okButton.addActionListener(new ActionListener() {
+                        public void actionPerformed(ActionEvent e) {
+                            for (Iterator<PrefPanelListener> i = listeners.iterator(); i.hasNext(); ) {
+                                PrefPanelListener ppl = i.next();
+                                ppl.commitEditing();
+                            }
+                            setVisible(false);
+                        }
+                    });
+                }
+
+                getRootPane().setDefaultButton(okButton);
+
+                JButton cancelButton = BlueJTheme.getCancelButton();
+                {
+                    cancelButton.addActionListener(new ActionListener() {
+                        public void actionPerformed(ActionEvent e) {
+                            for (Iterator<PrefPanelListener> i = listeners.iterator(); i.hasNext(); ) {
+                                PrefPanelListener ppl = i.next();
+                                ppl.revertEditing();
+                            }
+                            setVisible(false);
+                        }
+                    });
+                }
+
+                DialogManager.addOKCancelButtons(buttonPanel, okButton, cancelButton);
+            }
+
+            contentPanel.add(tabbedPane, BorderLayout.CENTER);
+            contentPanel.add(buttonPanel, BorderLayout.SOUTH);
+        }
+
+        // save position when window is moved
+        addComponentListener(new ComponentAdapter() {
+            public void componentMoved(ComponentEvent event)
+            {
+                Config.putLocation("bluej.preferences", getLocation());
+            }
+        });
+
+        setLocation(Config.getLocation("bluej.preferences"));
+        pack();        
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/PrefPanelListener.java b/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/PrefPanelListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..53fbe256e5fc1e6e16823c236d708924a1c06153
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/prefmgr/PrefPanelListener.java
@@ -0,0 +1,34 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.prefmgr;
+
+/**
+ * 
+ * @author Andrew Patterson
+ * @version $Id: PrefPanelListener.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface PrefPanelListener
+{
+    void beginEditing();
+    void revertEditing();
+    void commitEditing();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/BJInputStream.java b/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/BJInputStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..cdbb28bae93420c605360a58de41c7a74c1adeff
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/BJInputStream.java
@@ -0,0 +1,87 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.runtime;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import bluej.terminal.InputBuffer;
+
+/**
+ * BlueJ input stream. An input stream filter to process "End of file"
+ * signals (CTRL-Z or CTRL-D) from a terminal
+ * 
+ * @author Davin McCall
+ * @version $Id: BJInputStream.java 7142 2010-02-17 23:47:00Z davmac $
+ */
+public class BJInputStream extends InputStream
+{
+    private InputStream source;
+    int buffoffset = 0;
+    
+    boolean endOfLine = false;
+    boolean exOnEOL = false;
+    
+    /**
+     * Construct a BJ
+     * @param source  The source input stream, generally System.in
+     */
+    BJInputStream(InputStream source)
+    {
+        this.source = source;
+    }
+    
+    public int read() throws IOException {
+        
+        if (exOnEOL && endOfLine)
+            throw new IOException();
+        
+        int n = source.read();
+        
+        // Check for EOF signal
+        if (n == InputBuffer.EOF_CHAR)
+            return -1;
+        
+        // Are we line-buffering?
+        if (exOnEOL && n == '\n')
+            endOfLine = true;
+        
+        return n;
+    }
+    
+    public int read(byte [] b, int off, int len) throws IOException
+    {
+        // reads are line buffered. If a complete line is read, we don't
+        // want to read any more. So we flag this and it is handled in the
+        // read() method.
+        exOnEOL = true;
+        int n = super.read(b, off, len);
+        exOnEOL = false;
+        endOfLine = false;
+        return n;
+    }
+    
+    public int available() throws IOException
+    {
+        return source.available();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/BJMap.java b/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/BJMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..1eaee69bc7160b5385458b2823d3f6b0298f006f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/BJMap.java
@@ -0,0 +1,95 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.runtime;
+
+/**
+ * A simple map implementation, for use in J2ME. Not efficient, but fine for
+ * how it is presently used.
+ * 
+ * @author Davin McCall
+ */
+public class BJMap<K,V>
+{
+    private V[] values;
+    private K[] keys;
+    
+    @SuppressWarnings("unchecked")
+    public BJMap()
+    {
+        values = (V[]) new Object[0];
+        keys = (K[]) new Object[0];
+    }
+    
+    public V get(K key)
+    {
+        for (int i = 0; i < keys.length; i++) {
+            if (keys[i].equals(key)) {
+                return values[i];
+            }
+        }
+        
+        return null;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public void put(K key, V value)
+    {
+        for (int i = 0; i < keys.length; i++) {
+            if (keys[i].equals(key)) {
+                values[i] = value;
+                return;
+            }
+        }
+        
+        K [] newKeys = (K []) new Object[keys.length + 1];
+        V [] newValues = (V []) new Object[keys.length + 1];
+        System.arraycopy(keys, 0, newKeys, 0, keys.length);
+        System.arraycopy(values, 0, newValues, 0, keys.length);
+        newKeys[keys.length] = key;
+        newValues[keys.length] = value;
+        keys = newKeys;
+        values = newValues;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public void remove(K key)
+    {
+        for (int i = 0; i < keys.length; i++) {
+            if (keys[i].equals(key)) {
+                K [] newKeys = (K []) new Object[keys.length - 1];
+                V [] newValues = (V []) new Object[keys.length - 1];
+                System.arraycopy(keys, 0, newKeys, 0, i);
+                System.arraycopy(keys, i+1, newKeys, i, keys.length - i - 1);
+                System.arraycopy(values, 0, newValues, 0, i);
+                System.arraycopy(values, i+1, newValues, i, keys.length - i - 1);
+                keys = newKeys;
+                values = newValues;
+                return;
+            }
+        }
+    }
+    
+    public K[] getKeys()
+    {
+        return keys;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/ExecServer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/ExecServer.java
new file mode 100644
index 0000000000000000000000000000000000000000..84cde81293dec6501f83c240b408ab1b07befd0f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/ExecServer.java
@@ -0,0 +1,887 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.runtime;
+
+import java.awt.AWTEvent;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.event.AWTEventListener;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+import bluej.utility.Utility;
+
+/**
+ * Class that controls the runtime of code executed within BlueJ.
+ * Sets up the initial thread state, etc.
+ *
+ * <p>This class both holds runtime attributes and executes commands.
+ * Execution is done through JDI reflection from the JdiDebugger class.
+ *
+ * @author  Michael Kolling
+ * @author  Andrew Patterson
+ */
+public class ExecServer
+{
+    // these fields will be fetched by VMReference
+    
+    // the initial thread that starts main()
+    public static final String MAIN_THREAD_NAME = "mainThread";
+    public static Thread mainThread = null;
+    
+    // a worker thread that we create
+    public static final String WORKER_THREAD_NAME = "workerThread";
+    public static Thread workerThread = null;
+    
+    // Parameters for main thread actions
+    public static String classToRun;
+    public static String methodToRun;
+    public static String [] parameterTypes;
+    public static Object [] arguments;
+    public static int execAction = -1;   // EXEC_SHELL, TEST_SETUP or TEST_RUN
+    
+    public static Object methodReturn;
+    public static Class<?> executedClass;
+    public static Throwable exception;
+    
+    // These constant values must match the variable names declared above
+    public static final String CLASS_TO_RUN_NAME = "classToRun";
+    public static final String METHOD_TO_RUN_NAME = "methodToRun";
+    public static final String PARAMETER_TYPES_NAME = "parameterTypes";
+    public static final String ARGUMENTS_NAME = "arguments";
+    public static final String EXEC_ACTION_NAME = "execAction";
+    public static final String METHOD_RETURN_NAME = "methodReturn";
+    public static final String EXCEPTION_NAME = "exception";
+    public static final String EXECUTED_CLASS_NAME = "executedClass";
+    
+    // Possible actions for the main thread
+    public static final int EXEC_SHELL = 0;  // Execute a shell class
+    public static final int TEST_SETUP = 1;
+    public static final int TEST_RUN = 2;
+    public static final int DISPOSE_WINDOWS = 3;
+    public static final int EXIT_VM = 4;
+    public static final int LOAD_INIT_CLASS = 5;  // load and initialize a class
+    public static final int INSTANTIATE_CLASS = 6; // use default constructor
+    public static final int INSTANTIATE_CLASS_ARGS = 7; // use constructor
+        // with specified parameter types and arguments
+    
+    // Parameter for worker thread actions
+    public static int workerAction = EXIT_VM;
+    public static String objectName;
+    public static Object object;
+    public static String classPath;
+    public static String className;
+    public static String scopeId;
+    public static ClassLoader classLoader = null; // null to use current loader.
+    
+    public static Object workerReturn;
+    
+    // These constant values must match the variable names declared above
+    public static final String WORKER_ACTION_NAME = "workerAction";
+    public static final String OBJECTNAME_NAME = "objectName";
+    public static final String OBJECT_NAME = "object";
+    public static final String CLASSPATH_NAME = "classPath";
+    public static final String CLASSNAME_NAME = "className";
+    public static final String WORKER_RETURN_NAME = "workerReturn";
+    public static final String SCOPE_ID_NAME = "scopeId";
+    public static final String CLASSLOADER_NAME = "classLoader";
+    
+    // possible actions for worker thread
+    public static final int REMOVE_OBJECT = 0;
+    public static final int ADD_OBJECT    = 1;
+    public static final int LOAD_CLASS    = 2;
+    public static final int NEW_LOADER    = 3;
+    // EXIT_VM ( = 4) is also used in the worker thread
+    public static final int LOAD_ALL      = 5; // load class and inner classes
+
+    // the current class loader
+    private static ClassLoader currentLoader;
+
+    // The loader that loads the greenfoot application classes. This is the
+    // loader that gets used the first time anything is loaded in the debugvm.
+    // This loader will be the parent loader for all loaders created later on.
+    // The reason we need to do this, is to keep using the same class for
+    // GreenfootObject and GreenfootWorld in order to cast newly created objects
+    // into these types.
+    //private static ClassLoader greenfootLoader;
+    
+    // a hashmap of names to objects
+    // private static Map objects = new HashMap();
+    private static Map<String,BJMap<String,Object>> objectMaps = new HashMap<String,BJMap<String,Object>>();
+    
+    /**
+     * We need to keep track of open windows so that we can dispose of them
+     * when simulating a System.exit() call
+     */
+    private static List<Window> openWindows = Collections.synchronizedList(new LinkedList<Window>());
+    private static boolean disposingAllWindows = false; // true while we are disposing
+
+    /**
+     * Main method.
+     */
+    public static void main(String[] args)
+        throws Throwable
+    {
+        // Set up an input stream filter to detect "End of file" signals
+        // (CTRL-Z or CTRL-D typed in terminal)
+        System.setIn(new BJInputStream(System.in));
+        
+        // Set up encoding for the terminal, the only arg that should be passed in
+        // is the encoding eg. "UTF-8", otherwise do nothing
+        if(args.length > 0 && !args[0].equals("")) {
+            try {
+                System.setOut(new PrintStream(System.out, true, args[0]));
+                System.setErr(new PrintStream(System.err, true, args[0]));
+            }
+            catch (UnsupportedEncodingException uee) {
+                // Do nothing; don't use the requested encoding
+            }
+        }
+        
+        // Set up the worker thread. The worker thread can be used to perform certain actions
+        // when the main thread is busy. Actions on the worker thread are guaranteed to execute
+        // in a timely manner - for this reason they must not execute user code.
+        workerThread = new Thread("BlueJ worker thread")
+        {
+            public void run()
+            {
+                while(true) {
+                    vmSuspend();
+                    switch(workerAction) {
+                        case ADD_OBJECT:
+                            addObject(scopeId, objectName, object);
+                            object = null;
+                            break;
+                        case REMOVE_OBJECT:
+                            removeObject(scopeId, objectName);
+                            break;
+                        case LOAD_CLASS:
+                            try {
+                                if (classLoader == null)
+                                    classLoader = currentLoader;
+                                
+                                workerReturn = Class.forName(className, false, currentLoader);
+                                // Cause the class to be prepared (ie. its fields and methods
+                                // enumerated). Otherwise we can get ClassNotPreparedException
+                                // when we try and get the fields on the other VM.
+                                ((Class<?>) workerReturn).getFields();
+                                
+                                classLoader = null;  // reset for next call
+                            }
+                            catch(Throwable cnfe) {
+                                workerReturn = null;
+                            }
+                            break;
+                        case NEW_LOADER:
+                            workerReturn = newLoader(classPath);
+                            break;
+                        case EXIT_VM:
+                            System.exit(0);
+                        case LOAD_ALL:
+                            workerReturn = loadAllClasses(className);
+                    }
+                    // After any action, set the next action to exit. If connection to
+                    // primary VM is lost, the secondary VM (i.e. this VM) will then exit.
+                    workerAction = EXIT_VM;
+                }
+            }
+        };
+
+        // register a listener to record all window opens and closes
+        Toolkit toolkit = Toolkit.getDefaultToolkit();
+
+        AWTEventListener listener = new AWTEventListener()
+        {
+            public void eventDispatched(AWTEvent event)
+            {
+                Object source = event.getSource();
+                if(event.getID() == WindowEvent.WINDOW_OPENED) {                    
+                    if (source instanceof Window) {
+                        addWindow((Window) source);
+                        Utility.bringToFront((Window) source);
+                    }
+                } else if(event.getID() == WindowEvent.WINDOW_CLOSED) {
+                    if (source instanceof Window) {
+                        removeWindow((Window) source);
+                    }
+                }
+            }
+        };
+
+        toolkit.addAWTEventListener(listener, AWTEvent.WINDOW_EVENT_MASK);
+
+        // signal with a breakpoint that we have performed our VM
+        // initialization, at the same time, create the initial server thread.
+        newThread();
+        
+        // Set the worker thread in motion also. Give it maximum priority so that it can
+        // be guarenteed to execute in a timely manner, and won't get starved by user code
+        // executing in other threads.
+        workerThread.setPriority(Thread.MAX_PRIORITY);
+        workerThread.start();
+    }
+
+    /**
+     * This method is used to suspend the execution of the
+     * machine to indicate that everything is up and running.
+     */
+    public static void vmStarted()
+    {
+        // <SUSPENDING BREAKPOINT!>
+    }
+
+    /**
+     * This method is used to suspend the execution of the worker threads.
+     * This is done via a breakpoint: a breakpoint is set in this method
+     * so calling this method suspends execution.
+     */
+    public static void vmSuspend()
+    {
+        // <SUSPENDING BREAKPOINT!>
+    }
+
+    /**
+     * Add the object to our list of open windows
+     *
+     * @param   o   a window object which has just been opened
+     */
+    private static void addWindow(Window o)
+    {
+        openWindows.add(o);
+    }
+
+    /**
+     * Remove the object from our list of open windows
+     *
+     * @param   o   a window object which has just been closed
+     */
+    private static void removeWindow(Window o)
+    {
+        if(!disposingAllWindows)   // don't bother if we are clearing up just now
+            openWindows.remove(o);
+    }
+
+    /**
+     * Find a scoping Map for the given scopeId
+     */
+    static BJMap<String,Object> getScope(String scopeId)
+    {
+        synchronized (objectMaps) {
+            BJMap<String,Object> m = objectMaps.get(scopeId);
+            if (m == null) {
+                m = new BJMap<String,Object>();
+                objectMaps.put(scopeId, m);
+            }
+            return m;
+        }
+    }
+
+    /**
+     * Create a new class loader for a given classpath.
+     * @param urlListAsString a URL list written as a single string (the \n is used to divide entries)
+     * @return a URLClassLoader that can be used to load user classes.
+     */
+    private static ClassLoader newLoader(String urlListAsString )
+    {
+        String [] splits = urlListAsString.split("\n");
+        URL []urls = new URL[splits.length];
+        
+        for (int index = 0; index < splits.length; index++)
+            try {
+                urls[index] = new URL(splits[index]);
+            }
+        catch (MalformedURLException mfue) {
+            // Should never happen but if it does we want to know about it
+            System.err.println("ExecServer.newLoader() Malformed URL=" + splits[index]);
+        }
+        
+        currentLoader = new URLClassLoader(urls);
+        
+        synchronized (objectMaps) {
+            objectMaps.clear();
+        }
+        
+        return currentLoader;
+    }
+
+    /**
+     * Load (and prepare) a class in the remote runtime. Return null if the class could not
+     * be loaded.
+     */
+    public static Class<?> loadAndInitClass(String className)
+    {
+        Throwable exception = null;
+        Class<?> cl;
+        try {
+            cl = Class.forName(className, true, currentLoader);
+        }
+        catch (ClassNotFoundException cnfe) {
+            // class definitely doesn't exist
+            cl = null;
+        }
+        catch (ExceptionInInitializerError eiie) {
+            // The class was loaded it, but an exception occurred during initialization.
+            // As this is an error in user code, we want to report it.
+            exception = eiie.getCause();
+            
+            // Now get the class again, uninitialized this time
+            try {
+                cl = Class.forName(className, false, currentLoader);
+            }
+            catch (ClassNotFoundException cnfe) {
+                // this shouldn't happen anyway.
+                cl = null;
+            }
+        }
+        catch (Throwable err) {
+            // There are numerous other linkage problems. Also there is the possibility that
+            // a static initialization block will throw an instance of java.lang.Error, which
+            // will not be wrapped in an ExceptionInInitializerError (unfortunately). In either
+            // case we probably should let the user know what happened.
+            
+            exception = err;
+
+            // The class may exist, but not be initializable for some reason.
+            try {
+                cl = Class.forName(className, false, currentLoader);
+            }
+            catch (Throwable t) {
+                cl = null;
+            }
+        }
+        
+        // If we have an exception to report, filter and report it.
+        if (exception != null) {
+            StackTraceElement [] stackTrace = exception.getStackTrace();
+            
+            // filter bluej.runtime.ExecServer from the stack trace
+            int i;
+            for (i = stackTrace.length - 1; i > 0; i--) {
+                String stClassName = stackTrace[i].getClassName();
+                if (! stClassName.startsWith("bluej.runtime.ExecServer")
+                        && ! stClassName.startsWith("java.lang.Class"))
+                    break;
+            }
+            StackTraceElement [] newStackTrace = new StackTraceElement[i+1];
+            System.arraycopy(stackTrace, 0, newStackTrace, 0, i+1);
+            exception.setStackTrace(newStackTrace);
+            recordException(exception);
+        }
+       
+        return cl;
+    }
+    
+    /**
+     * Load a class, and all its inner classes.
+     */
+    private static Class<?>[] loadAllClasses(String className)
+    {
+        List<Class<?>> l = new ArrayList<Class<?>>();
+        
+        try {
+            Class<?> c = currentLoader.loadClass(className);
+            c.getFields(); // prepare class
+            l.add(c);
+            getDeclaredInnerClasses(c, l);
+            
+            // Now we want the anonymous inner classes:
+            int i = 1;
+            while(true) {
+                c = currentLoader.loadClass(className + '$' + i);
+                c.getFields();
+                l.add(c);
+                i++;
+            }
+        }
+        catch (Throwable t) {}
+        
+        return (Class []) l.toArray(new Class[l.size()]);
+    }
+    
+    /**
+     * Add the declared inner classes of the given class to the given
+     * list, recursively.
+     */
+    private static void getDeclaredInnerClasses(Class<?> c, List<Class<?>> list)
+    {
+        try {
+            Class<?> [] rlist = c.getDeclaredClasses();
+            for (int i = 0; i < rlist.length; i++) {
+                c = rlist[i];
+                c.getFields(); // force preparation
+                list.add(rlist[i]);
+                getDeclaredInnerClasses(rlist[i], list);
+            }
+        }
+        catch (Throwable t) {}
+    }
+    
+    /**
+     * Add an object into a package scope (for possible use as parameter
+     * later). Used after object creation to add the newly created object
+     * to the scope.
+     *
+     * Must be static because it is used by Shell without a execServer reference
+     */
+    static void addObject(String scopeId, String instanceName, Object value)
+    {
+        // Debug.message("[VM] addObject: " + instanceName + " " + value);
+        BJMap<String,Object> scope = getScope(scopeId);
+        synchronized (scope) {
+            scope.put(instanceName, value);
+            scope.notify(); // in case Greenfoot is waiting for this object
+        }
+    }
+    
+    /**
+     * Execute a JUnit test case setUp method.
+     * 
+     * @return  an array consisting of String, Object pairs. For n fixture objects
+     *          there will be n*2 entries in the array. Putting it in an array saves
+     *          having to make lots of reflective List and HashMap calls on the
+     *          calling virtual machine. Once the calling VM gets this array it can
+     *          put it into a more suitable data structure itself.
+     */
+    private static Object[] runTestSetUp(String className)
+    {
+        Class<?> cl = loadAndInitClass(className);
+        
+        try {
+            // construct an instance of the test case (firstly trying the
+            // String argument constructor - then the no-arg constructor)
+            Object testCase = null;
+
+            Class<?> [] partypes = new Class[1];
+            partypes[0] = String.class;
+            try {
+                Constructor<?> ct = cl.getConstructor(partypes);
+
+                Object arglist[] = new Object[1];
+                arglist[0] = "TestCase " + className;
+                testCase = ct.newInstance(arglist);
+            }
+            catch(NoSuchMethodException nsme) {
+                testCase = null;                
+            }
+
+            if (testCase == null) {
+                testCase = cl.newInstance();
+            }
+                        
+            // cannot execute setUp directly because it is protected
+            // we can however use reflection to call it because this VM
+            // has access protection disabled
+
+            Method setUpMethod = findMethod(cl, "setUp", null);
+            if (setUpMethod != null) {
+                setUpMethod.setAccessible(true);
+                setUpMethod.invoke(testCase, (Object []) null);
+            }
+
+            // pick up all declared fields
+            // this will not get inherited fields!! (would need to deal
+            // with them some other way)            
+            Field fields[] = cl.getDeclaredFields();
+            // we make it one bigger than double the number of fields to store the
+            // test case object which is used later for extracting (possibly generic) fields
+            // whose exact generic types may not be available via class level
+            // reflection
+
+            Object obs[] = new Object[fields.length*2 + 1];
+
+            for(int i=0; i<fields.length; i++) {
+                // make sure we can access the field regardless of protection
+                fields[i].setAccessible(true);
+                // fill in the return array in the format
+                // name, object, name, object
+                obs[i*2] = fields[i].getName();
+                obs[i*2+1] = fields[i].get(testCase);
+            }
+            //add the testcase as the last object in the array
+            obs[obs.length-1] = testCase;
+            return obs;
+        }
+        catch (Throwable e) {
+            e.printStackTrace();
+        }
+
+        return new Object[0];
+    }
+    
+    /**
+     * Find a method in the class, regardless of visibility. This is
+     * essentially the same as Class.getMethod(), except that it also returns
+     * non-public methods.
+     * 
+     * @param cl         The class to search
+     * @param name       The name of the method
+     * @param paramtypes The argument types
+     * @return  The method, or null if not found.
+     */
+    static private Method findMethod(Class<?> cl, String name, Class<?>[] paramtypes)
+    {
+        while (cl != null) {
+            try {
+                return cl.getDeclaredMethod(name, paramtypes);
+            }
+            catch (NoSuchMethodException nsme) {}
+
+            cl = cl.getSuperclass();
+        }
+
+        return null;
+    }
+
+    /**
+     * Execute a JUnit test method and return the result.<p>
+     * 
+     * The array returned in case of failure or error contains:<br>
+     *  [0] = the runtime in milliseconds expressed as a decimal integer
+     *  [1] = the exception message (or "no exception message")<br>
+     *  [2] = the stack trace as a string (or "no stack trace")<br>
+     *  [3] = the name of the class in which the exception/failure occurred<br>
+     *  [4] = the source filename for where the exception/failure occurred<br>
+     *  [5] = the name of the method in which the exception/failure occurred<br>
+     *  [6] = the line number where the exception/failure occurred (a string)<br>
+     *  [7] = "failure" or "error" (string)<br>
+     *  
+     * The array returned in case of success contains:<br>
+     *  [0] = the runtime in milliseconds expressed as a decimal integer
+     * 
+     * @return an array of length 8 on test failure/error, or of length 1 if the test passed
+     */
+    private static Object[] runTestMethod(String className, String methodName)
+    {
+        Class<?> cl = loadAndInitClass(className);
+
+        Result res = (new JUnitCore()).run(Request.method(cl, methodName));
+        if (res.wasSuccessful()) {
+            Object result[] = new Object[1];
+            result[0] = String.valueOf(res.getRunTime());
+            return result;
+        } else {
+            Object result[] = new Object[8];
+            List<Failure> failures = res.getFailures();
+            for (Iterator<Failure> iterator = failures.iterator(); iterator.hasNext();) {
+                Failure failure = (Failure) iterator.next();
+                if (java.lang.AssertionError.class.isAssignableFrom(failure.getException().getClass()) 
+                        || failure.getException().getClass() == junit.framework.AssertionFailedError.class) {
+                    result[7] = "failure";
+                }
+                else {
+                    result[7] = "error";
+                }
+
+                result[0] = String.valueOf(res.getRunTime());
+                result[1] = failure.getMessage() != null ? failure.getMessage() : "no exception message";
+                result[2] = failure.getTrace() != null ? failure.getTrace() : "no trace";
+
+                // search the stack trace backward until finding a class not
+                // part of the org.junit framework
+                StackTraceElement [] ste = failure.getException().getStackTrace();
+                int i = 0; 
+                while(i < ste.length && ste[i].getClassName().startsWith("org.junit.")) {
+                    i++;
+                }
+
+                result[3] = ste[i].getClassName();
+                result[4] = ste[i].getFileName();
+                result[5] = ste[i].getMethodName();
+                result[6] = String.valueOf(ste[i].getLineNumber());
+            }
+
+            return result;
+        }
+    }
+
+    /**
+     * Remove an object from the scope.
+     */
+    private static void removeObject(String scopeId, String instanceName)
+    {
+        //Debug.message("[VM] removeObject: " + instanceName);
+        BJMap<String,Object> scope = getScope(scopeId);
+        synchronized (scope) {
+            scope.remove(instanceName);
+        }
+    }
+
+    /**
+     * Dispose of all the top level windows we think are open.
+     *
+     * Must be static because it is used by RemoteSecurityManager without a execServer reference
+     */
+    private static void disposeWindows()
+    {
+        synchronized(openWindows) {
+            disposingAllWindows = true;
+            Iterator<Window> it = openWindows.iterator();
+
+            while(it.hasNext()) {
+                it.next().dispose();
+            }
+            openWindows.clear();
+            disposingAllWindows = false;
+        }
+    }
+    
+    /**
+     * Clear the system input buffer. This is used between method calls to
+     * make sure that System.in.read() doesn't read input which was buffered
+     * during the last method call but never read.
+     */
+    private static void clearInputBuffer()
+    {
+        try {
+            int n = System.in.available();
+            while(n != 0) {
+                System.in.skip(n);
+                n = System.in.available();
+            }
+        }
+        catch(IOException ioe) { }
+    }
+    
+    /**
+     * Bug in the java debug VM means that exception events are unreliable 
+     * if we re-use the same thread over and over. So, whenever running user
+     * code results in an exception, this method is used to spawn a new thread.
+     */
+    private static void newThread()
+    {        
+        final Thread oldThread = mainThread;
+        // Then make a new one.
+        mainThread = new Thread("main") {
+            public void run()
+            {
+                try {
+                    if(oldThread != null) {
+                        oldThread.join();
+                    }
+                }
+                catch(InterruptedException ie) { }
+                
+                vmStarted();
+                
+                // Execute the command
+                methodReturn = null;
+                exception = null;
+                Thread.currentThread().setContextClassLoader(currentLoader);
+
+                try {
+                    switch(execAction) {
+                        case EXEC_SHELL:
+                        {
+                            // Execute a shell class.
+                            methodReturn = null;
+                            executedClass = null;
+                            
+                            clearInputBuffer();
+                            Class<?> c = currentLoader.loadClass(classToRun);
+                            executedClass = c;
+                            // Class c = cloader.loadClass(classToRun);
+                            Method m = c.getMethod("run", new Class[0]);
+                            try {
+                                methodReturn = m.invoke(null, new Object[0]);
+                            }
+                            catch(InvocationTargetException ite) {
+                                throw ite.getCause();
+                            }
+                            break;
+                        }
+                        case INSTANTIATE_CLASS:
+                        {
+                            // Instantiate a class using the default
+                            // constructor
+                            clearInputBuffer();
+                            Class<?> c = currentLoader.loadClass(classToRun);
+                            Constructor<?> cons = c.getDeclaredConstructor(new Class[0]);
+                            cons.setAccessible(true);
+                            try {
+                                methodReturn = cons.newInstance((Object []) null);
+                            }
+                            catch (InvocationTargetException ite) {
+                                throw ite.getCause();
+                            }
+                            break;
+                        }
+                        case INSTANTIATE_CLASS_ARGS:
+                        {
+                            // Instantiate a class using specified parameter
+                            // types and arguments
+                            clearInputBuffer();
+                            Class<?> c = currentLoader.loadClass(classToRun);
+                            Class<?> [] paramClasses = new Class[parameterTypes.length];
+                            for (int i = 0; i < parameterTypes.length; i++) {
+                                if (classLoader == null)
+                                    classLoader = currentLoader;
+                                
+                                paramClasses[i] = Class.forName(parameterTypes[i], false, currentLoader);
+                            }
+                            Constructor<?> cons = c.getDeclaredConstructor(paramClasses);
+                            cons.setAccessible(true);
+                            try {
+                                methodReturn = cons.newInstance(arguments);
+                            }
+                            catch (InvocationTargetException ite) {
+                                throw ite.getCause();
+                            }
+                            break;
+                        }
+                        case TEST_SETUP:
+                            methodReturn = runTestSetUp(classToRun);
+                            break;
+                        case TEST_RUN:
+                            methodReturn = runTestMethod(classToRun, methodToRun);
+                            break;
+                        case DISPOSE_WINDOWS:
+                            disposeWindows();
+                            break;
+                        case LOAD_INIT_CLASS:
+                            try {
+                                methodReturn = loadAndInitClass(classToRun);
+                            }
+                            catch(Throwable cnfe) {
+                                methodReturn = null;
+                            }
+                            break;
+                        case EXIT_VM:
+                            System.exit(0);
+                        default:
+                    }
+                }
+                catch(Throwable t) {
+                    // record that an exception occurred
+                    recordException(t);
+                }
+                finally {
+                    // Set execAction to EXIT_VM, so if the main bluej process has died,
+                    // this vm will exit also.
+                    execAction = EXIT_VM;
+                    newThread();
+                }
+            }
+        };
+        mainThread.start();
+    }
+    
+    /**
+     * Record that an exception occurred, as well as printing a filtered stack trace.
+     * @param t  the exception which was caught
+     */
+    private static void recordException(Throwable t)
+    {
+        // record that an exception occurred
+        exception = t;
+        
+        // print a filtered stack trace to System.err
+        StackTraceElement [] stackTrace = t.getStackTrace();
+        int i;
+        for(i = 0; i < stackTrace.length; i++) {
+            if(stackTrace[i].getClassName().startsWith("__SHELL"))
+                break;
+        }
+        StackTraceElement [] newStackTrace = new StackTraceElement[i];
+        System.arraycopy(stackTrace, 0, newStackTrace, 0, i);
+        t.setStackTrace(newStackTrace);
+        t.printStackTrace();
+    }
+    
+
+    /**
+     * Gets an object in the scope. Used by greenfoot.
+     * 
+     * @param instanceName The name of the object
+     * @return The object
+     */
+    public static Object getObject(String instanceName)
+    {
+        BJMap<String,Object> m = getScope(scopeId);
+        Object rval = null;
+        
+        try {
+            synchronized (m) {
+                rval = m.get(instanceName);
+                // Sometimes the object isn't available yet - the worker thread
+                // hasn't stored it in the map yet. In that case we'll wait to
+                // be notified that an object has been stored.
+                if (rval == null) {
+                    m.wait();
+                    rval = m.get(instanceName);
+                }
+            }
+        }
+        catch (InterruptedException ie) {}
+        
+        return rval;
+    }
+    
+    /**
+     * Get the name-to-object map for the current package scope.
+     * Access to the map must be synchronized.
+     */
+    public static BJMap<String,Object> getObjectMap()
+    {
+        return getScope(scopeId);
+    }
+    
+    /**
+     * Get the current class loader used to load user classes.
+     * 
+     * @return  The current class loader
+     */
+    public static ClassLoader getCurrentClassLoader()
+    {
+        return currentLoader;
+    }
+    
+    /**
+     * Set the current class loader, to be used for loading user classes.
+     * 
+     * @param newLoader   The new class loader
+     */
+    public static void setClassLoader(ClassLoader newLoader)
+    {
+        currentLoader = newLoader;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/Shell.java b/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/Shell.java
new file mode 100644
index 0000000000000000000000000000000000000000..df549b3fe66aba362d0b3ffaeaacb864d09efa0d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/runtime/Shell.java
@@ -0,0 +1,145 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.runtime;
+
+/**
+ * Interface implemented by all "shell" classes.
+ *
+ * The src for each "shell" class is constructed automatically,
+ * compiled and executed. They are used for method invocation
+ * and object creation.
+ *
+ * @author  Michael Cahill
+ * @author  Michael Kolling
+ */
+public abstract class Shell
+{
+    /**
+     * A dummy method called by class loader to prepare the class
+     * after loading.
+     */
+    public static void prepare()
+    {
+    }
+
+    /**
+     * Provide the shell class with static access to the object
+     * bench scopes.
+     */
+    protected static BJMap<String,Object> getScope(String scopeId)
+    {
+        return ExecServer.getScope(scopeId);
+    }
+
+    /**
+     * Put an object into the scope of one of the object benches.
+     */
+    protected static void putObject(String scopeId, String instanceName, Object value)
+    {
+        ExecServer.addObject(scopeId, instanceName, value);
+    }
+
+    /**
+     * Construct an object that allows the result to be plucked out by
+     * the debugger. We do this so that primitive types can be encapsulated
+     * properly; if we boxed them, the debugger wouldn't know if the result
+     * was really primitive or not.
+     */
+    public static Object makeObj(final Object o)
+    {
+        return new Object() {
+            @SuppressWarnings("unused")
+            public Object result = o;
+        };
+    }
+
+    protected static Object makeObj(final String s)
+    {
+        return new Object() {
+           @SuppressWarnings("unused")
+           public String result = s;
+        };
+    }
+
+    protected static Object makeObj(final boolean b)
+    {
+        return new Object() {
+            @SuppressWarnings("unused")
+            public boolean result = b;
+        };
+    }
+
+    protected static Object makeObj(final byte b)
+    {
+        return new Object() {
+            @SuppressWarnings("unused")
+            public byte result = b;
+        };
+    }
+
+    protected static Object makeObj(final char c)
+    {
+        return new Object() {
+            @SuppressWarnings("unused")
+            public char result = c;
+        };
+    }
+
+    protected static Object makeObj(final double d) {
+        return new Object() {
+            @SuppressWarnings("unused")
+            public double result = d;
+        };
+    }
+
+    protected static Object makeObj(final float f)
+    {
+        return new Object() {
+            @SuppressWarnings("unused")
+            public float result = f;
+        };
+    }
+
+    protected static Object makeObj(final int i)
+    {
+        return new Object() {
+            @SuppressWarnings("unused")
+            public int result = i;
+        };
+    }
+
+    protected static Object makeObj(final long l)
+    {
+        return new Object() {
+            @SuppressWarnings("unused")
+            public long result = l;
+        };
+    }
+
+    protected static Object makeObj(final short s)
+    {
+        return new Object() {
+            @SuppressWarnings("unused")
+            public short result = s;
+        };
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/splash.jpg b/Sd1/P/Maven/bluej/src/main/java/bluej/splash.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ecaa44bdba00b70b547899f1c32cdc91c9119b98
Binary files /dev/null and b/Sd1/P/Maven/bluej/src/main/java/bluej/splash.jpg differ
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/ExceptionSourceLocation.java b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/ExceptionSourceLocation.java
new file mode 100644
index 0000000000000000000000000000000000000000..971c8c1d8cb8a82662cd6f36b4c13c7687aa5254
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/ExceptionSourceLocation.java
@@ -0,0 +1,76 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.terminal;
+
+import java.io.File;
+
+import bluej.pkgmgr.Package;
+
+/**
+ * A class that holds information about the location of an exception.
+ * Effectively, this represents one line in a stack-trace.
+ * @author nccb
+ *
+ */
+public class ExceptionSourceLocation
+{
+    /** The package */
+    private Package pkg;
+    /** The unqualified class name */
+    private String className;
+    /** The line number */
+    private int lineNumber;
+    
+    /** The starting position in the document of the bit to be linked */
+    private int startPos;
+    /** The ending position in the document of the bit to be linked */
+    private int endPos;
+    
+    public ExceptionSourceLocation(int startPos, int endPos,
+            Package pkg, String className, int lineNumber)
+    {
+        this.startPos = startPos;
+        this.endPos = endPos;
+        this.pkg = pkg;
+        this.className = className;
+        this.lineNumber = lineNumber;
+    }
+    
+    public int getStart()
+    {
+        return startPos;
+    }
+    public int getEnd()
+    {
+        return endPos;
+    }
+    
+    public void showInEditor()
+    {
+        String fileName = className.replace('.', '/') + ".java";
+        
+        pkg.exceptionMessage(new File(pkg.getPath(), fileName).getAbsolutePath(), lineNumber);
+        
+    }
+    
+    
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/InputBuffer.java b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/InputBuffer.java
new file mode 100644
index 0000000000000000000000000000000000000000..c40d0914e8237486b686a0dbacf6929befb3f57c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/InputBuffer.java
@@ -0,0 +1,143 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.terminal;
+
+import java.awt.Toolkit;
+
+/**
+ * A type-ahead input buffer for the BlueJ terminal. Implemented with
+ * a circular array.
+ *
+ * @author  Michael Kolling
+ * @version $Id: InputBuffer.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public final class InputBuffer 
+{
+    private char[] buffer;
+    private int bufferNextFull = 0;	// next free position
+    private int bufferNextFree = 0;	// next full position
+    private int bufferSize;
+    private boolean eofMark = false;
+    
+    public static char EOF_CHAR = '\u0004'; // internal code for EOF
+
+    public InputBuffer(int size)
+    {
+        buffer = new char[size];
+        bufferSize = size;
+    }
+
+    public synchronized boolean putChar(char ch)
+    {
+        if(isFull()) {
+            Toolkit.getDefaultToolkit().beep();
+            return false;
+        }
+        else {
+            buffer[bufferNextFree] = ch;
+            bufferNextFree = advance(bufferNextFree);
+            return true;
+        }
+    }
+
+    public synchronized boolean backSpace()
+    {
+        if(!isEmpty()) {
+            bufferNextFree = backwards(bufferNextFree);
+            return true;
+        }
+        else {
+            Toolkit.getDefaultToolkit().beep();
+            return false;
+        }
+    }
+
+    public synchronized char getChar()
+    {
+        // block until input available
+
+        while(isEmpty()) {
+            try {
+                wait();		// sleep until there is some input
+            } catch(InterruptedException e) {
+				// our main process is telling us
+				// we want to exit the character
+				// reading loop
+				// we'll return a return character
+				return '\n';
+            }
+        }
+
+        char ch = buffer[bufferNextFull];
+        bufferNextFull = advance(bufferNextFull);
+        // If an "end-of-file" has been signalled, send it now 
+        if (eofMark) {
+            eofMark = false;
+            putChar(EOF_CHAR); // "Ctrl-D" character. This is really just a
+            // code used internally; it does not need to match the system
+            // EOF character.
+            notifyReaders();
+        }
+        return ch;
+    }
+    
+    /**
+     * Signal that an EOF condition should be emulated by the terminal.
+     */
+    public synchronized void signalEOF()
+    {
+        // EOF is indicated by sending EOF_CHAR to the debug VM, which is then
+        // interpreted by the custom input stream installed therein.
+        if (! isFull())
+            putChar(EOF_CHAR);
+        else
+            eofMark = true;
+        notifyReaders();
+    }
+
+    public synchronized void notifyReaders()
+    {
+        notify();
+    }
+
+    public synchronized boolean isEmpty()
+    {
+        return bufferNextFull == bufferNextFree;
+    }
+
+    // This method should be synchronized if it is made public
+    private boolean isFull()
+    {
+        return advance(bufferNextFree) == bufferNextFull;
+    }
+    
+    private int advance(int pos)
+    {
+        return (++pos) % bufferSize;
+    }
+
+    private int backwards(int pos)
+    {
+        pos--;
+        return (pos < 0 ? bufferSize - 1 : pos);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TermTextArea.java b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TermTextArea.java
new file mode 100644
index 0000000000000000000000000000000000000000..be42b744de3be39a18a1537042ed95acb86a25b1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TermTextArea.java
@@ -0,0 +1,302 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.terminal;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.io.IOException;
+
+import javax.swing.JEditorPane;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultEditorKit;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+import bluej.pkgmgr.Project;
+import bluej.utility.Debug;
+
+/**
+ * A customised text area for use in the BlueJ text terminal.
+ *
+ * @author  Michael Kolling
+ */
+public final class TermTextArea extends JEditorPane implements MouseMotionListener, MouseListener
+{
+    private static final int BUFFER_LINES = 48;
+
+    private boolean unlimitedBuffer = false;
+
+    private InputBuffer buffer;
+    private Terminal terminal;
+    
+    private int preferredRows;
+    private int preferredColumns;
+
+    /**
+     * Create a new text area with given size.
+     */
+    public TermTextArea(int rows, int columns, InputBuffer buffer, final Project proj, Terminal terminal, final boolean isStderr)
+    {
+        preferredRows = rows;
+        preferredColumns = columns;
+        resetPreferredSize();
+        this.buffer = buffer;
+        this.terminal = terminal;
+        setEditorKit(new DefaultEditorKit() {
+            
+            @Override
+            public Document createDefaultDocument()
+            {
+                return new TerminalDocument(proj, isStderr /* Highlight stack traces if stderr */);
+            }
+            
+            @Override
+            public ViewFactory getViewFactory()
+            {
+                return new ViewFactory() {
+                    @Override
+                    public View create(Element elem)
+                    {
+                        return new TerminalView(elem, isStderr);
+                    }
+                };
+            } 
+        });
+        if (isStderr) /* Only need mouse listener if we're highlighting stack traces */
+        {
+            addMouseMotionListener(this);
+            addMouseListener(this);
+        }
+        
+        setForeground(TerminalView.getDefaultColor(isStderr));
+    }
+    
+    @Override
+    public void setFont(Font font)
+    {
+        super.setFont(font);
+        resetPreferredSize();
+    }
+    
+    /**
+     * Reset the preferred size according to font metrics and desired rows/columns
+     */
+    private void resetPreferredSize()
+    {
+        FontMetrics metrics = getFontMetrics(getFont());
+        int mwidth = metrics.charWidth('m');
+        int mheight = metrics.getHeight();
+        setPreferredSize(new Dimension(mwidth * preferredColumns, mheight * preferredRows));
+    }
+
+    public void setUnlimitedBuffering(boolean arg)
+    {
+        unlimitedBuffer = arg;
+    }
+
+    /**
+     * Append some text to the terminal text area.
+     */
+    public void append(String s)
+    {
+        append(s, null);
+    }
+    
+    /**
+     * Append some text to the terminal text area.
+     */
+    public void append(String s, AttributeSet attribs)
+    {
+        int length = getDocument().getLength();
+        try {
+            getDocument().insertString(length, s, attribs);
+        }
+        catch (BadLocationException ble) {
+            throw new RuntimeException(ble);
+        }
+
+        if(!unlimitedBuffer) {             // possibly remove top line
+            int lines = getLineCount();
+            if(lines > BUFFER_LINES) {
+                int linePos = getLineStartOffset(lines-BUFFER_LINES);
+                replaceRange(null, 0, linePos);
+            }
+        }
+    }
+    
+    /**
+     * Append a line of text from a method call recording.
+     */
+    public void appendMethodCall(String s)
+    {
+        int length = getDocument().getLength();
+        int lineCount = getLineCount();
+        if (length != getLineStartOffset(lineCount - 1)) {
+            // Start a new line for the method call details
+            append("\n");
+            lineCount++;
+        }
+        
+        append(s, null);
+        
+        TerminalDocument doc = (TerminalDocument) getDocument();
+        doc.markLineAsMethodOutput(lineCount - 1);
+    }
+    
+    /**
+     * Get the number of lines in the text area
+     */
+    public int getLineCount()
+    {
+        return getDocument().getDefaultRootElement().getElementCount();
+    }
+    
+    /**
+     * Get the start offset of a particular line (line 0 is the first line).
+     */
+    public int getLineStartOffset(int line)
+    {
+        return getDocument().getDefaultRootElement().getElement(line).getStartOffset();
+    }
+    
+    /**
+     * Replace the text in some portion of the document with the given string.
+     */
+    public void replaceRange(String s, int startPos, int endPos)
+    {
+        try {
+            getDocument().remove(startPos, endPos - startPos);
+            if (s != null) {
+                getDocument().insertString(startPos, s, null);
+            }
+        }
+        catch (BadLocationException ble) {
+            throw new RuntimeException(ble);
+        }
+    }
+
+    /*
+     * Overrides the default method to stop it append to the JTextArea straight
+     * away, instead we add the resultant string to our pasteBuffer for use
+     * elsewhere
+     * @see Terminal.keyTyped(KeyEvent event)
+     */
+    @Override
+    public void paste()
+    {
+        if (! terminal.checkActive()) {
+            return;
+        }
+        
+        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+        Transferable contents = clipboard.getContents(null);
+        if (contents.isDataFlavorSupported(DataFlavor.stringFlavor)) {
+            String result = null;
+            try {
+                result = (String) contents.getTransferData(DataFlavor.stringFlavor);
+            } catch (UnsupportedFlavorException ex) {
+                Debug.message(ex.getMessage());
+            } catch (IOException ex) {
+                Debug.message(ex.getMessage());
+            }
+            
+            if (result != null) {
+                for (char ch : result.toCharArray()) {
+                    if (buffer.putChar(ch)) {
+                        terminal.writeToTerminal(String.valueOf(ch));
+                    }
+                }
+            }
+        } else {
+            // if it isn't a string, let the usual paste method handle it.
+            super.paste();
+        }
+    }
+    
+    @Override
+    public void mouseMoved(MouseEvent e)
+    {
+        TermTextArea editor = TermTextArea.this;
+        Point pt = new Point(e.getX(), e.getY());
+        int pos = editor.getUI().viewToModel(editor, pt);
+        
+        Document doc = getDocument();
+        int elementIndex = doc.getDefaultRootElement().getElementIndex(pos);
+        Element el = doc.getDefaultRootElement().getElement(elementIndex);
+        
+        Cursor cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
+        
+        AttributeSet attrs = el.getAttributes();
+        if (attrs != null && attrs.getAttribute(TerminalView.SOURCE_LOCATION) != null) {
+            ExceptionSourceLocation sel = (ExceptionSourceLocation) attrs.getAttribute(TerminalView.SOURCE_LOCATION);
+            if (pos >= sel.getStart() && pos < sel.getEnd())
+            {
+                cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
+            }
+        }
+        
+        editor.setCursor(cursor);
+    }
+    
+    @Override
+    public void mouseClicked(MouseEvent e)
+    {
+        TermTextArea editor = TermTextArea.this;
+        Point pt = new Point(e.getX(), e.getY());
+        int pos = editor.getUI().viewToModel(editor, pt);
+        
+        Document doc = getDocument();
+        int elementIndex = doc.getDefaultRootElement().getElementIndex(pos);
+        Element el = doc.getDefaultRootElement().getElement(elementIndex);
+        
+        AttributeSet attrs = el.getAttributes();
+        if (attrs != null && attrs.getAttribute(TerminalView.SOURCE_LOCATION) != null) {
+            ExceptionSourceLocation sel = (ExceptionSourceLocation) attrs.getAttribute(TerminalView.SOURCE_LOCATION);
+            if (pos >= sel.getStart() && pos < sel.getEnd())
+            {
+                sel.showInEditor();
+            }
+        }
+    }
+    
+    // Un-needed stubs:
+    @Override public void mouseDragged(MouseEvent e) { }
+    @Override public void mousePressed(MouseEvent e) { }
+    @Override public void mouseReleased(MouseEvent e) { }
+    @Override public void mouseEntered(MouseEvent e) { }
+    @Override public void mouseExited(MouseEvent e) { }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/Terminal.java b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/Terminal.java
new file mode 100644
index 0000000000000000000000000000000000000000..e07637f7b2da31b3560b33cef1d5c07907026c4d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/Terminal.java
@@ -0,0 +1,938 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011,2012,2013  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.terminal;
+
+import java.awt.BorderLayout;
+import java.awt.Event;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.print.PrinterJob;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.InputMap;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JSplitPane;
+import javax.swing.KeyStroke;
+
+import bluej.BlueJEvent;
+import bluej.BlueJEventListener;
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.DebuggerTerminal;
+import bluej.debugmgr.ExecutionEvent;
+import bluej.pkgmgr.Project;
+import bluej.prefmgr.PrefMgr;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+
+/**
+ * The Frame part of the Terminal window used for I/O when running programs
+ * under BlueJ.
+ *
+ * @author  Michael Kolling
+ * @author  Philip Stevens
+ */
+@SuppressWarnings("serial")
+public final class Terminal extends JFrame
+    implements KeyListener, BlueJEventListener, DebuggerTerminal
+{
+    private static final String WINDOWTITLE = Config.getApplicationName() + ": " + Config.getString("terminal.title");
+    private static final int SHORTCUT_MASK =
+        Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+    //private static final int ALT_SHORTCUT_MASK =
+    //        SHORTCUT_MASK == Event.CTRL_MASK ? Event.CTRL_MASK : Event.META_MASK;
+
+    private static final String TERMINALFONTPROPNAME = "bluej.terminal.font";
+    private static final String TERMINALFONTSIZEPROPNAME = "bluej.terminal.fontsize";
+    
+    private static final String RECORDMETHODCALLSPROPNAME = "bluej.terminal.recordcalls";
+    private static final String CLEARONMETHODCALLSPROPNAME = "bluej.terminal.clearscreen";
+    private static final String UNLIMITEDBUFFERINGCALLPROPNAME = "bluej.terminal.buffering";
+        
+    // initialise to config value or zero.
+    private static int terminalFontSize = Config.getPropInteger(
+            TERMINALFONTSIZEPROPNAME, PrefMgr.getEditorFontSize());
+
+    // -- instance --
+
+    private Project project;
+    
+    private TermTextArea text;
+    private TermTextArea errorText;
+    private JScrollPane errorScrollPane;
+    private JScrollPane scrollPane;
+    private JSplitPane splitPane;
+    private boolean isActive = false;
+    private static boolean recordMethodCalls =
+            Config.getPropBoolean(RECORDMETHODCALLSPROPNAME);
+    private static boolean clearOnMethodCall =
+            Config.getPropBoolean(CLEARONMETHODCALLSPROPNAME);
+    private static boolean unlimitedBufferingCall =
+            Config.getPropBoolean(UNLIMITEDBUFFERINGCALLPROPNAME);
+    private boolean newMethodCall = true;
+    private boolean errorShown = false;
+    private InputBuffer buffer;
+
+    private JCheckBoxMenuItem autoClear;
+    private JCheckBoxMenuItem recordCalls;
+    private JCheckBoxMenuItem unlimitedBuffering;
+
+    private Reader in = new TerminalReader();
+    private Writer out = new TerminalWriter(false);
+    private Writer err = new TerminalWriter(true);
+
+    /** Used for lazy initialisation  */
+    private boolean initialised = false; 
+
+    /**
+     * Create a new terminal window with default specifications.
+     */
+    public Terminal(Project project)
+    {
+        super(WINDOWTITLE + " - " + project.getProjectName());
+        this.project = project;
+        BlueJEvent.addListener(this);
+    }
+
+    /**
+     * Get the terminal font
+     */
+    private static Font getTerminalFont()
+    {
+        return Config.getFont(
+                TERMINALFONTPROPNAME, "Monospaced", terminalFontSize);
+    }
+
+    /*
+     * Set the terminal font size to equal either the passed parameter, or the
+     * editor font size if the passed parameter is too low. Place the updated
+     * value into the configuration.
+     */
+    private static void setTerminalFontSize(int size)
+    {
+        if (size <= 6) {
+            terminalFontSize = PrefMgr.getEditorFontSize();
+        } else {
+            terminalFontSize = size;
+        }
+        Config.putPropInteger(TERMINALFONTSIZEPROPNAME, terminalFontSize);
+    }
+
+    
+    /**
+     * Initialise the terminal; create the UI.
+     */
+    private synchronized void initialise()
+    {
+        if(! initialised) {            
+            buffer = new InputBuffer(256);
+            int width = Config.isGreenfoot() ? 80 : Config.getPropInteger("bluej.terminal.width", 80);
+            int height = Config.isGreenfoot() ? 10 : Config.getPropInteger("bluej.terminal.height", 22);
+            makeWindow(width, height);
+            initialised = true;
+            text.setUnlimitedBuffering(unlimitedBufferingCall);
+        }
+    }
+
+    /**
+     * Show or hide the Terminal window.
+     */
+    public void showHide(boolean show)
+    {
+        initialise();
+        setVisible(show);
+        if(show) {
+            text.requestFocus();
+        }
+    }
+
+    /**
+     * Return true if the window is currently displayed.
+     */
+    public boolean isShown()
+    {       
+        initialise();
+        return isShowing();
+    }
+
+    /**
+     * Make the window active.
+     */
+    public void activate(boolean active)
+    {
+        if(active != isActive) {
+            initialise();
+            text.setEditable(active);
+            if (!active) {
+                text.getCaret().setVisible(false);
+            }
+            isActive = active;
+        }
+    }
+
+    /**
+     * Check whether the terminal is active (accepting input).
+     */
+    public boolean checkActive()
+    {
+        return isActive;
+    }
+    
+    /**
+     * Reset the font according to preferences.
+     */
+    public void resetFont()
+    {
+        initialise();
+        Font terminalFont = getTerminalFont();
+        text.setFont(terminalFont);
+        if (errorText != null) {
+            errorText.setFont(terminalFont);
+        }
+    }
+
+    /**
+     * Clear the terminal.
+     */
+    public void clear()
+    {
+        initialise();
+        text.setText("");
+        if(errorText!=null) {
+            errorText.setText("");
+        }
+        hideErrorPane();
+    }
+
+
+    /**
+     * Save the terminal text to file.
+     */
+    public void save()
+    {
+        initialise();
+        String fileName = FileUtility.getFileName(this,
+                Config.getString("terminal.save.title"),
+                Config.getString("terminal.save.buttonText"),
+                null, false);
+        if(fileName != null) {
+            File f = new File(fileName);
+            if (f.exists()){
+                if (DialogManager.askQuestion(this, "error-file-exists") != 0)
+                    return;
+            }
+            try {
+                FileWriter writer = new FileWriter(fileName);
+                text.write(writer);
+                writer.close();
+            }
+            catch (IOException ex) {
+                DialogManager.showError(this, "error-save-file");
+            }
+        }
+    }
+    
+    public void print()
+    {
+        PrinterJob job = PrinterJob.getPrinterJob();
+        int printFontSize = Config.getPropInteger("bluej.fontsize.printText", 10);
+        Font font = new Font("Monospaced", Font.PLAIN, printFontSize);
+        if (job.printDialog()) {
+            TerminalPrinter.printTerminal(job, text, job.defaultPage(), font);
+        }
+    }
+
+    /**
+     * Write some text to the terminal.
+     */
+    private void writeToPane(boolean stdout, String s)
+    {
+        prepare();
+        if (!stdout)
+            showErrorPane();
+        
+        // The form-feed character should clear the screen.
+        int n = s.lastIndexOf('\f');
+        if (n != -1) {
+            clear();
+            s = s.substring(n + 1);
+        }
+        
+        TermTextArea tta = stdout ? text : errorText;
+        
+        tta.append(s);
+        tta.setCaretPosition(tta.getDocument().getLength());       
+    }
+    
+    public void writeToTerminal(String s)
+    {
+        writeToPane(true, s);
+    }
+    
+    /**
+     * Prepare the terminal for I/O.
+     */
+    private void prepare()
+    {
+        if (newMethodCall) {   // prepare only once per method call
+            showHide(true);
+            newMethodCall = false;
+        }
+        else if (Config.isGreenfoot()) {
+            // In greenfoot new output should always show the terminal
+            if (! isVisible()) {
+                showHide(true);
+            }
+        }
+    }
+
+    /**
+     * An interactive method call has been made by a user.
+     */
+    private void methodCall(String callString, boolean isVoid)
+    {
+        newMethodCall = false;
+        if(clearOnMethodCall) {
+            clear();
+        }
+        if(recordMethodCalls) {
+            if (isVoid) {
+                text.appendMethodCall(callString + ";\n");
+            }
+            else {
+                text.appendMethodCall(callString + "\n");
+            }
+        }
+        newMethodCall = true;
+    }
+    
+    private void constructorCall(InvokerRecord ir)
+    {
+        newMethodCall = false;
+        if(clearOnMethodCall) {
+            clear();
+        }
+        if(recordMethodCalls) {
+            String callString = ir.getResultTypeString() + " " + ir.getResultName() + " = " + ir.toExpression() + ";";
+            text.appendMethodCall(callString + "\n");
+        }
+        newMethodCall = true;
+    }
+    
+    private void methodResult(ExecutionEvent event)
+    {
+        if (recordMethodCalls) {
+            String result = null;
+            String resultType = event.getResult();
+            
+            if (resultType == ExecutionEvent.NORMAL_EXIT) {
+                DebuggerObject object = event.getResultObject();
+                if (object != null) {
+                    if (event.getClassName() != null && event.getMethodName() == null) {
+                        // Constructor call - the result object is the created object.
+                        // Don't display the result separately:
+                        return;
+                    }
+                    else {
+                        // if the method returns a void, we must handle it differently
+                        if (object.isNullObject()) {
+                            return; // Don't show result of void calls
+                        }
+                        else {
+                            // other - the result object is a wrapper with a single result field
+                            DebuggerField resultField = object.getField(0);
+                            result = "    returned " + resultField.getType().toString(true) + " ";
+                            result += resultField.getValueString();
+                        }
+                    }
+                }
+            }
+            else if (resultType == ExecutionEvent.EXCEPTION_EXIT) {
+                result = "    Exception occurred.";
+            }
+            else if (resultType == ExecutionEvent.TERMINATED_EXIT) {
+                result = "    VM terminated.";
+            }
+            
+            if (result != null) {
+                text.appendMethodCall(result + "\n");
+            }
+        }
+    }
+
+
+    /**
+     * Return the input stream that can be used to read from this terminal.
+     */
+    public Reader getReader()
+    {
+        return in;
+    }
+
+
+    /**
+     * Return the output stream that can be used to write to this terminal
+     */
+    public Writer getWriter()
+    {
+        return out;
+    }
+
+
+    /**
+     * Return the output stream that can be used to write error output to this terminal
+     */
+    public Writer getErrorWriter()
+    {
+        return err;
+    }
+
+    // ---- KeyListener interface ----
+
+    @Override
+    public void keyPressed(KeyEvent event)
+    {
+    }
+    
+    @Override
+    public void keyReleased(KeyEvent event)
+    {
+    }
+
+    @Override
+    public void keyTyped(KeyEvent event)
+    {
+        // We handle most things we are interested in here. The InputMap filters out
+        // most other unwanted actions (but allows copy/paste).
+        
+        char ch = event.getKeyChar();
+        switch (ch) {
+            
+        case KeyEvent.VK_EQUALS: // increase the font size
+        case KeyEvent.VK_PLUS: // increase the font size (non-uk keyboards)
+            if (event.getModifiers() == SHORTCUT_MASK) {
+                setTerminalFontSize(terminalFontSize + 1);
+                project.getTerminal().resetFont();
+                event.consume();
+                break;
+            }
+
+        case KeyEvent.VK_MINUS: // decrease the font size
+            if (event.getModifiers() == SHORTCUT_MASK) {
+                setTerminalFontSize(terminalFontSize - 1);
+                project.getTerminal().resetFont();
+                event.consume();
+                break;
+            }
+
+        // VK_(EQUALS|PLUS|MINUS) all fall through to here if no shortcut mask.
+        default:
+            if ((event.getModifiers() & Event.META_MASK) != 0) {
+                return; // return without consuming the event
+            }
+            if (isActive) {
+                switch (ch) {
+
+                case 4:   // CTRL-D (unix/Mac EOF)
+                case 26:  // CTRL-Z (DOS/Windows EOF)
+                    buffer.signalEOF();
+                    writeToTerminal("\n");
+                    event.consume();
+                    break;
+
+                case '\b':  // backspace
+                    if (buffer.backSpace()) {
+                        try {
+                            int length = text.getDocument().getLength();
+                            text.replaceRange("", length - 1, length);
+                        } catch (Exception exc) {
+                            Debug.reportError("bad location " + exc);
+                        }
+                    }
+                    event.consume();
+                    break;
+
+                case '\r':  // carriage return
+                case '\n':  // newline
+                    if (buffer.putChar('\n')) {
+                        writeToTerminal(String.valueOf(ch));
+                        buffer.notifyReaders();
+                    }
+                    event.consume();
+                    break;
+
+                default:
+                    if (ch >= 32) {
+                        if (buffer.putChar(ch)) {
+                            writeToTerminal(String.valueOf(ch));
+                        }
+                        event.consume();
+                    }
+                    break;
+                }
+            }
+            break;
+        }
+    }
+
+
+    // ---- BlueJEventListener interface ----
+
+    /**
+     * Called when a BlueJ event is raised. The event can be any BlueJEvent
+     * type. The implementation of this method should check first whether
+     * the event type is of interest an return immediately if it isn't.
+     *
+     * @param eventId  A constant identifying the event. One of the event id
+     *                 constants defined in BlueJEvent.
+     * @param arg      An event specific parameter. See BlueJEvent for
+     *                 definition.
+     */
+    @Override
+    public void blueJEvent(int eventId, Object arg)
+    {
+        initialise();
+        if(eventId == BlueJEvent.METHOD_CALL) {
+            InvokerRecord ir = (InvokerRecord) arg;
+            if (ir.getResultName() != null) {
+                constructorCall(ir);
+            }
+            else {
+                methodCall(ir.toExpression(), ir.hasVoidResult());
+            }
+        }
+        else if (eventId == BlueJEvent.EXECUTION_RESULT) {
+            methodResult((ExecutionEvent) arg);
+        }
+    }
+
+    // ---- make window frame ----
+
+    /**
+     * Create the Swing window.
+     */
+    private void makeWindow(int columns, int rows)
+    {
+        Image icon = BlueJTheme.getIconImage();
+        if (icon != null) {
+            setIconImage(icon);
+        }
+        text = new TermTextArea(rows, columns, buffer, project, this, false);
+        final InputMap origInputMap = text.getInputMap();
+        text.setInputMap(JComponent.WHEN_FOCUSED, new InputMap() {
+            {
+                setParent(origInputMap);
+            }
+            
+            @Override
+            public Object get(KeyStroke keyStroke)
+            {
+                Object actionName = super.get(keyStroke);
+                
+                if (actionName == null) {
+                    return null;
+                }
+                
+                char keyChar = keyStroke.getKeyChar();
+                if (keyChar == KeyEvent.CHAR_UNDEFINED || keyChar < 32) {
+                    // We might want to filter the action
+                    if ("copy-to-clipboard".equals(actionName)) {
+                        return actionName;
+                    }
+                    if ("paste-from-clipboard".equals(actionName)) {
+                        // Handled via paste() in TermTextArea
+                        return actionName;
+                    }
+                    return null;
+                }
+                
+                return actionName;
+            }
+        });
+        
+        scrollPane = new JScrollPane(text);
+        text.setFont(getTerminalFont());
+        text.setEditable(false);
+        text.setMargin(new Insets(6, 6, 6, 6));
+        text.addKeyListener(this);
+
+        getContentPane().add(scrollPane, BorderLayout.CENTER);
+
+        setJMenuBar(makeMenuBar());
+
+        // Close Action when close button is pressed
+        addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent event)
+            {
+                Window win = (Window)event.getSource();
+                
+                // don't allow them to close the window if the debug machine
+                // is running.. tries to stop them from closing down the
+                // input window before finishing off input in the terminal
+                if (project != null) {
+                    if (project.getDebugger().getStatus() == Debugger.RUNNING)
+                        return;
+                }
+                win.setVisible(false);
+            }
+        });
+
+        // save position when window is moved
+        addComponentListener(new ComponentAdapter() {
+            @Override
+                public void componentMoved(ComponentEvent event)
+                {
+                    Config.putLocation("bluej.terminal", getLocation());
+                }
+            });
+
+        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+        
+        setLocation(Config.getLocation("bluej.terminal"));
+
+        pack();
+    }
+
+    /**
+     * Create a second scrolled text area to the window, for error output.
+     */
+    private void createErrorPane()
+    {
+        errorText = new TermTextArea(Config.isGreenfoot() ? 20 : 5, 80, null, project, this, true);
+        errorScrollPane = new JScrollPane(errorText);
+        errorText.setFont(getTerminalFont());
+        errorText.setEditable(false);
+        errorText.setMargin(new Insets(6, 6, 6, 6));
+        errorText.setUnlimitedBuffering(true);
+
+        splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+                                   scrollPane, errorScrollPane); 
+    }
+    
+    /**
+     * Show the errorPane for error output
+     */
+    private void showErrorPane()
+    {
+        if(errorShown) {
+            return;
+        }
+        
+        //the first time the errortext is shown we need to pack() it
+        //to make it have the right size.
+        boolean isFirstShow = false; 
+        if(errorText == null) {
+            isFirstShow = true;
+            createErrorPane();
+        }
+     
+        getContentPane().remove(scrollPane);
+  
+        // We want to know if it is not the first time
+        // This means a "clear" has been used to remove the splitpane
+        // when this re-adds the scrollPane to the terminal area
+        // it implicitly removes it from the splitpane as it can only have one
+        // owner. The side-effect of this is the splitpane's
+        // top component becomes null.
+        if(!isFirstShow)
+            splitPane.setTopComponent(scrollPane);
+        getContentPane().add(splitPane, BorderLayout.CENTER);       
+        splitPane.resetToPreferredSizes();
+            
+        if(isFirstShow) {
+            pack();
+        } else {
+            validate();
+        }
+        
+        errorShown = true;
+    }
+    
+    /**
+     * Hide the pane with the error output.
+     */
+    private void hideErrorPane()
+    {
+        if(!errorShown) {
+            return;
+        }
+        getContentPane().remove(splitPane);
+        getContentPane().add(scrollPane, BorderLayout.CENTER);        
+        errorShown = false; 
+        validate();
+    }
+    
+    /**
+     * Create the terminal's menubar, all menus and items.
+     */
+    private JMenuBar makeMenuBar()
+    {
+        JMenuBar menubar = new JMenuBar();
+        JMenu menu = new JMenu(Config.getString("terminal.options"));
+        JMenuItem item;
+        item = menu.add(new ClearAction());
+        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_K,
+                                                   SHORTCUT_MASK));
+        item = menu.add(getCopyAction());
+        item.setText(Config.getString("terminal.copy"));
+        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,
+                                                   SHORTCUT_MASK));
+        item = menu.add(new SaveAction());
+        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
+                                                   SHORTCUT_MASK));
+        menu.add(new PrintAction());
+        menu.add(new JSeparator());
+
+        autoClear = new JCheckBoxMenuItem(new AutoClearAction());
+        autoClear.setSelected(clearOnMethodCall);
+        menu.add(autoClear);
+
+        recordCalls = new JCheckBoxMenuItem(new RecordCallAction());
+        recordCalls.setSelected(recordMethodCalls);
+        menu.add(recordCalls);
+
+        unlimitedBuffering = new JCheckBoxMenuItem(new BufferAction());
+        unlimitedBuffering.setSelected(unlimitedBufferingCall);
+        menu.add(unlimitedBuffering);
+
+        menu.add(new JSeparator());
+        item = menu.add(new CloseAction());
+        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W,
+                                                   SHORTCUT_MASK));
+
+        menubar.add(menu);
+        return menubar;
+    }
+    
+
+    private class ClearAction extends AbstractAction
+    {
+        public ClearAction()
+        {
+            super(Config.getString("terminal.clear"));
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            clear();
+        }
+    }
+
+    private class SaveAction extends AbstractAction
+    {
+        public SaveAction()
+        {
+            super(Config.getString("terminal.save"));
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            save();
+        }
+    }
+    
+    private class PrintAction extends AbstractAction
+    {
+        public PrintAction()
+        {
+            super(Config.getString("terminal.print"));
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            print();
+        }
+    }
+
+    private class CloseAction extends AbstractAction
+    {
+        public CloseAction()
+        {
+            super(Config.getString("terminal.close"));
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            showHide(false);
+        }
+    }
+
+    private Action getCopyAction()
+    {
+        Action[] textActions = text.getActions();
+        for (int i=0; i < textActions.length; i++) {
+            if(textActions[i].getValue(Action.NAME).equals("copy-to-clipboard")) {
+                return textActions[i];
+            }
+        }
+
+        return null;
+    }
+
+    private class AutoClearAction extends AbstractAction
+    {
+        public AutoClearAction()
+        {
+            super(Config.getString("terminal.clearScreen"));
+        }
+
+        public void actionPerformed(ActionEvent e)
+        {
+            clearOnMethodCall = autoClear.isSelected();
+            Config.putPropBoolean(CLEARONMETHODCALLSPROPNAME, clearOnMethodCall);
+        }
+    }
+
+    private class RecordCallAction extends AbstractAction
+    {
+        public RecordCallAction()
+        {
+            super(Config.getString("terminal.recordCalls"));
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            recordMethodCalls = recordCalls.isSelected();
+            Config.putPropBoolean(RECORDMETHODCALLSPROPNAME, recordMethodCalls);
+        }
+    }
+
+    private class BufferAction extends AbstractAction
+    {
+        public BufferAction()
+        {
+            super(Config.getString("terminal.buffering"));
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            unlimitedBufferingCall = unlimitedBuffering.isSelected();
+            text.setUnlimitedBuffering(unlimitedBufferingCall);
+            Config.putPropBoolean(UNLIMITEDBUFFERINGCALLPROPNAME, unlimitedBufferingCall);
+        }
+    }
+            
+    /**
+     * A Reader which reads from the terminal.
+     */
+    private class TerminalReader extends Reader
+    {
+        public int read(char[] cbuf, int off, int len)
+        {
+            initialise();
+            int charsRead = 0;
+
+            while(charsRead < len) {
+                cbuf[off + charsRead] = buffer.getChar();
+                charsRead++;
+                if(buffer.isEmpty())
+                    break;
+            }
+            return charsRead;
+        }
+
+        @Override
+        public boolean ready()
+        {
+            return ! buffer.isEmpty();
+        }
+        
+        public void close()
+        {
+        }
+    }
+
+    /**
+     * A writer which writes to the terminal. It can be flagged for error output.
+     * The idea is that error output could be presented differently from standard
+     * output.
+     */
+    private class TerminalWriter extends Writer
+    {
+        private boolean isErrorOut;
+        
+        TerminalWriter(boolean isError)
+        {
+            super();
+            isErrorOut = isError;
+        }
+
+        public void write(final char[] cbuf, final int off, final int len)
+        {
+            try {
+                // We use invokeAndWait so that terminal output is limited to
+                // the processing speed of the event queue. This means the UI
+                // will still respond to user input even if the output is really
+                // gushing.
+                EventQueue.invokeAndWait(new Runnable() {
+                    public void run()
+                    {
+                        initialise();
+                        writeToPane(!isErrorOut, new String(cbuf, off, len));
+                    }
+                });
+            }
+            catch (InvocationTargetException ite) {
+                ite.printStackTrace();
+            }
+            catch (InterruptedException ie) {}
+        }
+
+        public void flush()
+        {
+        }
+
+        public void close()
+        {
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalButtonModel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalButtonModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..be8c72d8ea03670c090ac351b91f961739d6e53d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalButtonModel.java
@@ -0,0 +1,67 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.terminal;
+
+import javax.swing.JToggleButton;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * ButtonModel for the "Show Terminal" checkBoxItem in the menu.
+ * This model takes care that the right things happen when the checkbox
+ * is shown or changed.
+ *
+ * @author Michael Kolling
+ */
+public class TerminalButtonModel extends JToggleButton.ToggleButtonModel
+{
+    private PkgMgrFrame pmf;
+    
+    public TerminalButtonModel(PkgMgrFrame pmf)
+    {
+        super();
+        this.pmf = pmf;
+    }
+
+    public boolean isSelected()
+    {
+        if (pmf.isEmptyFrame()) {
+            // if no project is open, we default to off
+            return false;
+        }
+        else if (!pmf.getProject().hasTerminal()) {
+            return false;
+        }
+        else {
+            // otherwise, ask the Terminal if it is visible
+            return pmf.getProject().getTerminal().isVisible();
+        }
+    }
+
+    public void setSelected(boolean b)
+    {
+        if (!pmf.isEmptyFrame()) {
+            super.setSelected(b);
+            pmf.getProject().getTerminal().showHide(b);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalDocument.java b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalDocument.java
new file mode 100644
index 0000000000000000000000000000000000000000..e85664d057a1618c6ffed796e06aa2cf898908d8
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalDocument.java
@@ -0,0 +1,357 @@
+/*
+ This file is part of the BlueJ program.
+ Copyright (C) 2011  Michael Kolling and John Rosenberg
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ This file is subject to the Classpath exception as provided in the
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.terminal;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.GapContent;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.Position;
+import javax.swing.text.Segment;
+
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.Package;
+import bluej.utility.JavaNames;
+
+/**
+ * Document implementation for the terminal editor pane.
+ * 
+ * <p>This is mainly necessary to override PlainDocument's slightly brain-damaged
+ * implementation of the insertUpdate() method, which can clear line attributes
+ * unexpectedly (insertUpdate method).
+ * 
+ * <p>It also allows highlighting of exception stack traces
+ * 
+ * @author Davin McCall
+ */
+public class TerminalDocument extends AbstractDocument
+{
+    Element root;
+    private boolean highlightSourceLinks;
+    private Project project;
+    
+    public TerminalDocument(Project project, boolean highlightSourceLinks)
+    {
+        super(new GapContent());
+        root = createDefaultRoot();
+        this.project = project;
+        this.highlightSourceLinks = highlightSourceLinks;
+    }
+    
+    /**
+     * Mark a line as displaying method output.
+     * 
+     * @param line  The line number (0..N)
+     */
+    public void markLineAsMethodOutput(int line)
+    {
+        writeLock();
+        
+        Element el = root.getElement(line);
+        MutableAttributeSet attr = (MutableAttributeSet) el.getAttributes();
+        attr.addAttribute(TerminalView.METHOD_RECORD, Boolean.valueOf(true));
+        
+        writeUnlock();
+    }
+    
+    @Override
+    public Element getDefaultRootElement()
+    {
+        return root;
+    }
+    
+    @Override
+    public Element getParagraphElement(int pos)
+    {
+        int index = root.getElementIndex(pos);
+        return root.getElement(index);
+    }
+    
+    protected AbstractElement createDefaultRoot()
+    {
+        BranchElement map = (BranchElement) createBranchElement(null, null);
+        Element[] lines = new Element[1];
+        lines[0] = new LeafElement(map, null, 0, 1);;
+        map.replace(0, 0, lines);
+        return map;
+    }
+    
+    @Override
+    protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr)
+    {
+        BranchElement lineMap = (BranchElement) getDefaultRootElement();
+        int offset = chng.getOffset();
+        int length = chng.getLength();
+        
+        Segment s = new Segment();
+        try {
+            getText(offset, length, s);
+        }
+        catch (BadLocationException ble) {
+            throw new RuntimeException(ble);
+        }
+        
+        int index = lineMap.getElementIndex(offset);
+        LeafElement firstAffected = (LeafElement) lineMap.getElement(index);
+        
+        int lindex = lineMap.getElementIndex(offset + length);
+        LeafElement nextLine = (LeafElement) lineMap.getElement(lindex);
+        
+        if (offset > 0 && (offset + length) == nextLine.getStartOffset()) {
+            // Inserting at a position moves the position, unless the position is 0.
+            // So inserting at the beginning of a line moves the line start position,
+            // and the previous line end position, which need to be reset:
+            firstAffected.setEndOffset(offset);
+            nextLine.setStartOffset(offset);
+            firstAffected = nextLine;
+            nextLine = (LeafElement) lineMap.getElement(lindex + 1);
+        }
+        
+        ArrayList<LeafElement> added = new ArrayList<LeafElement>();
+        
+        for (int i = 0; i < s.length(); i++) {
+            if (s.charAt(i) == '\n') {
+                // line break!
+                int origEnd = firstAffected.getEndOffset();
+                firstAffected.setEndOffset(i + offset + 1);
+                LeafElement newFirst = new LeafElement(root, attr, i + offset + 1, origEnd);
+                added.add(newFirst);
+                firstAffected = newFirst;
+            }
+        }
+        
+        if (! added.isEmpty()) {
+            Element [] removed = new Element[0];
+            Element [] addedArr = new Element[added.size()];
+            added.toArray(addedArr);
+            lineMap.replace(lindex + 1, 0, addedArr);
+            ElementEdit ee = new ElementEdit(lineMap, lindex + 1, removed, addedArr);
+            chng.addEdit(ee);
+        }
+        
+        if (highlightSourceLinks)
+            scanForStackTrace();
+
+        super.insertUpdate(chng, attr);
+    }
+
+    /**
+     * Looks through the contents of the terminal for lines
+     * that look like they are part of a stack trace.
+     */
+    private void scanForStackTrace()
+    {
+        try {
+            String content = getText(0, getLength());
+            
+            Pattern p = java.util.regex.Pattern.compile("at (\\S+)\\((\\S+)\\.java:(\\d+)\\)");
+            // Matches things like:
+            // at greenfoot.localdebugger.LocalDebugger$QueuedExecution.run(LocalDebugger.java:267)
+            //    ^--------------------group 1----------------------------^ ^--group 2--^      ^3^
+            Matcher m = p.matcher(content);
+            while (m.find())
+            {
+                int elementIndex = getDefaultRootElement().getElementIndex(m.start());
+                Element el = getDefaultRootElement().getElement(elementIndex);
+                MutableAttributeSet attr = (MutableAttributeSet) el.getAttributes();
+                
+                String fullyQualifiedMethodName = m.group(1);
+                String javaFile = m.group(2);
+                int lineNumber = Integer.parseInt(m.group(3));
+                
+                // The fully qualified method name will end in ".method", so we can
+                // definitely remove that:
+                
+                String fullyQualifiedClassName = JavaNames.getPrefix(fullyQualifiedMethodName);
+                // The class name may be an inner class, so we want to take the package:
+                String packageName = JavaNames.getPrefix(fullyQualifiedClassName);
+                
+                //Find out if that file is available, and only link if it is:                
+                Package pkg = project.getPackage(packageName);
+                
+                if (pkg != null && pkg.getAllClassnames().contains(javaFile))
+                {
+                    attr.addAttribute(TerminalView.SOURCE_LOCATION, new ExceptionSourceLocation(m.start(1), m.end(), pkg, javaFile, lineNumber));
+                }
+                else
+                {
+                    attr.addAttribute(TerminalView.FOREIGN_STACK_TRACE, Boolean.valueOf(true));
+                }
+            }
+            
+            //Also mark up native method lines in stack traces with a marker for font colour:
+            
+            p = java.util.regex.Pattern.compile("at \\S+\\(Native Method|Unknown Source\\)");
+            // Matches things like:
+            //  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+            m = p.matcher(content);
+            while (m.find())
+            {
+                int elementIndex = getDefaultRootElement().getElementIndex(m.start());
+                Element el = getDefaultRootElement().getElement(elementIndex);
+                MutableAttributeSet attr = (MutableAttributeSet) el.getAttributes();
+                
+                attr.addAttribute(TerminalView.FOREIGN_STACK_TRACE, Boolean.valueOf(true));
+            }
+        }
+        catch (BadLocationException e) {
+            e.printStackTrace();
+        }
+        catch (NumberFormatException e ) {
+            //In case it looks like an exception but has a large line number:
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    protected void removeUpdate(DefaultDocumentEvent chng)
+    {
+        BranchElement lineMap = (BranchElement) getDefaultRootElement();
+        int offset = chng.getOffset();
+        int length = chng.getLength();
+        
+        int index = lineMap.getElementIndex(offset);
+        
+        LeafElement first = (LeafElement) lineMap.getElement(index);
+        if (first.getEndOffset() > (offset + length)) {
+            return; // only removing part of a line
+        }
+        
+        ArrayList<Element> removed = new ArrayList<Element>();
+        
+        int lastIndex = index + 1;
+        LeafElement last = (LeafElement) lineMap.getElement(lastIndex);
+        removed.add(last);
+        while (last.getEndOffset() <= (offset + length)) {
+            lastIndex++;
+            last = (LeafElement) lineMap.getElement(lastIndex);
+            removed.add(last);
+        }
+        
+        first.end = last.end;
+        lineMap.replace(index, lastIndex - index, new Element[0]);
+        Element[] removedArr = new Element[removed.size()];
+        removed.toArray(removedArr);
+        ElementEdit ee = new ElementEdit(lineMap, index + 1, removedArr, new Element[0]);
+        chng.addEdit(ee);
+        
+        super.removeUpdate(chng);
+    }
+    
+    /**
+     * Special purposed leaf element which allows resetting the start and end
+     * positions.
+     */
+    public class LeafElement extends AbstractElement
+    {
+        Position start;
+        Position end;
+        
+        public LeafElement(Element parent, AttributeSet attrs, int startOffs, int endOffs)
+        {
+            super(parent, attrs);
+            try {
+                start = createPosition(startOffs);
+                end = createPosition(endOffs);
+            }
+            catch (BadLocationException ble) {
+                throw new RuntimeException(ble);
+            }
+        }
+        
+        @Override
+        public int getStartOffset()
+        {
+            return start.getOffset();
+        }
+        
+        @Override
+        public int getEndOffset()
+        {
+            return end.getOffset();
+        }
+        
+        public void setStartOffset(int offset)
+        {
+            try {
+                start = createPosition(offset);
+            }
+            catch (BadLocationException ble) {
+                throw new RuntimeException();
+            }
+        }
+
+        public void setEndOffset(int offset)
+        {
+            try {
+                end = createPosition(offset);
+            }
+            catch (BadLocationException ble) {
+                throw new RuntimeException();
+            }
+        }
+        
+        @Override
+        public int getElementCount()
+        {
+            return 0;
+        }
+        
+        @Override
+        public Element getElement(int index)
+        {
+            return null;
+        }
+        
+        @Override
+        public int getElementIndex(int offset)
+        {
+            return 0;
+        }
+        
+        @Override
+        public boolean isLeaf()
+        {
+            return true;
+        }
+        
+        @Override
+        public Enumeration children()
+        {
+            return new Vector().elements();
+        }
+        
+        @Override
+        public boolean getAllowsChildren()
+        {
+            return false;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalPrinter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalPrinter.java
new file mode 100644
index 0000000000000000000000000000000000000000..c26e75f878d87fd29410a1d426c672ea81bd9c6d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalPrinter.java
@@ -0,0 +1,221 @@
+/*
+ This file is part of the BlueJ program.
+ Copyright (C) 2010,2011  Michael Kolling and John Rosenberg
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ This file is subject to the Classpath exception as provided in the
+ LICENSE.txt file that accompanied this code.
+ */
+
+package bluej.terminal;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.print.Book;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+import javax.swing.text.Segment;
+import javax.swing.text.StyleContext;
+import javax.swing.text.TabExpander;
+import javax.swing.text.Utilities;
+
+import bluej.utility.Debug;
+import bluej.utility.Utility;
+
+/**
+ * Handles the printing of the Terminal window, including pagination and line-wrapping.
+ *
+ * @author nccb
+ *
+ */
+public class TerminalPrinter
+{
+    // This is done to match with the terminal text area which uses the
+    // JTextArea default, which is that every tab is 8 spaces:
+    private static final int tabSize = 8;
+    
+    private static final int PADDING = 5;
+    
+    public static class TerminalPage implements Printable
+    {
+        private List<String> pageText;
+        private Font font;
+        
+        public TerminalPage(List<String> pageText, Font font)
+        {
+            this.pageText = pageText;
+            this.font = font;
+        }
+
+        public int print(Graphics g, PageFormat pageFormat, int pageIndex)
+                throws PrinterException
+        {
+            
+            // the printing part
+            int position;
+            g.setFont(this.font);     // Set the font
+            g.setColor(Color.black);  // set color
+
+            // get co-ordinates for frame
+            int xPosition = (int)pageFormat.getImageableX(); 
+            int yPosition = (int)pageFormat.getImageableY();
+            int width = (int)pageFormat.getImageableWidth();
+            int height = (int)pageFormat.getImageableHeight();
+            
+            // Get some style information:
+            StyleContext context = new StyleContext();
+            final FontMetrics fontMetrics = context.getFontMetrics(font);
+            
+            // print main text area
+            int textYPosition = yPosition; // + HEADER_SPACE;
+            int textXPosition = xPosition + PADDING; // + (lineNumbers ? LINE_NUMBER_WIDTH : 0);
+            g.drawRect(xPosition, textYPosition, width, height /* - (HEADER_SPACE + FOOTER_SPACE)*/);
+            
+            // print the text
+            for(ListIterator<String> li = pageText.listIterator(); li.hasNext(); ) {
+                position = textYPosition + (this.font.getSize() + 2) * (li.nextIndex() + 1);
+                String line = li.next();
+                
+                int x = textXPosition;
+                
+                // workaround for strange problem on Mac:
+                // trying to print empty lines throws exception
+                if (line.length() == 0) {
+                    char[] nonBlank = new char[] {' '};
+                    Segment lineSeg = new Segment(nonBlank,0,1);
+                    x = Utilities.drawTabbedText(lineSeg, x, position, g, null, 0);
+                }
+                else {
+                    Segment lineSeg = new Segment(line.toCharArray(), 0, line.length());
+                    TabExpander tab = Utility.makeTabExpander(line, tabSize, fontMetrics);
+                    x = Utilities.drawTabbedText(lineSeg,x,position,g,tab,0);                    
+                } 
+            }
+   
+            return Printable.PAGE_EXISTS;   // print the page
+
+        }
+
+    }
+
+    public static boolean printTerminal(PrinterJob job, TermTextArea textArea, PageFormat pageFormat, Font font)
+    {
+        try {
+            Book pages = paginateText(textArea, pageFormat, font);        
+
+            // set the book pageable so the printjob knows 
+            // we are printing more than one page (maybe)
+            job.setPageable(pages);
+            job.print();
+                
+            return true;
+        }
+        catch (Exception e) {
+            // should it be an error dialog?
+            Debug.reportError("Exception thrown during printing: " + e);
+            e.printStackTrace();
+            return false;
+        }
+
+    }
+
+    private static Book paginateText(TermTextArea textArea, PageFormat pageFormat, Font font)
+    {
+        // It is important to make a new linked list because we may
+        // manipulate it later if lines need to be wrapped:
+        List<String> text = new LinkedList<String>(Arrays.asList(textArea.getText().split("\r\n|\r|\n")));
+        
+        Book book = new Book();
+        int pageNum = 1;        // page #
+
+        // height of text area of a page
+        int height = (int)pageFormat.getImageableHeight(); // - (HEADER_SPACE + FOOTER_SPACE);
+
+        // number of lines on a page
+        int linesPerPage = height / (font.getSize() + 2);   
+        wrapLines(text, pageFormat, font);
+
+        // set number of pages
+        int numberOfPages = ((int)(text.size() / linesPerPage)) + 1;  
+
+        List<String> pageText;      // one page of text
+
+        ListIterator<String> li = text.listIterator();
+        while ( pageNum <= numberOfPages) {
+            pageText = new ArrayList<String>(); 
+
+            for (int lineCount = 0; li.hasNext() && lineCount < linesPerPage; lineCount++) { 
+                pageText.add(li.next());
+            }
+        
+            // create a new page object with the text and add it to the book
+            book.append(new TerminalPage(pageText, font), pageFormat);  
+            pageNum++;   // increase the page number I am on
+        }
+        return book;  // return the completed book
+    }
+    
+    /**
+     * Wraps lines so that long lines of text outside of print page dimensions for a 
+     * given page format and font are printed as a new line.  This method iterates 
+     * through each line of text, calculates if there is an overlap and inserts 
+     * overlapping text on the next line.
+     */
+    private static void wrapLines(List<String> text, PageFormat format, Font font)
+    {
+        // code to wrap lines of text for printing
+        // get a line, get its length, do some font metrics,
+        StyleContext context = new StyleContext();
+        FontMetrics fontMetrics = context.getFontMetrics(font);
+        int maxWidth = (int)format.getImageableWidth() - (PADDING * 2);
+        int fontWidth = fontMetrics.charWidth('m');           
+        int chars = maxWidth / fontWidth;
+
+        for(ListIterator<String> li = text.listIterator(); li.hasNext(); ) {
+            String pl = li.next();
+            String currentLine = Utility.convertTabsToSpaces(pl.toString(), tabSize);
+            int currentLineLength = currentLine.length();
+            int width = fontMetrics.stringWidth(currentLine);
+            
+            // if line needs to be wrapped
+            if(width > maxWidth) {
+                int[] tabSpaces = Utility.calculateTabSpaces(pl.toString(), tabSize);
+                // remove original
+                li.remove();
+                double iterations = (currentLineLength / chars) + 1;
+                for(int begin = 0, end = 0; iterations > 0; iterations--, begin = Utility.advanceChars(pl.toString(),tabSpaces,begin,chars)) {
+                    end = Utility.advanceChars(pl.toString(),tabSpaces,begin,chars);
+                    
+                    String newSubString = pl.substring(begin, end);
+                    if(newSubString.length() != 0)
+                    {
+                        li.add(newSubString);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalView.java
new file mode 100644
index 0000000000000000000000000000000000000000..539062d03abda95416176293a9ab858107290d02
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/terminal/TerminalView.java
@@ -0,0 +1,157 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.terminal;
+
+import bluej.Config;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Toolkit;
+import java.util.Map;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.PlainView;
+import javax.swing.text.Segment;
+import javax.swing.text.Utilities;
+
+/**
+ * A View implementation for the terminal. Styles lines representing recorded method
+ * calls (and their results) differently to regular text.
+ * 
+ * @author Davin McCall
+ */
+public class TerminalView extends PlainView
+{
+    public static final String METHOD_RECORD = "method-record";
+    public static final String FOREIGN_STACK_TRACE = "foreign-stack-trace";    
+    public static final String SOURCE_LOCATION = "source-location";
+    
+
+    private static final Color STDOUT_TEXT_COLOR = Color.BLACK;
+    private static final Color STDERR_TEXT_COLOR = Color.RED;
+    private static final Color STACK_LOCAL_TEXT_COLOR = new Color(255, 96, 96); // Colour of lines in stack trace with clickable portion (i.e. local code)
+    private static final Color STACK_FOREIGN_TEXT_COLOR = Color.LIGHT_GRAY; // Colour of lines in stack trace with clickable portion (i.e. local code)
+    private static final Color METHOD_RECORD_COLOR = Config.ENV_COLOUR;
+    
+    public TerminalView(Element el, boolean isStderr)
+    {
+        super(el);
+    }
+
+    public static Color getDefaultColor(boolean isStderr)
+    {
+        return isStderr ? STDERR_TEXT_COLOR : STDOUT_TEXT_COLOR;
+    }
+    
+    @Override
+    protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
+        throws BadLocationException
+    {
+        try {
+            //Set correct rendering hints for graphics:
+            Toolkit tk = Toolkit.getDefaultToolkit(); 
+            Map<?,?> hints = (Map<?,?>) (tk.getDesktopProperty("awt.font.desktophints"));
+            
+            if (hints != null && g instanceof Graphics2D) {
+                Graphics2D g2d = (Graphics2D) g;
+                g2d.addRenderingHints(hints); 
+            }
+            
+        
+            Document doc = getDocument();
+            int elementIndex = doc.getDefaultRootElement().getElementIndex(p0);
+            Element el = doc.getDefaultRootElement().getElement(elementIndex);
+            
+            AttributeSet attrs = el.getAttributes();
+            if (attrs != null && (attrs.getAttribute(METHOD_RECORD) != null
+                                  || attrs.getAttribute(FOREIGN_STACK_TRACE) != null)) {
+                g.setColor(attrs.getAttribute(METHOD_RECORD) != null ? METHOD_RECORD_COLOR : STACK_FOREIGN_TEXT_COLOR);
+                Segment s = new Segment();
+                doc.getText(p0, p1 - p0, s);
+                return Utilities.drawTabbedText(s, x, y, g, this, p0);
+            } else if (attrs != null && attrs.getAttribute(SOURCE_LOCATION) != null) {
+                ExceptionSourceLocation esl = (ExceptionSourceLocation) attrs.getAttribute(SOURCE_LOCATION);
+                Segment s = new Segment();
+                
+                g.setColor(STACK_LOCAL_TEXT_COLOR);
+                
+                
+                // So we have some underline on this line, and we want to draw a portion of the line,
+                // which may or may not overlap the underline in any fashion, i.e.
+                
+                //  at Foo.foo2(Foo.java:26)
+                //              ^ esl.getStart()
+                //                         ^ esl.getEnd()
+                // and p0 and p1 will be anywhere on the line, with p0 < p1.
+                //
+                // So we will form three groups of text:
+                // 1. Pre-underline.  The part from p0, up to the earliest of: the beginning of the underline (esl.getStart()), or p1
+                //      (which should be ignored, if p0 >= esl.getStart())
+                // 2. Underlined.  The part from the (the latest of: beginning of the underline, or p0) up to (the earliest of: the end of the underline, or p1)
+                //      (which should be ignored, if p1 <= esl.getStart() or p0 >= esl.getEnd())
+                // 3. Post-underline.  The part from (the latest of: the end of the underline, or p0) up to p1
+                //      (which should be ignored, if p1 <= esl.getEnd())
+    
+                int startUnderline = Math.max(p0, Math.min(esl.getStart(), p1));
+                int endUnderline = Math.max(p0, Math.min(esl.getEnd(), p1));
+                
+                // Group 1, pre-underline:            
+                if (p0 < esl.getStart())
+                {
+                    doc.getText(p0, startUnderline - p0, s);
+                    x = Utilities.drawTabbedText(s, x, y, g, this, p0);
+                }
+                // Group 2, underline:
+                if (p0 < esl.getEnd() && p1 > esl.getStart())
+                {
+                    int startX = x;
+                    doc.getText(startUnderline, endUnderline - startUnderline, s);
+                    x = Utilities.drawTabbedText(s, x, y, g, this, startUnderline);
+                    g.drawLine(startX, y + 1, x, y + 1);
+                }
+                // Group 3, post-underline:
+                if (p1 > esl.getEnd())
+                {
+                    doc.getText(endUnderline, p1 - endUnderline, s);
+                    x = Utilities.drawTabbedText(s, x, y, g, this, endUnderline);
+                }
+                return x;
+            }
+            else {
+                return super.drawUnselectedText(g, x, y, p0, p1);
+            }
+        
+        }
+        catch (BadLocationException e)
+        {
+            // Print the stack trace, because (as I found out due to bitter experience)
+            // the JDK won't print it, it will display a different problem
+            // (javax.swing.text.StateInvariantError):
+            e.printStackTrace();
+            throw e;
+        }
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/CounterPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/CounterPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce38de7ee3c397413123f7ad4f3857ff8adf307d
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/CounterPanel.java
@@ -0,0 +1,152 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+import bluej.Config;
+
+/**
+ * A panel with test run counters.
+ *
+ * @author  Andrew Patterson (derived from JUnit src)
+ */
+public class CounterPanel extends JPanel
+{
+    private JLabel fNumberOfErrors;
+    private JLabel fNumberOfFailures;
+    private JLabel fTotalTime;
+    private JLabel fNumberOfRuns;
+    final static Icon fFailureIcon = Config.getFixedImageAsIcon("failure.gif");
+    final static Icon fErrorIcon = Config.getFixedImageAsIcon("error.gif");
+
+    private int fTotal;
+
+    public CounterPanel()
+    {
+        super(new GridBagLayout());
+        fNumberOfErrors= createOutputField(5);
+        fNumberOfFailures= createOutputField(5);
+        fNumberOfRuns= createOutputField(9);
+        fTotalTime = createOutputField(9);
+
+        addToGrid(new JLabel(Config.getString("testdisplay.counter.runs"), JLabel.CENTER),
+                0, 0, 1, 1, 0.0, 0.0,
+                GridBagConstraints.CENTER, GridBagConstraints.NONE,
+                new Insets(0, 0, 0, 0));
+        addToGrid(fNumberOfRuns,
+                1, 0, 1, 1, 0.33, 0.0,
+                GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
+                new Insets(0, 8, 0, 0));
+
+        addToGrid(new JLabel(Config.getString("testdisplay.counter.errors"), fErrorIcon, SwingConstants.LEFT),
+                2, 0, 1, 1, 0.0, 0.0,
+                GridBagConstraints.CENTER, GridBagConstraints.NONE,
+                new Insets(0, 8, 0, 0));
+        addToGrid(fNumberOfErrors,
+                3, 0, 1, 1, 0.33, 0.0,
+                GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
+                new Insets(0, 8, 0, 0));
+
+        addToGrid(new JLabel(Config.getString("testdisplay.counter.failures"), fFailureIcon, SwingConstants.LEFT),
+                4, 0, 1, 1, 0.0, 0.0,
+                GridBagConstraints.CENTER, GridBagConstraints.NONE,
+                new Insets(0, 8, 0, 0));
+        addToGrid(fNumberOfFailures,
+                5, 0, 1, 1, 0.33, 0.0,
+                GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
+                new Insets(0, 8, 0, 0));
+
+        addToGrid(new JLabel(Config.getString("testdisplay.counter.totalTime"), SwingConstants.LEFT),
+                6, 0, 1, 1, 0.0, 0.0,
+                GridBagConstraints.CENTER, GridBagConstraints.NONE,
+                new Insets(0, 8, 0, 0));
+        addToGrid(fTotalTime,
+                7, 0, 1, 1, 0.33, 0.0,
+                GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
+                new Insets(0, 8, 0, 0));
+
+        setMaximumSize(new Dimension(getMaximumSize().width, getPreferredSize().height));
+    }
+
+    private JLabel createOutputField(int width) {
+        JLabel field= new JLabel("0");
+        Dimension size = field.getMinimumSize();
+        size.width *= width;
+        field.setMinimumSize(size);
+
+        return field;
+    }
+
+    public void addToGrid(Component comp,
+            int gridx, int gridy, int gridwidth, int gridheight,
+            double weightx, double weighty,
+            int anchor, int fill,
+            Insets insets) {
+
+        GridBagConstraints constraints= new GridBagConstraints();
+        constraints.gridx= gridx;
+        constraints.gridy= gridy;
+        constraints.gridwidth= gridwidth;
+        constraints.gridheight= gridheight;
+        constraints.weightx= weightx;
+        constraints.weighty= weighty;
+        constraints.anchor= anchor;
+        constraints.fill= fill;
+        constraints.insets= insets;
+        add(comp, constraints);
+    }
+
+    public void reset() {
+        setLabelValue(fNumberOfErrors, 0);
+        setLabelValue(fNumberOfFailures, 0);
+        setLabelValue(fTotalTime, 0);
+        setLabelValue(fNumberOfRuns, 0);
+        fTotal= 0;
+    }
+
+    public void setTotal(int value) {
+        fTotal= value;
+    }
+
+    public void setRunValue(int value) {
+        fNumberOfRuns.setText(Integer.toString(value) + "/" + fTotal);
+    }
+
+    public void setErrorValue(int value) {
+        setLabelValue(fNumberOfErrors, value);
+    }
+
+    public void setFailureValue(int value) {
+        setLabelValue(fNumberOfFailures, value);
+    }
+
+    public void setTotalTime(int value) {
+        fTotalTime.setText(Integer.toString(value)+"ms");
+    }
+
+    private void setLabelValue(JLabel label, int value) {
+        label.setText(Integer.toString(value));
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/ProgressBar.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/ProgressBar.java
new file mode 100644
index 0000000000000000000000000000000000000000..c187d605026f9d0707c6a65eb86d297cfef0666a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/ProgressBar.java
@@ -0,0 +1,69 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr;
+
+import java.awt.Color;
+
+import javax.swing.JProgressBar;
+
+/**
+ * A progress bar showing the green/red status.
+ * 
+ * @author Andrew Patterson (derived from JUnit src)
+ * @version $Id: ProgressBar.java 6215 2009-03-30 13:28:25Z polle $
+ */
+class ProgressBar extends JProgressBar
+{
+    public static final Color redBarColour = new Color(208, 16, 16);
+    public static final Color greenBarColour = new Color(32, 192, 32);
+
+    private boolean fError = false;
+
+    public ProgressBar() 
+    {
+        super();
+        setForeground(getStatusColor());
+    }
+
+    private Color getStatusColor()
+    {
+        if(fError)
+            return redBarColour;
+        return greenBarColour;
+    }
+
+    public void reset()
+    {
+        fError = false;
+        setForeground(getStatusColor());
+        setValue(0);
+    }
+
+    public void step(int value, boolean successful)
+    {
+        setValue(value);
+        if(!fError && !successful) {
+            fError = true;
+            setForeground(getStatusColor());
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/TestDisplayButtonModel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/TestDisplayButtonModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6e8de5e826add623e9493021bd0bf80d9dcecc3
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/TestDisplayButtonModel.java
@@ -0,0 +1,49 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr;
+
+import javax.swing.JToggleButton.ToggleButtonModel;
+
+/**
+ * ButtonModel for the "Show Test Runner" checkBoxItem in the menu.
+ * This model takes care that the right things happen when the checkbox
+ * is shown or changed.
+ *
+ * @author  Michael Kolling
+ * @version $Id: TestDisplayButtonModel.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class TestDisplayButtonModel extends ToggleButtonModel
+{
+    long timeStamp = 0;  // for bug fix
+
+    public boolean isSelected()
+    {
+        return TestDisplayFrame.isFrameShown();
+    }
+
+    public void setSelected(boolean b)
+    {
+        super.setSelected(b);
+        TestDisplayFrame.getTestDisplay().showTestDisplay(b);
+    }
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/TestDisplayFrame.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/TestDisplayFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..07f3a8f9098c4aa0d7fba4fde8c545747ddf7c3c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/TestDisplayFrame.java
@@ -0,0 +1,476 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.*;
+
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.debugger.DebuggerTestResult;
+import bluej.debugger.SourceLocation;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.Project;
+import bluej.utility.GradientFillPanel;
+import bluej.utility.JavaNames;
+import java.awt.Image;
+
+/**
+ * A Swing based user interface to run tests.
+ *
+ * @author  Andrew Patterson
+ */
+public class TestDisplayFrame
+{
+    // -- static singleton factory method --
+
+    static TestDisplayFrame singleton = null;
+
+    public synchronized static TestDisplayFrame getTestDisplay()
+    {
+        if(singleton == null) {
+            singleton = new TestDisplayFrame();
+        }
+        return singleton;
+    }
+
+    public static boolean isFrameShown()
+    {
+        if(singleton == null) {
+            return false;
+        }
+        else {
+            return singleton.isShown();
+        }
+    }
+
+    private JFrame frame;
+    private DefaultListModel testEntries;
+
+    private JList testnames;
+    private ProgressBar progressBar;
+    private GridBagConstraints pbConstraints;
+    private JPanel statusLabel;
+    private JPanel bottomPanel;
+    
+    // index of the progress bar in the topPanel's components
+    private final static int PROGRESS_BAR_INDEX = 0;
+    
+    private CounterPanel counterPanel;
+    private int errorCount;
+    private int failureCount;
+    private int totalTimeMs;
+    private int testTotal;
+    private boolean doingMultiple;
+        
+    // private FailureDetailView fdv;
+    private JTextArea exceptionMessageField;
+    private JButton showSourceButton;
+    
+    private Project lastProject;
+    
+    public TestDisplayFrame()
+    {
+        testTotal = 0;
+        errorCount = 0;
+        failureCount = 0;
+        totalTimeMs = 0;
+        doingMultiple = false;
+
+        createUI();
+    }
+
+    /**
+     * Show or hide the test display window.
+     */
+    public void showTestDisplay(boolean doShow)
+    {
+        frame.setVisible(doShow);
+    }
+
+    /**
+     * Return true if the window is currently displayed.
+     */
+    public boolean isShown()
+    {
+        return frame.isShowing();
+    }
+    
+    /**
+     * Create the user-interface for the error display dialog.
+     */
+    protected void createUI()
+    {
+        frame = new JFrame(Config.getString("testdisplay.title"));
+        frame.setContentPane(new GradientFillPanel(frame.getContentPane().getLayout()));
+
+        Image icon = BlueJTheme.getIconImage();
+        if (icon != null) {
+            frame.setIconImage(icon);
+        }
+        frame.setLocation(Config.getLocation("bluej.testdisplay"));
+
+        // save position when window is moved
+        frame.addComponentListener(new ComponentAdapter() {
+            public void componentMoved(ComponentEvent event)
+            {
+                Config.putLocation("bluej.testdisplay", frame.getLocation());
+            }
+        });
+
+        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+        splitPane.setBorder(BlueJTheme.generalBorder);
+        splitPane.setResizeWeight(0.5);
+        splitPane.setOpaque(false);
+        
+        JScrollPane resultScrollPane = new JScrollPane();
+        {
+            testEntries = new DefaultListModel();
+            testnames = new JList(testEntries);
+            testnames.setCellRenderer(new MyCellRenderer());
+            testnames.addListSelectionListener(new MyListSelectionListener());
+            testnames.addMouseListener(new ShowSourceListener());
+                        
+            resultScrollPane.setViewportView(testnames);
+        }
+        splitPane.setTopComponent(resultScrollPane);
+        
+        bottomPanel = new JPanel();
+        bottomPanel.setOpaque(false);
+        {
+            bottomPanel.setLayout(new GridBagLayout());
+            GridBagConstraints constraints = new GridBagConstraints();
+            
+            constraints.fill = GridBagConstraints.BOTH;
+            constraints.weightx = 1.0;
+            constraints.weighty = 0;
+            constraints.gridx = 0;
+            
+            progressBar = new ProgressBar();
+            bottomPanel.add(progressBar, constraints);
+            
+            bottomPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth), constraints);
+            
+            counterPanel = new CounterPanel();
+            counterPanel.setOpaque(false);
+            bottomPanel.add(counterPanel, constraints);
+            bottomPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth), constraints);
+        
+            // exception message field (text area)
+            exceptionMessageField = new JTextArea("");
+            exceptionMessageField.setEditable(false);
+            exceptionMessageField.setRows(6);
+            exceptionMessageField.setColumns(42);
+            // exceptionMessageField.setLineWrap(true);
+            exceptionMessageField.setFocusable(false);
+            
+            Dimension size = exceptionMessageField.getPreferredSize();
+            // size.width = exceptionMessageField.getMaximumSize().width;
+            // exceptionMessageField.setPreferredSize(size);
+            size.width = exceptionMessageField.getMinimumSize().width;
+            exceptionMessageField.setMinimumSize(size);
+            JScrollPane exceptionScrollPane = new JScrollPane(exceptionMessageField);
+            exceptionScrollPane.setMinimumSize(size);
+
+            // "show source" and "close" buttons
+            showSourceButton = new JButton(Config.getString("testdisplay.showsource"));
+            showSourceButton.addActionListener(new ShowSourceListener());
+            
+            JButton closeButton = new JButton(Config.getString("close"));
+            closeButton.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    frame.setVisible(false);
+                }
+            });
+            
+            // Panel for "show source" and "close" buttons
+            JPanel buttonPanel = new JPanel();
+            buttonPanel.setOpaque(false);
+            buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
+            buttonPanel.add(showSourceButton);
+            buttonPanel.add(Box.createHorizontalGlue());
+            buttonPanel.add(closeButton);
+            
+            constraints.weighty = 1.0;
+            bottomPanel.add(exceptionScrollPane, constraints);
+            constraints.weighty = 0;
+            bottomPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth), constraints);
+            bottomPanel.add(buttonPanel, constraints);
+
+            constraints.gridy = PROGRESS_BAR_INDEX;
+            pbConstraints = constraints;
+        }
+        splitPane.setBottomComponent(bottomPanel);
+        
+        frame.getContentPane().add(splitPane);
+        frame.pack();
+    }
+
+    protected void reset()
+    {
+        testEntries.clear();
+        
+        errorCount = 0;
+        failureCount = 0;
+        totalTimeMs = 0;
+        testTotal = 0;   
+
+        exceptionMessageField.setText("");
+        showSourceButton.setEnabled(false);
+        progressBar.reset();
+        counterPanel.setTotal(0);
+        counterPanel.setErrorValue(0);
+        counterPanel.setFailureValue(0);
+        
+        bottomPanel.remove(PROGRESS_BAR_INDEX);
+        bottomPanel.add(progressBar, pbConstraints, PROGRESS_BAR_INDEX);
+        bottomPanel.validate();
+        progressBar.repaint();
+    }
+    
+    /**
+     * Indicate that we are starting a bunch of tests.
+     * 
+     * @param num  The total number of tests to be run
+     */
+    public void startMultipleTests(int num)
+    {
+        doingMultiple = true;    
+        
+        reset();
+        testTotal = num;
+        counterPanel.setTotal(testTotal);
+        progressBar.setMaximum(testTotal);  
+        showTestDisplay(true);
+    }
+    
+    public void endMultipleTests()
+    {
+        doingMultiple = false;
+        setResultLabel();
+    }  
+
+    /**
+     * Tell the dialog we are about to start a test run.
+     * 
+     * @param num   the number of tests we will run
+     */
+    public void startTest(Project project, int num)
+    {
+        lastProject = project;
+
+        if (! doingMultiple) {
+            reset();
+            testTotal = num;
+            counterPanel.setTotal(testTotal);
+            progressBar.setMaximum(testTotal);  
+        }
+    }
+
+    /**
+     * Add a test result to the test displayer.
+     * 
+     * @param dtr  The test result to add
+     * @param quiet  True if the result should be added "quietly" (do not make
+     *               test frame visible or bring it to front)
+     */
+    public void addResult(DebuggerTestResult dtr, boolean quiet)
+    {
+        addResultQuietly(dtr);
+
+        if (! quiet) {
+            showTestDisplay(true);
+        }
+    }
+
+    /**
+     * Add a test result to the test displayer but do not
+     * bring the test display window to the front.
+     * 
+     * @param dtr  The test result to add
+     */ 
+    public void addResultQuietly(final DebuggerTestResult dtr)
+    {
+        if (!dtr.isSuccess()) {
+            if (dtr.isFailure())
+                ++failureCount;
+            else
+                ++errorCount;
+        }
+
+        totalTimeMs += dtr.getRunTimeMs();
+        
+        testEntries.addElement(dtr);
+        progressBar.step(testEntries.getSize(), dtr.isSuccess());
+        
+        counterPanel.setTotalTime(totalTimeMs);
+        counterPanel.setFailureValue(failureCount);
+        counterPanel.setErrorValue(errorCount);
+        counterPanel.setRunValue(testEntries.getSize());
+
+        if (!doingMultiple &&
+                (progressBar.getValue() == progressBar.getMaximum())) {
+            setResultLabel();
+        }
+    }
+    
+    /**
+     * Change the progress bar into a red or green label, depending on
+     * success/failure status. Should be called on the swing event thread.
+     */
+    private void setResultLabel()
+    {
+        statusLabel = new JPanel();
+
+        if ((errorCount + failureCount) == 0) {
+            statusLabel.setBackground(ProgressBar.greenBarColour);
+        } else {
+            statusLabel.setBackground(ProgressBar.redBarColour);
+        }
+
+        statusLabel.setMinimumSize(progressBar.getMinimumSize());
+        statusLabel.setMaximumSize(progressBar.getMaximumSize());
+        statusLabel.setPreferredSize(progressBar.getSize());
+        statusLabel.setOpaque(true);
+        bottomPanel.remove(PROGRESS_BAR_INDEX);
+        bottomPanel.add(statusLabel, pbConstraints, PROGRESS_BAR_INDEX);
+        bottomPanel.validate();
+        statusLabel.repaint();
+    }
+
+    class MyListSelectionListener implements ListSelectionListener
+    {
+        public void valueChanged(ListSelectionEvent e)
+        {
+            if (testnames.getSelectedValue() != null) {
+                DebuggerTestResult dtr = (DebuggerTestResult) testnames.getSelectedValue();
+
+                if (dtr.isError() || dtr.isFailure()) {
+                    // fdv.showFailure(dtr.getExceptionMessage() + "\n---\n" + dtr.getTrace());
+                    exceptionMessageField.setText(dtr.getExceptionMessage()
+                            + "\n---\n" + dtr.getTrace());
+                    exceptionMessageField.setCaretPosition(0);
+
+                    // Set the column count to a small number; the text area
+                    // will use the available space anyway, and this prevents
+                    // unncessary horizontal scrollbar from appearing
+                    exceptionMessageField.setColumns(1);
+                    showSourceButton.setEnabled(dtr.getExceptionLocation() != null);
+                } else {
+                    exceptionMessageField.setText("");
+                    showSourceButton.setEnabled(false);
+                }
+            }
+        }
+    }
+    
+    class ShowSourceListener extends MouseAdapter implements ActionListener
+    {
+        public void mouseClicked(MouseEvent e)
+        {
+            int cc = e.getClickCount();
+            if (cc == 2) {
+                showSource();
+            }
+        }
+        
+        public void actionPerformed(ActionEvent e)
+        {
+            showSource();
+        }
+        
+        private void showSource()
+        {
+            DebuggerTestResult dtr = (DebuggerTestResult) testnames.getSelectedValue();
+
+            if ((dtr != null) && (dtr.isError() || dtr.isFailure())) {
+                SourceLocation exceptionLocation = dtr.getExceptionLocation();
+
+                if (exceptionLocation == null) {
+                    return;
+                }
+
+                String packageName = JavaNames.getPrefix(exceptionLocation.getClassName());
+
+                Package spackage = lastProject.getPackage(packageName);
+
+                if (spackage == null) {
+                    return;
+                }
+
+                // We have the package name. Now get the source name and
+                // line number.
+                String sourceName = exceptionLocation.getFileName();
+                int lineno = exceptionLocation.getLineNumber();
+
+                spackage.showSource(sourceName, lineno, "", false);
+            }
+        }
+    }
+}
+
+class MyCellRenderer extends JLabel implements ListCellRenderer
+{
+    final static Icon errorIcon = Config.getFixedImageAsIcon("error.gif");
+    final static Icon failureIcon = Config.getFixedImageAsIcon("failure.gif");
+    final static Icon okIcon = Config.getFixedImageAsIcon("ok.gif");
+
+    // This is the only method defined by ListCellRenderer.
+    // We just reconfigure the JLabel each time we're called.
+    public Component getListCellRendererComponent(
+            JList list,
+            Object value,            // value to display
+            int index,               // cell index
+            boolean isSelected,      // is the cell selected
+            boolean cellHasFocus)    // the list and the cell have the focus
+    {
+        if (value instanceof DebuggerTestResult) {
+            DebuggerTestResult dtr = (DebuggerTestResult) value;
+            setText(dtr.getName() + " (" + dtr.getRunTimeMs() + "ms)");
+            setIcon((dtr.isSuccess()) ? okIcon : (dtr.isFailure() ? failureIcon : errorIcon));
+        } else {
+            setText(value.toString());
+        }
+
+        if (isSelected) {
+            setBackground(list.getSelectionBackground());
+            setForeground(list.getSelectionForeground());
+            setOpaque(true);
+        }
+        else {
+            setBackground(list.getBackground());
+            setForeground(list.getForeground());
+            setOpaque(false);
+        }
+        setEnabled(list.isEnabled());
+        setFont(list.getFont());
+
+        return this;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ArrayElementGetRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ArrayElementGetRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1097769b60c602dbb30fdae2d9536276b16a46e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ArrayElementGetRecord.java
@@ -0,0 +1,125 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * An invoker record for "get" operations on array elements.
+ * 
+ * @author Davin McCall
+ */
+public class ArrayElementGetRecord extends InvokerRecord
+{
+    /** The invoker record for the inspector where the Get button was pressed, that resulted in the creation of this GetInvokerRecord. */
+    private InvokerRecord parentIr;
+    
+    /** Index of the element to get */
+    private int elementIndex;
+    
+    /** Type of the element */
+    private String elementType;
+    
+    /** Name of the object as it appears on the object bench */
+    private String objName;
+    
+    /** Type of the object (on the bench) */
+    private String objType;
+
+
+    public ArrayElementGetRecord(String elementType, int elementIndex, InvokerRecord parentIr)
+    {
+        this.parentIr = parentIr;
+        this.elementType = elementType;
+        this.elementIndex = elementIndex;
+        parentIr.incUsageCount();
+    }
+
+    @Override
+    public boolean hasVoidResult()
+    {
+        return false;
+    }
+    
+    /**
+     * Give this method invoker record a name on the object bench.
+     * 
+     * @param name Name of the object a it appears on the object bench.
+     * @param type The type that the object is on the actual bench.
+     */
+    @Override
+    public void setBenchName(String name, String type)
+    {
+        objName = name;
+        objType = type;
+    }
+
+    /**
+     * Construct a declaration for any objects constructed
+     * by this invoker record.
+     * 
+     * @return a String representing the object declaration
+     *         src or null if there is none.
+     */    
+    @Override
+    public String toFixtureDeclaration(String firstIndent)
+    {
+        return firstIndent + fieldDeclarationStart + objType + " " + objName + statementEnd;    
+    }
+
+    /**
+     * Construct a portion of an initialisation method for
+     * this invoker record.
+     *  
+     * @return a String representing the object initialisation
+     *         src or null if there is none. 
+     */    
+    @Override
+    public String toFixtureSetup(String secondIndent)
+    {
+        return secondIndent + objName + " = " + toExpression() + statementEnd;          
+    }
+
+    /**
+     * Construct a portion of a test method for this
+     * invoker record.
+     * 
+     * @return a String representing the test method src
+     */
+    @Override
+    public String toTestMethod(PkgMgrFrame pmf, String secondIndent)
+    {
+        return secondIndent + objType + " " + objName + " = " + toExpression() + statementEnd;
+    }
+    
+    @Override
+    public String toExpression()
+    {
+        if(! objType.equals(elementType)) {
+            return "((" + objType + ") " + parentIr.toExpression() + "[" + elementIndex + "])";
+        }
+        else {
+            return parentIr.toExpression() + "[" + elementIndex + "]";
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ArrayElementInspectorRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ArrayElementInspectorRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c1f141d68c51aae579ad00e06ff53c59d9c913c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ArrayElementInspectorRecord.java
@@ -0,0 +1,66 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+public class ArrayElementInspectorRecord extends InvokerRecord
+{
+    private InvokerRecord parentIr;
+    private int element;
+    
+    public ArrayElementInspectorRecord(InvokerRecord parentIr, int element)
+    {
+        this.parentIr = parentIr;
+        this.element = element;
+    }
+    
+    @Override
+    public boolean hasVoidResult()
+    {
+        return false;
+    }    
+    
+    @Override
+    public String toExpression()
+    {
+        return parentIr.toExpression() + "[" + element + "]";
+    }
+
+    @Override
+    public String toFixtureDeclaration(String firstIndent)
+    {
+        return null;
+    }
+
+    @Override
+    public String toFixtureSetup(String secondIndent)
+    {
+        return null;
+    }
+
+    @Override
+    public String toTestMethod(PkgMgrFrame pmf, String secondIndent)
+    {
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ClassInspectInvokerRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ClassInspectInvokerRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..da701edcc86a18ee2fc280103f373889fe0e7119
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ClassInspectInvokerRecord.java
@@ -0,0 +1,78 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Records a single user interaction with the 
+ * class inspection mechanisms of BlueJ.
+ * 
+ * This record is for classes accessed through inspectors
+ * (not currently working).
+ *
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class ClassInspectInvokerRecord extends InvokerRecord
+{   
+    private String className;
+
+    /**
+     * Class inspection 
+     * 
+     * @param className name of the class
+     */    
+    public ClassInspectInvokerRecord(String className)
+    {
+        this.className = className;        
+    }   
+    
+    @Override
+    public boolean hasVoidResult()
+    {
+        return false;
+    }
+
+    @Override
+    public String toFixtureDeclaration(String firstIndent)
+    {
+        return null;
+    }
+    
+    @Override
+    public String toFixtureSetup(String secondIndent)
+    {
+        return secondIndent + className + statementEnd;
+    }
+
+    @Override
+    public String toTestMethod(PkgMgrFrame pmf, String secondIndent)
+    {
+        return secondIndent + className + statementEnd;
+    }
+    
+    @Override
+    public String toExpression()
+    {
+        return className;       
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ConstructionInvokerRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ConstructionInvokerRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..607598542993e6ff34a8cf40dab0c40190d20473
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ConstructionInvokerRecord.java
@@ -0,0 +1,114 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Records a single user interaction with the object construction
+ * mechanisms of BlueJ.
+ *
+ * @author  Andrew Patterson
+ */
+public class ConstructionInvokerRecord extends InvokerRecord
+{
+    private String type;
+    private String name;
+    private String command;
+    private String [] argumentValues;
+    
+    public ConstructionInvokerRecord(String type, String name, String command, String [] argVals)
+    {
+        this.type = type;
+        this.name = name;
+        this.command = command;
+        this.argumentValues = argVals;
+    }
+    
+    @Override
+    public boolean hasVoidResult()
+    {
+        return false;
+    }
+    
+    @Override
+    public String [] getArgumentValues()
+    {
+        return argumentValues;
+    }
+
+    @Override
+    public String getResultName()
+    {
+        return name;
+    }
+    
+    @Override
+    public String getResultTypeString()
+    {
+        return type;
+    }
+    
+    /**
+     * Construct a declaration for any objects constructed
+     * by this invoker record.
+     * 
+     * @return a String representing the object declaration
+     *         src or null if there is none.
+     */
+    @Override
+    public String toFixtureDeclaration(String firstIndent)
+    {
+        return firstIndent + fieldDeclarationStart + type + " " + name + statementEnd;       
+    }
+
+    /**
+     * Construct a portion of an initialisation method for
+     * this invoker record.
+     *  
+     * @return a String reprenting the object initialisation
+     *         src or null if there is none. 
+     */
+    @Override
+    public String toFixtureSetup(String secondIndent)
+    {
+        return secondIndent + name + " = " + command + statementEnd;          
+    }
+
+    /**
+     * Construct a portion of a test method for this
+     * invoker record.
+     * 
+     * @return a String representing the test method src
+     */
+    @Override
+    public String toTestMethod(PkgMgrFrame pmf, String secondIndent)
+    {
+        return secondIndent + type + " " + name + " = " + command + statementEnd;
+    }
+
+    @Override
+    public String toExpression()
+    {
+        return command;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ExistingFixtureInvokerRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ExistingFixtureInvokerRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c77f665ea398cf8a37521a8f4765e099aabda6e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ExistingFixtureInvokerRecord.java
@@ -0,0 +1,129 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * From an existing unit test we create an invoker record
+ * that represents all the existing fixture declarations
+ * and setup code.
+ * 
+ * @author  Andrew Patterson
+ */
+public class ExistingFixtureInvokerRecord extends InvokerRecord
+{
+    private List<String> fieldsSrc;
+    private String setUpSrc;
+    
+    /**
+     * Records a method call that returns a result to the user.
+     * 
+     * @param returnType  the Class of the return type of the method
+     * @param command     the method statement to execute
+     */
+    public ExistingFixtureInvokerRecord()
+    {
+        fieldsSrc = new ArrayList<String>();
+    }
+    
+    @Override
+    public boolean hasVoidResult()
+    {
+        return false;
+    }
+
+    public void addFieldDeclaration(String fieldDecl)
+    {
+        fieldsSrc.add(fieldDecl);
+    }
+    
+    public void setSetupMethod(String setupMethodSrc)
+    {
+        setUpSrc = setupMethodSrc;
+    }
+    
+    /**
+     * Construct a declaration for any objects constructed
+     * by this invoker record.
+     * 
+     * @return a String representing the object declaration
+     *         src or null if there is none.
+     */
+    @Override
+    public String toFixtureDeclaration(String firstIndent)
+    {
+        StringBuffer sb = new StringBuffer();
+
+        ListIterator<String> it = fieldsSrc.listIterator();
+                
+        while(it.hasNext()) {
+            String fieldDecl = (String) it.next();
+                    
+            sb.append(firstIndent);
+            sb.append(fieldDecl);
+            sb.append('\n');
+        }
+
+        return sb.toString();
+    }
+    
+    /**
+     * Construct a portion of an initialisation method for
+     * this invoker record.
+     *  
+     * @return a String reprenting the object initialisation
+     *         src or null if there is none. 
+     */
+    @Override
+    public String toFixtureSetup(String secondIndent)
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append(secondIndent);
+        sb.append(setUpSrc);
+        sb.append('\n');
+
+        return sb.toString();
+    }
+
+    /**
+     * Construct a portion of a test method for this
+     * invoker record.
+     * 
+     * @return a String representing the test method src
+     */
+    @Override
+    public String toTestMethod(PkgMgrFrame pmf, String secondIndent)
+    {
+        return null;
+    }
+
+    @Override
+    public String toExpression()
+    {
+        throw new RuntimeException("Method not implemented for this type.");
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ExpressionInvokerRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ExpressionInvokerRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..bcd42e42635fd7bcaec349bd8de2ba1656b14641
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ExpressionInvokerRecord.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import bluej.utility.JavaUtils;
+
+/**
+ * Records a single user interaction with the 
+ * method call mechanisms of BlueJ.
+ * 
+ * <p>This record is for method calls with no result.
+ *
+ * @author  Bruce Quig
+ */
+public class ExpressionInvokerRecord extends MethodInvokerRecord 
+{
+    /**
+     * Construct an ExpressionInvokerRecord for the given command/expression.
+     */
+    public ExpressionInvokerRecord(String command) 
+    {
+        super(JavaUtils.genTypeFromClass(Object.class), command, null);
+    }
+
+    /*
+     * @see bluej.testmgr.record.MethodInvokerRecord#benchAssignmentTypecast()
+     */
+    protected String benchAssignmentTypecast()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append(benchName);
+        sb.append(" = ");
+        sb.append(command);
+
+        return sb.toString();
+    }   
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/GetInvokerRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/GetInvokerRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..0bc10da14e5b73c65ccc3737748f6ebc32e5810e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/GetInvokerRecord.java
@@ -0,0 +1,125 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Records a "Get" from the inspector window. Not from a result inspector
+ * though, since that is handled by the MethodInvocationRecord. 
+ * 
+ * @author Poul Henriksen
+ */
+public class GetInvokerRecord extends InvokerRecord
+{
+    /** The invoker record for the inspector where the Get button was pressed, that resulted in the creation of this GetInvokerRecord. */
+    private InvokerRecord parentIr;
+    
+    /** Name of the field to Get */
+    private String fieldName;
+    
+    /** Type of the field */
+    private String fieldType;
+    
+    /** Name of the object as it appears on the object bench */
+    private String objName;
+    
+    /** Type of the object */
+    private String objType;
+
+
+    public GetInvokerRecord(String fieldType, String fieldName, InvokerRecord parentIr)
+    {
+        this.parentIr = parentIr;
+        this.fieldName = fieldName;
+        this.fieldType = fieldType;
+        parentIr.incUsageCount();
+    }
+
+    /**
+     * Give this method invoker record a name on the object bench.
+     * 
+     * @param name Name of the object a it appears on the object bench.
+     * @param type The type that the object is on the actual bench.
+     */
+    @Override
+    public void setBenchName(String name, String type)
+    {
+        objName = name;
+        objType = type;
+    }
+    
+    @Override
+    public boolean hasVoidResult()
+    {
+        return false;
+    }
+
+    /**
+     * Construct a declaration for any objects constructed
+     * by this invoker record.
+     * 
+     * @return a String representing the object declaration
+     *         src or null if there is none.
+     */    
+    @Override
+    public String toFixtureDeclaration(String firstIndent)
+    {
+        return firstIndent + fieldDeclarationStart + objType + " " + objName + statementEnd;    
+    }
+
+    /**
+     * Construct a portion of an initialisation method for
+     * this invoker record.
+     *  
+     * @return a String representing the object initialisation
+     *         src or null if there is none. 
+     */    
+    @Override
+    public String toFixtureSetup(String secondIndent)
+    {
+        return secondIndent + objName + " = " + toExpression() + statementEnd;          
+    }
+
+    /**
+     * Construct a portion of a test method for this
+     * invoker record.
+     * 
+     * @return a String representing the test method src
+     */
+    @Override
+    public String toTestMethod(PkgMgrFrame pmf, String secondIndent)
+    {
+        return secondIndent + objType + " " + objName + " = " + toExpression() + statementEnd;
+    }
+    
+    @Override
+    public String toExpression()
+    {
+        if(! objType.equals(fieldType)) {
+            return "((" + objType + ") " + parentIr.toExpression() + "." + fieldName + ")";
+        }
+        else {
+            return parentIr.toExpression() + "." + fieldName;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/InvokerRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/InvokerRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd419faba21c1a7aecf475f9ed5041932c24cd7e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/InvokerRecord.java
@@ -0,0 +1,308 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import java.util.ArrayList;
+
+import bluej.debugger.DebuggerObject;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Records a single user interaction with the object
+ * construction/method call mechanisms of BlueJ.
+ * 
+ * Also contains static methods to help deal with the
+ * construction and maintenance of assertion data.
+ *
+ * @author  Andrew Patterson
+ */
+public abstract class InvokerRecord
+{
+    final static String statementEnd = ";\n";
+    
+    final static String fieldDeclarationStart = "private ";
+
+    // -------------- instance fields ----------------
+    
+    /**
+     * A collection of assertion skeletons made about the invoker
+     * record.
+     */
+    private ArrayList<String> assertions = new ArrayList<String>();
+    private DebuggerObject resultObject;
+    
+    private static int nextUniqueIdentifier = 1;
+    private final int uniqueIdentifier;
+    
+    // -------------- instance methods -----------------
+    
+    public InvokerRecord()
+    {
+        uniqueIdentifier = nextUniqueIdentifier++;
+    }
+    
+    /**
+     * If this invoker record represents a method or constructor call,
+     * this method returns the argument values used in the call.
+     * Otherwise it returns null.
+     */
+    public String [] getArgumentValues()
+    {
+        return null;
+    }
+    
+    /**
+     * If the result of this invocation is to be consigned to the object bench, get
+     * its name (otherwise returns null).
+     */
+    public String getResultName()
+    {
+        return null;
+    }
+    
+    /**
+     * Get the (static, compile time) result type of the invocation, if known. 
+     */
+    public String getResultTypeString()
+    {
+        return null;
+    }
+    
+    /**
+     * Check whether this record represents an invocation that has no result.
+     */
+    public abstract boolean hasVoidResult();
+    
+    /**
+     * Construct a declaration for any objects constructed
+     * by this invoker record.
+     * 
+     * @return a String representing the object declaration
+     *         src or null if there is none.
+     */    
+    public abstract String toFixtureDeclaration(String firstIndent);
+
+    /**
+     * Construct a portion of an initialisation method for
+     * this invoker record.
+     *  
+     * @return a String reprenting the object initialisation
+     *         src or null if there is none. 
+     */    
+    public abstract String toFixtureSetup(String secondIndent);
+
+    /**
+     * Construct a portion of a test method for this
+     * invoker record.
+     * 
+     * @return a String representing the test method src
+     */
+    public abstract String toTestMethod(PkgMgrFrame pmf, String secondIndent);
+
+    /**
+     * Construct an expression. This is an open expression which is not ended by
+     * by semicolon or line breaks. It is typically used by other InvokerRecords
+     * to created "chained" invocation records. The returned string should not
+     * include any indentation.
+     * 
+     * @return a String representing the expression
+     */
+    public abstract String toExpression();
+    
+    /**
+     * Set the name of this result as saved on the object bench.
+     * @param benchName  The name of the object (on the Object Bench).
+     * @param benchType  The type of the object as known to the bench.
+     */
+    public void setBenchName(String benchName, String benchType)
+    {
+        // By default do nothing.
+    }
+    
+    /**
+     * Add the skeleton of an assertion statement to our list of
+     * assertions made about this invoker record.
+     * 
+     * @param assertion
+     */
+    public void addAssertion(String assertion)
+    {
+        assertions.add(assertion);  
+    }
+    
+    public int getAssertionCount()
+    {
+        return assertions.size();
+    }
+    
+    public String getAssertion(int i)
+    {
+        return (String) assertions.get(i);
+    }
+    
+    /**
+     * Returns a statement representing this assertion
+     * with an @@ at the point where code needs to be
+     * inserted.
+     * 
+     * This case is for when there is only a single argument
+     * for the assertion.
+
+     * @return a String of the assertion statement.
+     */
+    public static String makeAssertionStatement(String assertName)
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append(assertName);
+        sb.append("(@@)");
+        return sb.toString();
+    }
+
+    /**
+     * Returns a statement representing this assertion
+     * with an @@ at the point where code needs to be
+     * inserted.
+     * 
+     * This case is for when there are two arguements
+     * for the assertion.
+     * 
+     * For example, if the user has selected equals and
+     * has put a value of
+     * 
+     * new X(a,b)
+     * 
+     * in the edit box, we return the string
+     * 
+     * "assertEquals(new X(a,b), @@)"  
+     *  
+     * @return a String of the assertion statement.
+     * 
+     * There is a danger here if the characters @@ appear
+     * in the user input. This is considered unlikely, but
+     * when searching for the @@ location, the _last_ @@
+     * in this string should be found.
+     */
+    public static String makeAssertionStatement(String assertName, String userData)
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append(assertName);
+        sb.append("(");
+        sb.append(userData);
+        sb.append(", @@)");
+        return sb.toString();    
+    }
+
+    /**
+     * Returns a statement representing this assertion
+     * with an @@ at the point where a statement needs to be
+     * inserted.
+     * 
+     * This case is for when we have floating point or
+     * double assertions with assertEquals()
+     *
+     * @return a String of the assertion statement.
+     */
+    public static String makeAssertionStatement(String assertName, String userData, String deltaData)
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append(assertName);
+        sb.append("(");
+        sb.append(userData);
+        sb.append(", @@, ");
+        sb.append(deltaData);
+        sb.append(")");
+        return sb.toString();    
+    }
+
+    /**
+     * Insert a command into an assertion.
+     * 
+     * Our assertions have an @@ wherever the command needs to go. We
+     * find this and insert the string there.
+     * 
+     * @param  assertion   a String representing the assertion in the
+     *                     form "assertXXXX(YYYY, @@)"
+     * @param  command     a String representing the statement to make the
+     *                     assertion against ie foo.bar(5,6) 
+     * @return the combined string representing original assertion with the 
+     *         insertion of the command or reference to bench object.
+     *         ie assertXXXX(YYYY, foo.bar(5,6)) 
+     */
+    public static String insertCommandIntoAssertionStatement(String assertion, String command)
+    {
+        StringBuffer assertCommand = new StringBuffer(assertion);
+        // search for the _last_ @@ in case the user has input some of these
+        // @@ characters in the assertion
+        int insertionSpot = assertion.lastIndexOf("@@");
+
+        if(insertionSpot == -1)
+            throw new IllegalArgumentException("the assertion must have an @@");
+
+        assertCommand.replace(insertionSpot, insertionSpot + 2, command);
+            
+        return assertCommand.toString();
+    }
+
+    /**
+     * If a result is related to this invoker record, it can be set here. This
+     * is mostly here for the MethodInvokerRecord, so that we can refer to the
+     * object by a unique name, by adding it to the object bench.
+     * 
+     * @param resultObject Result object or null
+     */
+    public void setResultObject(DebuggerObject resultObject)
+    {
+        this.resultObject = resultObject;
+    }
+    
+    /**
+     * Get the result object.
+     * 
+     * @return The result object or null.
+     */
+    protected DebuggerObject getResultObject() 
+    {
+        return resultObject;
+    }
+    
+    /**
+     * Call when using this invoker record as a parent for another invoker
+     * record. This implementation does nothing - overide for subclasses 
+     * that need this.
+     */
+    public void incUsageCount()
+    {
+    }
+    
+    /**
+     * Gets the original command.  Used by the Data Collection mechanism.
+     */
+    public String getOriginalCommand() { return null; }
+
+    /**
+     * Gets a unique identifier for this invoker.  For data collection purposes.
+     */
+    public int getUniqueIdentifier()
+    {
+        return uniqueIdentifier;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/MethodInvokerRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/MethodInvokerRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..6dd9fb999d6863eb702ae9af0b164c84015ac009
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/MethodInvokerRecord.java
@@ -0,0 +1,278 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugmgr.objectbench.ObjectBench;
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.utility.JavaNames;
+
+/**
+ * Records a single user interaction with the 
+ * method call mechanisms of BlueJ.
+ * 
+ * This record is for method calls that return a result.
+ *
+ * @author  Andrew Patterson
+ */
+public class MethodInvokerRecord extends VoidMethodInvokerRecord
+{
+    private JavaType returnType;
+    private String benchType;
+    protected String benchName;
+    
+    /** How many times has this record been used. */
+    private int usageCount;
+    
+    /** Has the method call been initialised? */
+    private boolean methodCallInited = false;
+    
+    /**
+     * Records a method call that returns a result to the user.
+     * 
+     * @param returnType  the Class of the return type of the method
+     * @param command     the method statement to execute
+     */
+    public MethodInvokerRecord(JavaType returnType, String command, String [] argumentValues)
+    {
+        super(command, argumentValues);
+    
+        this.returnType = returnType;
+        this.benchType = returnType.toString(false);
+        this.benchName = null;
+    }
+    
+    @Override
+    public boolean hasVoidResult()
+    {
+        return false;
+    }
+
+    /**
+     * Give this method invoker record a name on the object
+     * bench (the user has done a "Get" on the result). The type
+     * is the type that the object is on the actual bench.
+     * 
+     * @param name
+     * @param type
+     */
+    @Override
+    public void setBenchName(String name, String type)
+    {
+        benchName = name;
+        benchType = type;
+    }
+
+    /**
+     * Construct a declaration for any objects constructed
+     * by this invoker record.
+     * 
+     * @return a String representing the object declaration
+     *         src or null if there is none.
+     */
+    @Override
+    public String toFixtureDeclaration(String firstIndent)
+    {
+        // if it hasn't been assigned a name there is nothing to do for
+        // fixture declaration
+        if (benchName == null) {
+            return null;
+        }
+
+        // declare the variable
+        StringBuffer sb = new StringBuffer();
+        sb.append(firstIndent);
+        sb.append(fieldDeclarationStart);
+        sb.append(benchDeclaration());
+        sb.append(benchName);
+        sb.append(statementEnd);
+
+        return sb.toString();
+    }
+    
+    /**
+     * Construct a portion of an initialisation method for
+     * this invoker record.
+     *  
+     * @return a String reprenting the object initialisation
+     *         src or null if there is none. 
+     */
+    @Override
+    public String toFixtureSetup(String secondIndent)
+    {
+        if (benchName == null) {
+            return secondIndent + command + statementEnd;
+        }
+
+        StringBuffer sb = new StringBuffer();
+        sb.append(secondIndent);
+        sb.append(benchAssignmentTypecast());
+        sb.append(statementEnd);
+
+        return sb.toString();
+    }
+
+    /*
+     * @see bluej.testmgr.record.VoidMethodInvokerRecord#toTestMethod(bluej.pkgmgr.PkgMgrFrame)
+     */
+    @Override
+    public String toTestMethod(PkgMgrFrame pmf, String secondIndent)
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append(toTestMethodInit(pmf, secondIndent));
+
+        String resultRef = toExpression();
+
+        // with no uses of the result, just invoke the method.
+        if (getUsageCount() == 0) {
+            sb.append(secondIndent + resultRef + statementEnd);
+        }
+        else {
+            // here are all the assertions
+            for (int i = 0; i < getAssertionCount(); i++) {
+                sb.append(secondIndent);
+                sb.append(insertCommandIntoAssertionStatement(getAssertion(i), resultRef));
+                sb.append(statementEnd);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Do any initialisation needed for creating the test method. This will set
+     * up local variables if the result of the method is used more than once or
+     * placed on the bench by using "Get".
+     */
+    private String toTestMethodInit(PkgMgrFrame pkgMgrFrame, String secondIndent)
+    {
+        // If we have already prepared the method call, we return the name that
+        // references it.
+        if (methodCallInited) {
+            return "";
+        }
+
+        // Method result has not been put on the bench by using "Get".
+        if (benchName == null) {
+            if (getUsageCount() > 1) {
+                // If the method result is not "Get" onto the bench, and we use the
+                // method result more than once, we need to put it on the bench to
+                // give it a unique name.
+                DebuggerObject result = getResultObject();
+                ObjectBench bench = pkgMgrFrame.getObjectBench();
+                ObjectWrapper wrapper = ObjectWrapper.getWrapper(pkgMgrFrame, bench, result, result.getGenType(),
+                "result");
+                bench.addObject(wrapper); // might change name
+                benchName = wrapper.getName();            
+            }
+            else {
+                // Nothing to prepare
+                return "";
+            }
+        }
+        else {
+            // We used "Get" on the result, so increase usage count.
+            incUsageCount();
+        }
+
+        methodCallInited = true;
+        // assign result to a local variable with the given benchName.
+        return secondIndent + benchDeclaration() + benchAssignmentTypecast() + statementEnd;
+    }
+
+    /**
+     * This will return a string containing a reference to the method result.
+     * Either as the command itself, or the name of a local variable containing
+     * the result.
+     * 
+     * @return Reference to the method result
+     */
+    @Override
+    public String toExpression()
+    {
+        assert (methodCallInited);
+
+        // Method result has not been put on the bench by using "Get".
+        if (benchName == null) {
+            return command;
+        }
+        return benchName;
+    }
+
+    /**
+     * @return A string representing the type name of an object
+     */
+    private String benchDeclaration()
+    {
+        return JavaNames.typeName(benchType) + " ";
+    }
+
+    /**
+     * @return A string representing the assignment statement
+     *         with an optional typecast to get the type correct
+     */
+    protected String benchAssignmentTypecast()
+    {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append(benchName);
+        sb.append(" = ");
+
+        // check if a typecast is required
+        if (!benchType.equals(returnType.toString(false))) {
+            sb.append("(");
+            sb.append(benchType);
+            sb.append(")");
+        }
+
+        sb.append(command);
+
+        return sb.toString();
+    }
+
+    @Override
+    public void addAssertion(String assertion)
+    {
+        super.addAssertion(assertion);
+        usageCount++;        
+    }
+
+    /**
+     * Call when using this invoker record as a parent for another invoker
+     * record. Increases usage count.
+     */
+    public void incUsageCount()
+    {
+        usageCount++;
+    }
+
+    /**
+     * Get the number of times the result of this record is used (by another record,
+     * or by an assertion).
+     */
+    private int getUsageCount()
+    {
+        return usageCount;
+    }    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ObjectInspectInvokerRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ObjectInspectInvokerRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4f2b71e423a9641365616ab6515bc8c053759b9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/ObjectInspectInvokerRecord.java
@@ -0,0 +1,107 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * Records a single user interaction with the 
+ * object inspection mechanisms of BlueJ.
+ * 
+ * This record is for objects accessed through inspectors
+ * (not currently working).
+ *
+ * @author  Andrew Patterson
+ */
+public class ObjectInspectInvokerRecord extends InvokerRecord
+{
+    private String name;
+    private InvokerRecord parentIr;
+
+    /**
+     * Object inspection from an initial result.
+     * 
+     * @param type
+     * @param name
+     */    
+    public ObjectInspectInvokerRecord(String name)
+    {
+        this.name = name;
+    }
+
+    @Override
+    public boolean hasVoidResult()
+    {
+        return false;
+    }    
+    
+    /**
+     * Object inspection from another inspector.
+     * 
+     * @param type
+     * @param name
+     * @param ir
+     */
+    public ObjectInspectInvokerRecord(String name, InvokerRecord ir)
+    {
+        this.name = name;
+        this.parentIr = ir;
+    }
+
+    @Override
+    public String toFixtureDeclaration(String firstIndent)
+    {
+        return null;
+    }
+    
+    @Override
+    public String toFixtureSetup(String secondIndent)
+    {
+        return null;
+    }
+
+    @Override
+    public String toTestMethod(PkgMgrFrame pmf, String secondIndent)
+    {
+        return null;
+    }
+
+    @Override
+    public String toExpression()
+    {
+        if(parentIr != null) {
+            return parentIr.toExpression() + "." + name; 
+        }
+        else {
+            return name;
+        }
+    }
+
+    @Override
+    public void incUsageCount()
+    {
+        if(parentIr != null) {
+            parentIr.incUsageCount();     
+        }
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/VoidMethodInvokerRecord.java b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/VoidMethodInvokerRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..51916fd48337a241b0552f0678fad4abc9cb73d0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/testmgr/record/VoidMethodInvokerRecord.java
@@ -0,0 +1,104 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.testmgr.record;
+
+import bluej.pkgmgr.PkgMgrFrame;
+
+
+/**
+ * Records a single user interaction with the 
+ * method call mechanisms of BlueJ.
+ * 
+ * This record is for method calls with no result.
+ *
+ * @author  Andrew Patterson
+ */
+public class VoidMethodInvokerRecord extends InvokerRecord
+{
+    protected String command;
+    private String [] argumentValues;
+    
+    public VoidMethodInvokerRecord(String command, String [] argVals)
+    {
+        this.command = command;
+        this.argumentValues = argVals;
+    }
+    
+    @Override
+    public String [] getArgumentValues()
+    {
+        return argumentValues;
+    }
+    
+    @Override
+    public boolean hasVoidResult()
+    {
+        return true;
+    }
+
+    /**
+     * Construct a declaration for any objects constructed
+     * by this invoker record.
+     * 
+     * @return null because a void method results in no objects
+     */
+    @Override
+    public String toFixtureDeclaration(String firstIndent)
+    {
+        return null;
+    }
+    
+    /**
+     * Construct a portion of an initialisation method for
+     * this invoker record.
+     *  
+     * @return a String reprenting the object initialisation
+     *         src or null if there is none. 
+     */    
+    @Override
+    public String toFixtureSetup(String secondIndent)
+    {
+        // code for the fixture setup involves just inserting the method call
+        return secondIndent + command + statementEnd;
+    }
+
+    @Override
+    public String toTestMethod(PkgMgrFrame pmf, String secondIndent)
+    {
+        // code for the test method involves just inserting the method call
+        return secondIndent + command + statementEnd;
+    }
+
+    @Override
+    public String toExpression()
+    {
+        return command;
+    }
+
+    @Override
+    public String getOriginalCommand()
+    {
+        return command;
+    }
+    
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/BlueJFileChooser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/BlueJFileChooser.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c52962f5ae53ecee73eb47de81aaa2a18551ff0
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/BlueJFileChooser.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import javax.swing.*;
+import java.io.File;
+
+/**
+ * A modified JFileChooser. Modifications are made for
+ * displaying BlueJ packages with a specific icon and to clear the selection
+ * field after traversing into a directory.
+ *
+ * @author Michael Kolling
+ * @version $Id: BlueJFileChooser.java 6215 2009-03-30 13:28:25Z polle $
+ */
+class BlueJFileChooser extends JFileChooser
+{
+    /**
+     * Create a new BlueJFileChooser.
+     *
+     * @param   startDirectory  directory to start the package selection in.
+     */
+    public BlueJFileChooser(String startDirectory)
+    {
+        super(startDirectory);
+        setFileView(new PackageFileView());
+    }
+
+    /**
+     * A directory was double-clicked. If it is a BlueJ package maybe
+     * we want to treat it differently
+     */
+    public void setCurrentDirectory(File dir)    // redefined
+    {
+        //Here we could treat bluej package differently
+        //At the moment nothing is done.
+        //if (Package.isBlueJPackage(dir)) { ...
+        
+        //commented out post 1.1.6 to fix null pointer issue with J2SDK 1.4
+        //setSelectedFile(null);              //clear the textfield
+        super.setCurrentDirectory(dir);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/BlueJFileReader.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/BlueJFileReader.java
new file mode 100644
index 0000000000000000000000000000000000000000..5f3f41d50109e701fca1fa9fa1521837651242e7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/BlueJFileReader.java
@@ -0,0 +1,327 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.util.*;
+import java.io.*;
+import java.nio.charset.Charset;
+
+import bluej.Config;
+
+/**
+ * BlueJFileReader - a (static) class grouping all functions to read and write
+ * BlueJ specific files.
+ * <p>
+ * The BlueJ files are help files (used for compiler help, exception help,
+ * editor help), dialogue files (for message and error dialogues) and templates
+ * (for class skeletons).
+ * <p>
+ * Help texts and dialogue texts are handled through the "readHelpText" method.
+ * The files consist of text IDs (a short string) followed by the full text.
+ * <p>
+ * Class skeletons (handled by the "translateFile" method) are text files with
+ * place holders (variables) in them that will be replaced using a dictionary.
+ * 
+ * @author Michael Kolling
+ */
+public class BlueJFileReader
+{
+    private static final int tabSize = Config.getPropInteger("bluej.editor.tabsize", 4);
+    private static final String spaces = "                                        ";
+    private static final char TAB_CHAR = '\t';
+    
+    /**
+     * Read a help text out of a help file.
+     * <p>
+     * Help files are named (language)/(baseFileName).help (for example
+     * "english/moe.help"). Help texts inside the file are identified by
+     * a help ID (a string).
+     * <p>
+     * The files are expected to be in ISO 8859-1 character encoding, with "slash-u-XXXX" unicode
+     * escape sequences.
+     *
+     * @param baseFileName  Base name of the help file
+     * @param textID        ID string for the help message
+     * @param exactMatch    If true, match ID string exactly. If false,
+     *                      wildcards are used.
+     *
+     * @return              The help text or null.
+     */
+    public static String readHelpText(File file, String textID,
+                                      boolean exactMatch)
+    {
+        BufferedReader in = null;
+
+        try {
+            in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "8859_1"));
+            String msg;
+            String line;
+            String helptext = "";
+            boolean match;
+
+            while ((msg = in.readLine()) != null) {
+                msg = msg.trim();
+                if(exactMatch) {
+                    match = msg.equals(textID);
+                }
+                else {
+                    match = helpTextMatch(textID, msg);
+                }
+
+                if(match) {
+                    // found it - read help text
+                    line = in.readLine();
+                    if((line != null) && (line.length() > 0)) {
+                        helptext = line;
+                        line = in.readLine();
+                    }
+                    while ((line != null) && (line.length() > 0)) {
+                        helptext += "\n" + line;
+                        line = in.readLine();
+                    }
+                    return convert(helptext);
+                }
+                else {
+                    // skip help text
+                    line = in.readLine();
+                    while ((line != null) && (line.length() > 0)) {
+                        line = in.readLine();
+                    }
+                }
+            }
+        }
+        catch(IOException e) {
+            // This use to show a dialog, but showing a dialog involves reading the
+            // help file... infinite recursion! just ignore and return null
+        }
+        finally {
+            if(in != null) {
+                try {
+                    in.close();
+                }
+                catch(Exception e) {}
+            }
+        }
+        return null; // not found
+    }
+
+    /**
+     * Helper function for "readHelpText" (above). Used to determine
+     * help ID matches when accepting wildcards in the message. Recognised
+     * wildcards are asterisks (*) at the start or end of the pattern.
+     */
+    private static boolean helpTextMatch(String message, String pattern)
+    {
+        if(pattern.length() == 0) {
+            return false;
+        }
+        
+        if(pattern.charAt(pattern.length()-1) == '*') {
+            if(pattern.charAt(0) == '*') {  // * at both ends
+                pattern = pattern.substring(1, pattern.length()-3);
+                return (message.indexOf(pattern) > -1);
+            }
+            else { // * at end
+                return message.startsWith(
+                     pattern.substring(0, pattern.length()-2));
+            }
+        }
+        else if(pattern.charAt(0) == '*') {
+            return message.endsWith(pattern.substring(1));
+        }
+        else {
+            return pattern.equals(message);
+        }
+    }
+
+    /**
+     * Copy a file while replacing special keywords within the file by
+     * definitions.
+     * <p>
+     * Keywords are marked with a dollar sign and a name ($KEYWORD).
+     * 'translations' contains definitions to be used as replacements. This is
+     * used to create shell files from the shell file template.
+     * 
+     * @param templateCharset Charset that should be used to read the template file.
+     */
+    public static void translateFile(File template, File dest,
+                                     Dictionary<String,String> translations,
+                                     Charset templateCharset, Charset outputCharset)
+        throws IOException
+    {
+        translateFile(template, dest, translations, true, templateCharset, outputCharset);
+    }
+
+    /**
+     * Copy a file while replacing special keywords within the file by definitions.
+     * <p>
+     * Keywords are marked with a dollar sign and a name ($KEYWORD). 'translations' contains definitions
+     * to be used as replacements. This is used to create shell files from the shell file template.
+     * 
+     * @param templateCharset Charset that should be used to read the template file.
+     * @param outputCharset  Charset that should be used to write the output file.
+     */
+    private static void translateFile(File template, File dest,
+            Dictionary<String,String> translations, boolean replaceTabs,
+            Charset templateCharset, Charset outputCharset)
+        throws IOException
+    {
+        InputStreamReader in = null;
+        OutputStreamWriter out = null;
+        String newline = System.getProperty("line.separator");
+      
+        try {
+            in = new InputStreamReader(new FileInputStream(template), templateCharset);
+            out = new OutputStreamWriter(new FileOutputStream(dest), outputCharset);
+            
+            for(int c; (c = in.read()) != -1; ) {
+                if(c == '$') {
+                    StringBuffer buf = new StringBuffer();
+                    while(((c = in.read()) != -1) && Character.isLetter((char)c)) {
+                        buf.append((char)c);
+                    }
+
+                    String key = buf.toString();
+                    if (key.length() != 0) {
+                        String value = (String)translations.get(key);
+
+                        if(value == null) {
+                            out.write('$');
+                            value = key;
+                        }
+
+                        // If there are tabs, replace
+                        if(replaceTabs && value.indexOf(TAB_CHAR) != -1) {
+                            value = convertTabsToSpaces(value);
+                        }
+
+                        out.write(value);
+                    }
+                    else if (c != '$') {
+                        // let '$$' be an escape for single $
+                        out.write('$');
+                    }
+                    
+                    if(c != -1) {
+                        out.write(c);
+                    }
+                }
+                else if(replaceTabs && c == TAB_CHAR) {
+                    out.write(tabAsSpace());
+                }
+                else if(c == '\r') {
+                    // The template is encoded with CR+LF line endings
+                    int nc = in.read();
+                    if (nc == '\n') {
+                        out.write(newline);
+                    }
+                    else {
+                        out.write(c);
+                        if (nc != -1) {
+                            out.write(nc);
+                        }
+                    }
+                }
+                else {
+                    out.write(c);
+                }
+            }
+
+            in.close();
+            out.close();
+        }
+        catch(IOException e) {
+            if(in != null) {
+                in.close();
+            }
+            if(out != null) {
+                out.close();
+            }
+            throw e;
+        }
+    }
+    
+    /**
+     * Convert tab chars to the applicable number of spaces
+     */
+    private static String convertTabsToSpaces(String tabString)
+    {
+       return tabString.replaceAll("\t", tabAsSpace());
+    }
+    
+    /**
+     * return a String representing the number of spaces to be used in replacing a tab character
+     */
+    private static String tabAsSpace()
+    {
+        return spaces.substring(0, tabSize);
+    }
+    
+    /**
+     * Converts encoded &#92;uxxxx to unicode chars <br> 
+     * 
+     * Copied large chunks from java.util.Properties#loadConvert
+     */
+    private static String convert(String theString)
+    {
+        char aChar;
+        int len = theString.length();
+        StringBuffer outBuffer = new StringBuffer(len);
+        
+        for(int x=0; x<len; ) {
+            aChar = theString.charAt(x++);
+            if (aChar == '\\') {
+                aChar = theString.charAt(x++);
+                if(aChar == 'u') {
+                    // Read the xxxx
+                    int value=0;
+                    for (int i=0; i<4; i++) {
+                        aChar = theString.charAt(x++);
+                        switch (aChar) {
+                            case '0': case '1': case '2': case '3': case '4':
+                            case '5': case '6': case '7': case '8': case '9':
+                                value = (value << 4) + aChar - '0';
+                                break;
+                            case 'a': case 'b': case 'c':
+                            case 'd': case 'e': case 'f':
+                                value = (value << 4) + 10 + aChar - 'a';
+                                break;
+                            case 'A': case 'B': case 'C':
+                            case 'D': case 'E': case 'F':
+                                value = (value << 4) + 10 + aChar - 'A';
+                                break;
+                            default:
+                                //error in encoding - what to do? - nothing
+                        }
+                    }
+                    outBuffer.append((char)value);
+                } else {
+                    //ignore other special characters
+                    outBuffer.append('\\');
+                    outBuffer.append(aChar);
+                }
+            } else
+                outBuffer.append(aChar);
+        }
+        return outBuffer.toString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/ComponentFactory.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/ComponentFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ec66459db2e7396bc54be8faed2ff9c1e5090ec
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/ComponentFactory.java
@@ -0,0 +1,37 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+
+
+/**
+ * Interface for a factory to create components for a GrowableBox.
+ * 
+ * @see bluej.utility.GrowableBox
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: ComponentFactory.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public interface ComponentFactory
+{
+    public JComponent createComponent(JButton addButton, JButton removeButton);
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/DBox.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/DBox.java
new file mode 100644
index 0000000000000000000000000000000000000000..faf7b2097f13f1fb2ccea99184888c18987f3fa1
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/DBox.java
@@ -0,0 +1,160 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.awt.Component;
+import java.awt.Dimension;
+
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+/**
+ * An improved Box class. It allows specifying a default alignment for
+ * added components, and has helpful methods for adding spacers.
+ * 
+ * @author Davin McCall
+ */
+public class DBox extends JPanel
+{
+    private float defaultAlignment;
+    private int axis;
+    
+    private boolean xAxisBounded;
+    private boolean yAxisBounded;
+    
+    public static final int X_AXIS = DBoxLayout.X_AXIS;
+    public static final int Y_AXIS = DBoxLayout.Y_AXIS;
+    
+    /**
+     * Constructor for DBox, with a specified default alignment. Parameter
+     * axis should be one of DBoxLayout.X_AXIS or DBoxLayout.Y_AXIS.
+     * Parameter alignmentVal should be 0.0 for left, 0.5 for centered or
+     * 1.0 for right alignment. 
+     * 
+     * @param axis  Specifies layout direction. Either be X_AXIS or Y_AXIS.
+     * @param alignmentVal   The default component alignment (0.0 - 1.0)
+     */
+    public DBox(int axis, float alignmentVal)
+    {
+        setLayout(new DBoxLayout(axis));
+        defaultAlignment = alignmentVal;
+        this.axis = axis;
+    }
+    
+    /**
+     * Constructor for DBox, which allows putting space between each component.
+     */
+    public DBox(int axis, int minSpacing, int prefSpacing, float alignmentVal)
+    {
+        setLayout(new DBoxLayout(axis, minSpacing, prefSpacing));
+        defaultAlignment = alignmentVal;
+        this.axis = axis;
+    }
+    
+    /**
+     * Add a component to this DBox, first setting the alignment to the
+     * default alignment for this DBox.
+     * 
+     * @param c  The JComponent to add.
+     */
+    public void addAligned(JComponent c)
+    {
+        if (axis == Y_AXIS) {
+            c.setAlignmentX(defaultAlignment);
+        }
+        else {
+            c.setAlignmentY(defaultAlignment);
+        }
+        add(c);
+    }
+    
+    /**
+     * Sets the size bounding for an axis. When bounding is enabled, the maximum size on
+     * the axis will be equal to the preferred size.
+     * 
+     * @param axis   The axis to set the bounding for (X_AXIS or Y_AXIS)
+     * @param bounded  True to enable bounding or false to disable
+     */
+    public void setAxisBounded(int axis, boolean bounded)
+    {
+        if (axis == X_AXIS) {
+            xAxisBounded = bounded;
+        }
+        else if (axis == Y_AXIS) {
+            yAxisBounded = bounded;
+        }
+    }
+    
+    /**
+     * Add a spacer to the box.
+     * 
+     * @param size  The size of the spacer
+     * @return  The spacer component
+     */
+    public Component addSpacer(int size)
+    {
+        JComponent spacer = new JPanel();
+        spacer.setBorder(null);
+
+        if (axis == X_AXIS) {
+            Dimension d = new Dimension(size, 0);
+            spacer.setMaximumSize(d);
+            spacer.setPreferredSize(d);
+        }
+        else {
+            Dimension d = new Dimension(0, size);
+            spacer.setMaximumSize(d);
+            spacer.setPreferredSize(d);
+        }
+        
+        Dimension min = new Dimension(0, 0);
+        spacer.setMinimumSize(min);
+        add(spacer);
+        return spacer;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.Component#getMaximumSize()
+     */
+    public Dimension getMaximumSize()
+    {
+        if (! xAxisBounded && ! yAxisBounded) {
+            return super.getMaximumSize();
+        }
+        else {
+            if (xAxisBounded && yAxisBounded) {
+                return getPreferredSize();
+            }
+            else {
+                Dimension d = super.getMaximumSize();
+                Dimension p = getPreferredSize();
+                if (xAxisBounded) {
+                    d.width = p.width;
+                }
+                else {
+                    d.height = p.height;
+                }
+                return d;
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/DBoxLayout.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/DBoxLayout.java
new file mode 100644
index 0000000000000000000000000000000000000000..58ef81f2bac67efee41bc919acc1177cfb758bcc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/DBoxLayout.java
@@ -0,0 +1,623 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager2;
+
+import javax.swing.SizeRequirements;
+
+/**
+ * A handy layout manager, similar to BoxLayout but which handles component alignment
+ * in a more useful fashion and which provides some handy additional functionality.
+ * 
+ * @author Davin McCall
+ */
+public class DBoxLayout implements LayoutManager2
+{
+    public static int X_AXIS = 0;
+    public static int Y_AXIS = 1;
+
+    /** A SizeRequirements object representing an empty size */
+    private static final SizeRequirements noSize = new SizeRequirements(0, 0, 0, 0.5f); 
+    
+    private int axis;
+    
+    /** minimum required space between components */
+    private int minComponentSpacing;
+    /** preferred space between components */
+    private int componentSpacing;
+    
+    /** Size requirements in the X axis for each component */
+    private SizeRequirements [] sizeReqsX;
+    /** Size requirements in the Y axis for each component */
+    private SizeRequirements [] sizeReqsY;
+    /** Total size requirements in the X axis */
+    private SizeRequirements totalReqsX;
+    /** Total size requirements in the Y axis */
+    private SizeRequirements totalReqsY;
+    /** The number of visible components */
+    private int visibleCount;
+    
+    // Fields below here are used during a layout operation, and are meaningless
+    // outside the operation.
+    
+    /** During a layout, this keeps track of the current layout position */
+    private int curPos;
+    
+    // Following three variables track the spacing between components. In some
+    // cases it is not an integer, so we need to track the fractional part.
+    private boolean needSpaces;
+    private int spacingNumerator;
+    private int spacingDenom;
+    private int spacingRemainder;
+    
+    /** The insets of the parent component (due to its border) */
+    private Insets insets;
+        
+    /**
+     * Construct a DBoxLayout to layout components along the given axis.
+     * @param axis   either X_AXIS or Y_AXIS
+     */
+    public DBoxLayout(int axis)
+    {
+        this.axis = axis;
+    }
+    
+    /**
+     * Construct a DBoxLayout to layout components along the given axis,
+     * with the given amount of space between each components. The minimum
+     * space requirement will always be inserted between each component; the
+     * preferred spacing will be provided only when all components are able
+     * to reach their preferred size.
+     * 
+     * @param axis
+     * @param minSpacing
+     * @param prefSpacing
+     */
+    public DBoxLayout(int axis, int minSpacing, int prefSpacing)
+    {
+        this.axis = axis;
+        minComponentSpacing = minSpacing;
+        componentSpacing = prefSpacing;
+    }
+    
+    /**
+     * Return true if the X_AXIS is the primary layout axis.
+     */
+    public boolean isXPrimaryAxis()
+    {
+        return axis == X_AXIS;
+    }
+    
+    /**
+     * This is called during a layout operation. It places a component
+     * at the current position and updates the current position.
+     * 
+     * @param c   The component to place
+     * @param space    The amount of space given to the component in the
+     *                 primary axis direction
+     * @param opposedPos   The position in the opposed axis
+     * @param opposedSize  The size on the opposed axis
+     */
+    private void placeComponent(Component c, int space, int opposedPos, int opposedSize)
+    {
+        // Take spacing between components into account
+        int advance = spacingNumerator / spacingDenom;
+        spacingRemainder += spacingNumerator % spacingDenom;
+        if (spacingRemainder > spacingDenom) {
+            spacingRemainder -= spacingDenom;
+            advance++;
+        }
+        
+        if (axis == X_AXIS) {
+            c.setBounds(curPos + insets.left, opposedPos + insets.top, space, opposedSize);
+            curPos += space + advance;
+        }
+        else {
+            c.setBounds(opposedPos + insets.left, curPos + insets.top, opposedSize, space);
+            curPos += space + advance;
+        }
+    }
+    
+    /**
+     * Make sure all size requirement calculations are up-to-date.
+     * @param target  The container whose layout we are managing
+     */
+    private void calcSizeReqs(Container target)
+    {
+        if (sizeReqsX == null || sizeReqsY == null) {
+            Component [] components = target.getComponents();
+            recalcSizeReqs(components);
+        }
+    }
+    
+    /**
+     * Make sure all size requirement calculations are up-to-date.
+     * Sets needSpaces variable according to whether spacing may need to
+     * be added between components (i.e. there is more than one visible
+     * component, and the spacing amount is non-zero) and visibleCount
+     * to the number of visible components.
+     * 
+     * @param components  The components in the container whose layout we
+     *                    are managing
+     */
+    private void calcSizeReqs(Component [] components)
+    {
+        if (sizeReqsX == null || sizeReqsY == null) {
+            recalcSizeReqs(components);
+        }
+    }
+    
+    /**
+     * Force re-calculation of all size requirements. A dummy requirement
+     * for the spacing between components is also calculated if necessary.
+     * 
+     * @param components  The components in the target container
+     */
+    private void recalcSizeReqs(Component [] components)
+    {
+        int extra = (componentSpacing != 0 && components.length != 0) ? 1 : 0;
+        sizeReqsX = new SizeRequirements[components.length + extra];
+        sizeReqsY = new SizeRequirements[components.length + extra];
+        
+        totalReqsX = new SizeRequirements(0, 0, 0, 0.5f);
+        totalReqsY = new SizeRequirements(0, 0, 0, 0.5f);
+        
+        visibleCount = 0;
+        
+        int i;
+        for (i = 0; i < components.length; i++) {
+            Component component = components[i];
+            if (component.isVisible()) {
+                visibleCount++;
+                Dimension min = component.getMinimumSize();
+                Dimension pref = component.getPreferredSize();
+                Dimension max = component.getMaximumSize();
+                
+                sizeReqsX[i] = new SizeRequirements(min.width, pref.width, max.width, component.getAlignmentX());
+                sizeReqsY[i] = new SizeRequirements(min.height, pref.height, max.height, component.getAlignmentY());
+                
+                if (isXPrimaryAxis()) {
+                    addReqs(totalReqsX, sizeReqsX[i]);
+                    maxReq(totalReqsY, sizeReqsY[i]);
+                }
+                else {
+                    addReqs(totalReqsY, sizeReqsY[i]);
+                    maxReq(totalReqsX, sizeReqsX[i]);
+                }
+            }
+            else {
+                sizeReqsX[i] = noSize;
+                sizeReqsY[i] = noSize;
+            }
+        }
+        
+        // adjust for spacing between components
+        if (visibleCount > 1 && componentSpacing != 0) {
+            needSpaces = true;
+            sizeReqsX[i] = new SizeRequirements();
+            sizeReqsY[i] = new SizeRequirements();
+            int minSpacing = (visibleCount - 1) * minComponentSpacing;
+            int spacing = (visibleCount - 1) * componentSpacing;
+            if (isXPrimaryAxis()) {
+                sizeReqsX[i].minimum = minSpacing;
+                sizeReqsX[i].preferred = spacing;
+                sizeReqsX[i].maximum = spacing;
+                addReqs(totalReqsX, sizeReqsX[i]);
+            }
+            else {
+                sizeReqsY[i].minimum = minSpacing;
+                sizeReqsY[i].preferred = spacing;
+                sizeReqsY[i].maximum = spacing;
+                addReqs(totalReqsY, sizeReqsY[i]);
+            }
+        }
+        else {
+            needSpaces = false;
+        }
+    }
+
+    /**
+     * Adjust a dimension to take the given insets into account.
+     * 
+     * @param d   The dimension to adjust (will be modified)
+     * @param insets  The insets to consider
+     * @return The adjusted Dimension object
+     */
+    private Dimension adjustSizeForInsets(Dimension d, Insets insets)
+    {
+        d.width = (int) Math.min((long) d.width + insets.left
+                + insets.right, Integer.MAX_VALUE);
+        d.height = (int) Math.min((long) d.height + insets.top
+                + insets.bottom, Integer.MAX_VALUE);
+        return d;
+    }
+        
+    /**
+     * Add one set of size requirements (b) to another (a).
+     * @param a  The first set of size requirements (will be modified)
+     * @param b  The second set of size requirements
+     */
+    private void addReqs(SizeRequirements a, SizeRequirements b)
+    {
+        a.minimum = restrictedAdd(a.minimum, b.minimum);
+        a.preferred = restrictedAdd(a.preferred, b.preferred);
+        a.maximum = restrictedAdd(a.maximum, b.maximum);
+    }
+    
+    /**
+     * Add two integers, but cap the result at Integer.MAX_VALUE
+     * @param a  The first integer
+     * @param b  The second integer
+     * @return  The result
+     */
+    private int restrictedAdd(int a, int b)
+    {
+        return (int) Math.min((long) a + b, Integer.MAX_VALUE);
+    }
+
+    /**
+     * Make sure that one set of size requirements (a) is at least as
+     * large as another (b).
+     * @param a  The first set of size requirements
+     * @param b  The second set of size requirements
+     */
+    private void maxReq(SizeRequirements a, SizeRequirements b)
+    {
+        a.minimum = Math.max(a.minimum, b.minimum);
+        a.preferred = Math.max(a.preferred, b.preferred);
+        a.maximum = Math.max(a.maximum, b.maximum);
+    }
+
+    /**
+     * Get the "A-size" from a dimension - that is the size along the
+     * layout axis.
+     * 
+     * @param d  The dimension to get the "A-size" from
+     * @return  The "A-size" of the dimension
+     */
+    private int getASize(Dimension d)
+    {
+        if (axis == X_AXIS) {
+            return d.width;
+        }
+        else {
+            return d.height;
+        }
+    }
+
+    /**
+     * Get the "B-size" from a dimension - that is the size along the
+     * opposing axis of the layout axis.
+     * 
+     * @param d  The dimension to get the "B-size" from
+     * @return  The "A-size" of the dimension
+     */
+    private int getBSize(Dimension d)
+    {
+        if (axis == X_AXIS) {
+            return d.height;
+        }
+        else {
+            return d.width;
+        }
+    }
+
+    /**
+     * Return the alignment value of a component along the opposed axis
+     * @param component
+     * @return
+     */
+    private float getOpposedAlignment(Component component)
+    {
+        if (axis == X_AXIS) {
+            return component.getAlignmentY();
+        }
+        else {
+            return component.getAlignmentX();
+        }
+    }
+        
+    /**
+     * Make a duplicate of a SizeRequirements object.
+     * @param src  The object to duplicate
+     * @return  The duplicate object
+     */
+    private SizeRequirements copySizeReqs(SizeRequirements src)
+    {
+        return new SizeRequirements(src.minimum, src.preferred,
+                src.maximum, src.alignment);
+    }
+
+
+    // ----- LayoutManager2 interface -----
+    
+    public void addLayoutComponent(Component comp, Object constraints)
+    {
+    }
+
+    public float getLayoutAlignmentX(Container target)
+    {
+        return 0.5f;
+    }
+
+    public float getLayoutAlignmentY(Container target)
+    {
+        return 0.5f;
+    }
+
+    public void invalidateLayout(Container target)
+    {
+        sizeReqsX = null;
+        sizeReqsY = null;
+    }
+
+    public void addLayoutComponent(String name, Component comp)
+    {
+    }
+
+    public void removeLayoutComponent(Component comp)
+    {
+    }
+    
+    public Dimension minimumLayoutSize(Container parent)
+    {
+        calcSizeReqs(parent);
+        Insets insets = parent.getInsets();
+        Dimension d = new Dimension(totalReqsX.minimum, totalReqsY.minimum);
+        return adjustSizeForInsets(d, insets); 
+    }
+    
+    public Dimension preferredLayoutSize(Container parent)
+    {
+        calcSizeReqs(parent);
+        Insets insets = parent.getInsets();
+        Dimension d = new Dimension(totalReqsX.preferred, totalReqsY.preferred);
+        return adjustSizeForInsets(d, insets); 
+    }
+
+    public Dimension maximumLayoutSize(Container parent)
+    {
+        calcSizeReqs(parent);
+        Insets insets = parent.getInsets();
+        Dimension d = new Dimension(totalReqsX.maximum, totalReqsY.maximum);
+        return adjustSizeForInsets(d, insets); 
+    }
+
+    public void layoutContainer(Container parent)
+    {
+        Component [] components = parent.getComponents();
+        
+        if (components.length == 0) {
+            // Handle this easy case first; simplifies some of the later
+            // logic anyway (avoids the need to explictly check for
+            // 0 components when calculating spacing)
+            return;
+        }
+        
+        calcSizeReqs(components);
+        
+        insets = parent.getInsets();
+        Dimension parentSize = parent.getSize();
+        int availSize = getASize(parentSize);
+        int opposedSize = getBSize(parentSize);
+        SizeRequirements [] sizeReqs;
+        SizeRequirements [] opposedReqs;
+        SizeRequirements totalSizeReqs;
+        
+        if (isXPrimaryAxis()) {
+            sizeReqs = sizeReqsX;
+            opposedReqs = sizeReqsY;
+            totalSizeReqs = copySizeReqs(totalReqsX);
+            availSize -= insets.left + insets.right;
+            opposedSize -= insets.top + insets.bottom;
+        }
+        else {
+            sizeReqs = sizeReqsY;
+            opposedReqs = sizeReqsX;
+            totalSizeReqs = copySizeReqs(totalReqsY);
+            availSize -= insets.top + insets.bottom;
+            opposedSize -= insets.left + insets.right;
+        }
+        
+        // First we need to allocate space to all components.
+        // We allocate one additional for the spacing between components.
+        int numComponents = components.length + (needSpaces ? 1 : 0);
+        int [] space = new int[numComponents];
+        int [] diffs = new int[numComponents];
+        boolean [] fixed = new boolean[numComponents];
+        if (needSpaces) {
+            // Reset the spacing minimum/preferred/maximum, as sometimes it
+            // gets butchered (and it is reset when sizes are recalculated anyway)
+            int minSpace = minComponentSpacing * (visibleCount - 1);
+            int prefSpace = componentSpacing * (visibleCount - 1);
+            SizeRequirements spaceReqs = sizeReqs[numComponents - 1];
+            
+            totalSizeReqs.minimum += minSpace - spaceReqs.minimum;
+            totalSizeReqs.preferred += prefSpace - spaceReqs.preferred;
+            totalSizeReqs.maximum += prefSpace - spaceReqs.maximum;
+            
+            spaceReqs.minimum = minSpace;
+            spaceReqs.preferred = prefSpace;
+            spaceReqs.maximum = prefSpace;
+        }
+        
+        if (totalSizeReqs.maximum < availSize) {
+            // Center if available size exceeds maximum size
+            curPos = (availSize - totalSizeReqs.maximum) / 2;
+            availSize = totalSizeReqs.maximum;
+        }
+        else {
+            curPos = 0;
+        }
+
+        boolean needAnotherPass;
+
+        adjust:
+        do {
+            needAnotherPass = false;
+            if (totalSizeReqs.minimum >= availSize) {
+                // One simple case: We don't have enough space for everything.
+                // Just set every component to its minimum size.
+                for (int i = 0; i < numComponents; i++) {
+                    space[i] = sizeReqs[i].minimum;
+                }
+            }
+            else if (totalSizeReqs.preferred >= availSize) {
+                // The available space is greater than the minimum size,
+                // but smaller than the preferred size
+                
+                // First we'll try and shrink the space between components, rather
+                // than shrink the components themselves.
+                if (needSpaces) {
+                    SizeRequirements spaceReqs = sizeReqs[numComponents - 1];
+                    int diff = spaceReqs.preferred - spaceReqs.minimum;
+                    if (diff + availSize >= totalSizeReqs.preferred) {
+                        spaceReqs.preferred -= totalSizeReqs.preferred - availSize;
+                        totalSizeReqs.preferred = availSize;
+                    }
+                    else {
+                        spaceReqs.preferred = spaceReqs.minimum;
+                        totalSizeReqs.preferred -= diff;
+                    }
+                }
+                
+                int totalDiffs = 0;
+                int discrepancy = availSize - totalSizeReqs.minimum;
+                
+                for (int i = 0; i < numComponents; i++) {
+                    if (! fixed[i]) {
+                        diffs[i] = sizeReqs[i].preferred - sizeReqs[i].minimum;
+                        totalDiffs += diffs[i];
+                    }
+                }
+                
+                for (int i = 0; i < numComponents; i++) {
+                    if (! fixed[i]) {
+                        if (diffs[i] != 0) {
+                            space[i] = (int) (sizeReqs[i].minimum + (long) diffs[i] * discrepancy / totalDiffs);
+                        }
+                        else {
+                            space[i] = sizeReqs[i].minimum;
+                            fixed[i] = true;
+                        }
+                        if (space[i] > sizeReqs[i].maximum) {
+                            space[i] = sizeReqs[i].maximum;
+                            totalSizeReqs.minimum -= sizeReqs[i].minimum;
+                            totalSizeReqs.preferred -= sizeReqs[i].preferred;
+                            totalSizeReqs.maximum -= sizeReqs[i].maximum;
+                            fixed[i] = true;
+                            availSize -= space[i];
+                            needAnotherPass = true;
+                            continue adjust;
+                        }
+                    }
+                }
+            }
+            else {
+                // available size is greater than preferred size
+                if (totalSizeReqs.preferred == 0) {
+                    int numComponentsLeft = 0;
+                    int unassignedSpace = availSize;
+                    for (int i = 0; i < numComponents; i++) {
+                        if (! fixed[i]) {
+                            numComponentsLeft++;
+                            unassignedSpace -= sizeReqs[i].preferred;
+                        }
+                    }
+                            
+                    for (int i = 0; i < numComponents; i++) {
+                        if (! fixed[i]) {
+                            int toAssign = unassignedSpace / numComponentsLeft;
+                            space[i] = restrictedAdd(sizeReqs[i].preferred, toAssign);
+                            if (space[i] > sizeReqs[i].maximum) {
+                                space[i] = sizeReqs[i].maximum;
+                                totalSizeReqs.minimum -= sizeReqs[i].minimum;
+                                totalSizeReqs.preferred -= sizeReqs[i].preferred;
+                                totalSizeReqs.maximum -= sizeReqs[i].maximum;
+                                fixed[i] = true;
+                                availSize -= space[i];
+                                needAnotherPass = true;
+                                continue adjust;
+                            }
+                        }
+                    }
+                }
+                else {
+                    // available size is greater than preferred size;
+                    // some components do have a preferred size
+                    for (int i = 0; i < numComponents; i++) {
+                        if (! fixed[i]) {
+                            space[i] = (int) ((long) sizeReqs[i].preferred * availSize / totalSizeReqs.preferred);
+                            if (space[i] > sizeReqs[i].maximum) {
+                                // Some component maxed out. This means we'll need
+                                // another pass.
+                                space[i] = sizeReqs[i].maximum;
+                                totalSizeReqs.minimum -= sizeReqs[i].minimum;
+                                totalSizeReqs.preferred -= sizeReqs[i].preferred;
+                                totalSizeReqs.maximum -= sizeReqs[i].maximum;
+                                fixed[i] = true;
+                                availSize -= space[i];
+                                needAnotherPass = true;
+                                continue adjust;
+                            }
+                        }
+                    }
+                }
+            }
+        } while (needAnotherPass);
+        
+        // Now we know how much space to give each component, we can
+        // set the position of each component according to its alignment
+        // and constraints
+        
+        if (needSpaces) {
+            spacingNumerator = space[numComponents - 1];
+            spacingDenom = visibleCount - 1;
+        }
+        else {
+            spacingNumerator = 0;
+            spacingDenom = 1;
+        }
+        spacingRemainder = 0;
+        
+        for (int i = 0; i < components.length; i++) {
+            if (components[i].isVisible()) {
+                if (opposedReqs[i].maximum < opposedSize) {
+                    // We need to position the component according to
+                    // its alignment
+                    float alignment = getOpposedAlignment(components[i]);
+                    int offset = (int)((opposedSize - opposedReqs[i].maximum) * alignment);
+                    placeComponent(components[i], space[i], offset, opposedReqs[i].maximum);
+                }
+                else {
+                    placeComponent(components[i], space[i], 0, opposedSize);
+                }
+            }
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/Debug.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/Debug.java
new file mode 100644
index 0000000000000000000000000000000000000000..99edc266bb084022eccfef236ff43de318bd03bf
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/Debug.java
@@ -0,0 +1,172 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+import bluej.Config;
+
+/**
+ * Class to handle debugging messages.
+ * 
+ * @author Michael Kolling
+ */
+public class Debug
+{
+    private static final String eol = System.getProperty("line.separator");
+    
+    private static Writer debugStream = new Writer() {
+        @Override
+        public void write(char[] cbuf, int off, int len) throws IOException
+        {
+        }
+        
+        @Override
+        public void flush() throws IOException
+        {
+        }
+        
+        @Override
+        public void close() throws IOException
+        {
+        }
+    };
+    
+    /**
+     * Set the debug output stream. All debug messages go to the debug
+     * output stream.
+     */
+    public static void setDebugStream(Writer debugStream)
+    {
+        Debug.debugStream = debugStream;
+    }
+    
+    /**
+     * Get the debug output stream.
+     * Output to the stream should be synchronized on the stream object. 
+     */
+    public static Writer getDebugStream()
+    {
+        return debugStream;
+    }
+    
+    /**
+     * Write out a debug message. This may go to a terminal, or to
+     * a debug file, depending on external debug settings.
+     * 
+     * @param msg The message to be written.
+     */
+    public static void message(String msg)
+    {
+        try {
+            synchronized (debugStream) {
+                debugStream.write(msg);
+                debugStream.write(eol);
+                debugStream.flush();
+            }
+        }
+        catch (IOException ioe) {
+            System.err.println("IOException writing debug log");
+        }
+    }
+    
+    /**
+     * Write out a debug message to the debuglog file only.
+     * 
+     * @param msg The message to be written.
+     */
+    public static void log(String msg)
+    {
+        if (! Config.getPropString("bluej.debug").equals("true")) {
+            message(msg);
+        }
+    }
+
+    /**
+     * Write out a BlueJ error message for debugging. Note, this does
+     * not by itself provide a stack trace, so it's of only limited use -
+     * it should be used only when what has gone wrong should be obvious.
+     * 
+     * <p>Use the variant which takes an exception as a parameter where
+     * otherwise prudent.
+     * 
+     * @param error The error message.
+     */
+    public static void reportError(String error)
+    {
+        message("Internal error: " + error);
+    }
+
+    /**
+     * Write out a BlueJ error message for debugging.
+     * 
+     * @param error The error message.
+     */
+    public static void reportError(String error, Throwable exc)
+    {
+        synchronized (debugStream) {
+            message("Internal error: " + error);
+            message("Exception message: " + exc.getMessage());
+            PrintWriter pwriter = new PrintWriter(debugStream);
+            exc.printStackTrace(pwriter);
+            pwriter.flush();
+        }
+    }
+    
+    /**
+     * Log an unexpected exception. Generally this should be used only if the
+     * exception is probably harmless; otherwise, a message should also be
+     * provided, stating what was being attempted when the exception occurred -
+     * see {@link #reportError(String,Throwable)}.
+     * 
+     * @param error  The exception which occurred.
+     */
+    public static void reportError(Throwable error)
+    {
+        synchronized (debugStream) {
+            message("An unexpected exception occurred:");
+            PrintWriter pwriter = new PrintWriter(debugStream);
+            error.printStackTrace(pwriter);
+            pwriter.flush();
+        }
+    }
+    
+    /**
+     * Log a stack trace with the given message.
+     * 
+     * @param msg  The message to precede the stack trace.
+     */
+    public static void printCallStack(String msg)
+    {
+        synchronized (debugStream) {
+            message(msg + "; call stack:");
+            StackTraceElement[] stack = Thread.currentThread().getStackTrace();
+            // Miss out first line (getStackTrace()) and second line (printCallStack, us)
+            // as that will always be the same and irrelevant:
+            for (int i = 2; i < stack.length; i++) {
+                message("  " + stack[i].toString());
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/DialogManager.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/DialogManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..08362788be534f89262666884327f3e454cea88a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/DialogManager.java
@@ -0,0 +1,448 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.awt.Component;
+import java.awt.Point;
+import java.awt.Window;
+import java.io.File;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import bluej.Config;
+
+/**
+ * The dialog manager is a utility class to simplyfy communication with 
+ * the user via dialogs. It provides convinience methods to display
+ * message, choice or question dialogs. Messages are properly
+ * internationalised, using BlueJ's langauage library system.
+ *
+ * @author Michael Kolling
+ */
+public class DialogManager
+{
+    private static final String DLG_FILE_NAME = "dialogues";
+    private static final String GREENFOOT_DLG_FILE_NAME = "greenfoot/dialogues";
+
+    /**
+     * Show an information dialog with message and "OK" button. The
+     * message itself is identified by a message ID (a short string)
+     * which is looked up in the language specific dialogue text file
+     * (eg. "dialogues.english").
+     */
+    public static void showMessage(Component parent, String msgID)
+    {
+        String message = getMessage(msgID);
+        if (message != null)
+            JOptionPane.showMessageDialog(parent, message,
+                                          Config.getApplicationName() + ":  " +
+                                          Config.getString("dialogmgr.message"),
+                                          JOptionPane.INFORMATION_MESSAGE);
+    }
+
+    /**
+     * Show an information dialog with message and "OK" button. The
+     * message itself is identified by a message ID (a short string)
+     * which is looked up in the language specific dialogue text file
+     * (eg. "dialogues.english"). A text (given in a parameter) is appended
+     * to the message.
+     */
+    public static void showMessageWithText(Component parent, String msgID,
+                                           String text)
+    {
+        String message = getMessage(msgID);
+        if (message != null) {
+            JOptionPane.showMessageDialog(parent, message + "\n" + text);
+        }
+    }
+    
+    /**
+     * Show an information dialog with message (including and "OK" button. The
+     * message itself is identified by a message ID (a short string)
+     * which is looked up in the language specific dialogue text file
+     * (eg. "dialogues.english"). A text (given in a parameter) is appended
+     * to the message.
+     */
+    public static void showMessageWithText(Component parent, String msgID, String[] subs)
+    {
+        String message = getMessage(msgID);
+        message = Utility.mergeStrings(message, subs);
+        
+        // Replace single ':' with a blank line:
+        message = message.replace("\n:\n", "\n\n");
+        message = message.replace("\r\n:\r\n", "\r\n\r\n");
+        
+        if (message != null) {
+            JOptionPane.showMessageDialog(parent, message,
+                    Config.getApplicationName() + ":  " +
+                    Config.getString("dialogmgr.message"),
+                    JOptionPane.INFORMATION_MESSAGE);
+        }
+    }
+    
+    /**
+     * Show an information dialog with message and "OK" button. The
+     * message itself is identified by a message ID (a short string)
+     * which is looked up in the language specific dialogue text file
+     * (eg. "dialogues.english"). A text (given in a parameter) is appended
+     * as a prefix to the message. Use showMessageWithText in order to
+     * append to the suffix of the message
+     */
+    public static void showMessageWithPrefixText(Component parent, String msgID,
+                                           String text)
+    {
+        String message = getMessage(msgID);
+        if (message != null)
+            JOptionPane.showMessageDialog(parent, text+ "\n"+message);
+    }
+    
+    /**
+     * Show an information dialog with message and "OK" button. The
+     * message itself is identified by a message ID (a short string)
+     * which is looked up in the language specific dialogue text file
+     * (eg. "dialogues.english"). A text (given in a parameter) is appended
+     * as a prefix to the message. Some text (given as a parameter -
+     * innerText) is inserted within the message itself. 
+     */
+    public static void showMessageWithPrefixText(Component parent, String msgID,
+                                           String text, String innerText)
+    {
+        String message = getMessage(msgID);
+        String messageDialog=Utility.mergeStrings(message, innerText);
+        if (message != null)
+            JOptionPane.showMessageDialog(parent, text+ "\n"+messageDialog);
+    }
+
+
+    /**
+     * Show an information dialog with a text and "OK" button. The text
+     * is shown as it is passed in here. This method should only be used
+     * if the text has already been localised (translated into the local
+     * language). Most of the time "showMessage" (above) should be used.
+     */
+    public static void showText(Component parent, String text)
+    {
+        JOptionPane.showMessageDialog(parent, text);
+    }
+
+
+    /**
+     * Show an error dialog with message and "OK" button.
+     */
+    public static void showError(Component parent, String msgID)
+    {
+        String message = getMessage(msgID);
+        if (message != null) {
+            showErrorText(parent, message);
+        }
+    }
+
+    /**
+     * Show an error dialog with an already-localized message and "OK" button.
+     * 
+     * @param parent   The component to position the dialog over
+     * @param message  The message text to display (should be localized)
+     */
+    public static void showErrorText(Component parent, String message)
+    {
+        JOptionPane.showMessageDialog(parent, message,
+                Config.getApplicationName() + ":  " +
+                Config.getString("dialogmgr.error"),
+                JOptionPane.ERROR_MESSAGE);
+    }
+    
+
+    /**
+     * Show an error dialog with a message, some additional text, and "OK" button.
+     */
+    public static void showErrorWithText(Component parent, String msgID,
+                                         String text)
+    {
+        String message = getMessage(msgID);
+        if (message != null) {
+            showErrorText(parent, message + "\n" + text);
+        }
+    }
+
+    /**
+     * Brings up a two or three button question dialog. The text for the
+     * question and the buttons is read from the dialogues file. If the third
+     * button text is "null", it is not shown. Returns the button index that
+     * was selected (0..2).
+     */
+    public static int askQuestion(Component parent, String msgID)
+    {
+        String message = getMessage(msgID);
+        if (message != null) {
+            int button3Index = message.lastIndexOf("\n");
+            int button2Index = message.lastIndexOf("\n", button3Index-1);
+            int button1Index = message.lastIndexOf("\n", button2Index-1);
+            String button3 = message.substring(button3Index+1);
+            String button2 = message.substring(button2Index+1, button3Index);
+            String button1 = message.substring(button1Index+1, button2Index);
+            message = message.substring(0, button1Index);
+            Object[] options;
+            if ("null".equals(button3)) {
+                options = new Object[] { button1, button2 };
+            }
+            else {
+                options = new Object[] { button1, button2, button3 };
+            }
+
+            return JOptionPane.showOptionDialog(parent, message,
+                                                Config.getApplicationName() + ":  " +
+                                                Config.getString("dialogmgr.question"),
+                                                JOptionPane.DEFAULT_OPTION,
+                                                JOptionPane.WARNING_MESSAGE,
+                                                null, options, options[0]);
+        }
+        return 0;
+    }
+    
+    /**
+     * Brings up a two or three button question dialog. The text for the
+     * question and the buttons is read from the dialogues file; '$'
+     * characters in the message are replaced one-by-one with the specified
+     * strings.
+     * 
+     * <p>If the third button text is "null", it is not shown. Returns the button
+     * index that was selected (0..2).
+     */
+    public static int askQuestion(Component parent, String msgID, String [] subs)
+    {
+        String message = getMessage(msgID);
+        if (message != null) {
+            int button3Index = message.lastIndexOf("\n");
+            int button2Index = message.lastIndexOf("\n", button3Index-1);
+            int button1Index = message.lastIndexOf("\n", button2Index-1);
+            String button3 = message.substring(button3Index+1);
+            String button2 = message.substring(button2Index+1, button3Index);
+            String button1 = message.substring(button1Index+1, button2Index);
+            message = message.substring(0, button1Index);
+            message = Utility.mergeStrings(message, subs);
+            Object[] options;
+            if ("null".equals(button3)) {
+                options = new Object[] { button1, button2 };
+            }
+            else {
+                options = new Object[] { button1, button2, button3 };
+            }
+
+            return JOptionPane.showOptionDialog(parent, message,
+                                                Config.getApplicationName() + ":  " +
+                                                Config.getString("dialogmgr.question"),
+                                                JOptionPane.DEFAULT_OPTION,
+                                                JOptionPane.WARNING_MESSAGE,
+                                                null, options, options[0]);
+        }
+        return 0;
+    }
+
+    /**
+     * Bring up a dialog which asks the user for a response in the form of a string.
+     * 
+     * @param parent The parent component of the dialog
+     * @param msgId  the identifier of the message in the dialogs file. The first line
+     *               is used as the dialog title, and the last line is used as the
+     *               default response ("null" means no default response).
+     * 
+     * @return The string supplied by the user, or null if the dialog was cancelled.
+     */
+    public static String askString(Component parent, String msgID)
+    {
+        String response = "";
+        String message = getMessage(msgID);
+        if (message != null) {
+            int defaultTextIndex = message.lastIndexOf("\n");
+            int titleIndex = message.lastIndexOf("\n", defaultTextIndex-1);
+            String defaultText = message.substring(defaultTextIndex+1);
+            String title = message.substring(titleIndex+1, defaultTextIndex);
+            message = message.substring(0, titleIndex);
+            if ("null".equals(defaultText)) {
+                defaultText = null;
+            }
+            response = (String)JOptionPane.showInputDialog(parent,
+                                                           message,
+                                                           title,
+                                                           JOptionPane.PLAIN_MESSAGE,
+                                                           null,
+                                                           null,
+                                                           defaultText);
+        }
+        return response;
+    }
+
+    /**
+     * Bring up a dialog which asks the user for a response in the form of a string,
+     * using a specified default response.
+     * 
+     * @param parent The parent component of the dialog
+     * @param msgId  the identifier of the message in the dialogs file. The first line
+     *               is used as the dialog title. The last line is ignored.
+     * @param defaultText The default response, which may be null for no default.
+     * 
+     * @return The string supplied by the user, or null if the dialog was cancelled.
+     */
+    public static String askString(Component parent, String msgID, String defaultText)
+    {
+        String response = "";
+        String message = getMessage(msgID);
+        if (message != null) {
+            int defaultTextIndex = message.lastIndexOf("\n");
+            int titleIndex = message.lastIndexOf("\n", defaultTextIndex - 1);
+            String title = message.substring(titleIndex + 1, defaultTextIndex);
+            message = message.substring(0, titleIndex);
+            response = (String) JOptionPane.showInputDialog(parent,
+                                                            message,
+                                                            title,
+                                                            JOptionPane.PLAIN_MESSAGE,
+                                                            null,
+                                                            null,
+                                                            defaultText);
+        }
+        return response;
+    }
+
+    /**
+     * Support routine for dialogues. Read the message text out of the
+     * dialogue text file (language dependent).
+     */
+    public static String getMessage(String msgID)
+    {
+        String message = null;
+        
+        if (Config.isGreenfoot()) {
+            File filename = Config.getLanguageFile(GREENFOOT_DLG_FILE_NAME);
+            message = BlueJFileReader.readHelpText(filename, msgID, true);
+            if (message == null) {
+                // Might not be available in the chosen language; try English:
+                filename = Config.getDefaultLanguageFile(GREENFOOT_DLG_FILE_NAME);
+                message = BlueJFileReader.readHelpText(filename, msgID, true);
+            }
+        }
+        
+        if (message == null) {
+            File filename = Config.getLanguageFile(DLG_FILE_NAME);
+            message = BlueJFileReader.readHelpText(filename, msgID, true);
+        }
+        
+        // check that message has been found, some messages may be missing
+        // in non-default language resource files.  If not found and not using
+        // English, then use the default English message
+        if (message == null && (!Config.language.equals(Config.DEFAULT_LANGUAGE))) {
+            File filename = Config.getDefaultLanguageFile(DLG_FILE_NAME);
+            message = BlueJFileReader.readHelpText(filename, msgID, true);
+        }
+        // if we still can't find it, there's something wrong...
+        if (message == null) {
+            message = "BlueJ configuration problem:\n" + "text not found for message ID\n" + msgID;
+            Debug.message(message);
+        }
+        return message;
+    }
+
+    /**
+     * Show a "Not Yet Implemented" message.
+     */
+    public static void NYI(Component frame)
+    {
+        showMessage(frame, "not-yet-implemented");
+    }
+
+
+    // --- utility methods to position dialogues and other windows ---
+
+    /**
+     * centreDialog - try to center a dialog within its parent frame
+     */
+    public static void centreDialog(JDialog dialog)
+    {
+        centreWindow(dialog, (Window)dialog.getParent());
+    }
+
+
+    /**
+     * centreWindow - try to center a window within a parent window
+     */
+    public static void centreWindow(Window child, Window parent)
+    {
+        child.setLocationRelativeTo(parent);
+    }
+
+
+    /**
+     * tileWindow - position the child at 20, 20 offset of parent
+     *  location
+     */
+    public static void tileWindow(Window child, Window parent)
+    {
+        if(parent.isShowing()) {
+            Point p_topleft = parent.getLocationOnScreen();
+            child.setLocation(p_topleft.x + 20, p_topleft.y + 20);
+        }
+    }
+    
+    /**
+     * Allows the user to specify the number of buttons in question dialog. 
+     * The text for the question and the buttons is read from the dialogues file. 
+     */
+    public static int askQuestion(Component parent, String msgID, int numOptions)
+    {
+        String message = getMessage(msgID);
+        if(message != null) {
+            String buttonName;
+            int btnIndex=message.length()+1;
+            int prevBtnIndex=message.length(); 
+            String[] options=new String[numOptions];
+            for (int i=0; i < numOptions; i++) {
+                btnIndex=message.lastIndexOf("\n", btnIndex-1);
+                buttonName=message.substring(btnIndex+1, prevBtnIndex);
+                options[numOptions-i-1]=buttonName; //just to ensure they go in, in the correct order
+                prevBtnIndex=btnIndex;
+            }
+            message = message.substring(0, btnIndex);
+
+            return JOptionPane.showOptionDialog(parent, message,
+                    Config.getApplicationName() + ":  " +
+                    Config.getString("dialogmgr.question"),
+                    JOptionPane.DEFAULT_OPTION,
+                    JOptionPane.WARNING_MESSAGE,
+                    null, options, options[0]);
+        }
+        return 0;
+    }
+
+    public static void addOKCancelButtons(JPanel panel, JButton okButton, JButton cancelButton) 
+    {
+        if (Config.isMacOS()) {
+            panel.add(cancelButton);
+            panel.add(okButton);
+        } else {
+            panel.add(okButton);
+            panel.add(cancelButton);
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/EscapeDialog.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/EscapeDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..94a9fa531fc7a4c8403bda6deaca947117c82acb
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/EscapeDialog.java
@@ -0,0 +1,68 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+
+public class EscapeDialog extends JDialog {
+  public EscapeDialog() {
+    this((Frame)null, false);
+  }
+  public EscapeDialog(Frame owner) {
+    this(owner, false);
+  }
+  public EscapeDialog(Frame owner, boolean modal) {
+    this(owner, null, modal);
+  }
+  public EscapeDialog(Frame owner, String title) {
+    this(owner, title, false);     
+  }
+  public EscapeDialog(Frame owner, String title, boolean modal) {
+    super(owner, title, modal);
+  }
+  public EscapeDialog(Dialog owner) {
+    this(owner, false);
+  }
+  public EscapeDialog(Dialog owner, boolean modal) {
+    this(owner, null, modal);
+  }
+  public EscapeDialog(Dialog owner, String title) {
+    this(owner, title, false);     
+  }
+  public EscapeDialog(Dialog owner, String title, boolean modal) {
+    super(owner, title, modal);
+  }
+  protected JRootPane createRootPane() {
+    ActionListener actionListener = new ActionListener() {
+      public void actionPerformed(ActionEvent actionEvent) {
+        setVisible(false);
+      }
+    };
+    JRootPane rootPane = super.createRootPane();
+    KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+    rootPane.registerKeyboardAction(actionListener, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
+    return rootPane;
+  }
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/FileEditor.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/FileEditor.java
new file mode 100644
index 0000000000000000000000000000000000000000..5152baa2dad992c686013802ed36c23815b9f2cf
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/FileEditor.java
@@ -0,0 +1,130 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.io.*;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.PlainDocument;
+
+import bluej.parser.symtab.Selection;
+
+/**
+ * An object which allows (semi) direct editing of files on
+ * disk.
+ *
+ * @author  Andrew Patterson
+ * @version $Id: FileEditor.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class FileEditor extends PlainDocument
+{
+    private File fileToEdit;
+
+	/**
+	 * Construct a FileEditor object which allows "editor" style
+	 * replacements to be made to the file, and then allows the changes
+	 * to be committed back to disk.
+	 *
+	 * @param fileToEdit    the file to edit
+	 */
+    public FileEditor(File fileToEdit) throws IOException
+    {
+        this.fileToEdit = fileToEdit;
+
+        Reader in = null;
+        Writer out = null;
+
+        in = new BufferedReader(new FileReader(fileToEdit));
+        out = new StringWriter();
+
+        for(int c; (c = in.read()) != -1; )
+            out.write(c);
+
+        try {
+            insertString(0, out.toString(), null);
+        }
+        catch(BadLocationException ble)
+        {
+            ble.printStackTrace();
+        }
+        finally {
+            if(in != null)
+                in.close();
+        }
+    }
+
+	/**
+	 * Replace the specified selection region with
+	 * new text.
+	 *
+	 * @param s     the Selection to replace
+	 * @param text  the text to insert
+	 */
+    public void replaceSelection(Selection s, String text)
+    {
+        try {
+            int lineNo = s.getLine() - 1;
+            int endLineNo = s.getEndLine() - 1;
+
+            Element root = getDefaultRootElement();
+
+            if (endLineNo < root.getElementCount()) {
+                Element line = root.getElement(lineNo);
+                Element endLine = root.getElement(endLineNo);
+
+                int pos = line.getStartOffset() + s.getColumn() - 1;
+                int len = endLine.getStartOffset() + s.getEndColumn() - pos - 1;
+                
+                remove(pos, len);
+
+                insertString(line.getStartOffset() + s.getColumn() - 1,
+                                text, null);
+             }
+        }
+        catch(BadLocationException ble)
+        {
+            ble.printStackTrace();
+        }
+    }
+
+    /**
+     * Save the changes made to this file back to disk.
+     */
+    public void save() throws IOException
+    {
+        try {
+            Writer out = new BufferedWriter(new FileWriter(fileToEdit));
+
+            for(int c=0; c<getLength(); c++)
+            {
+                out.write(getText(c,1));
+            }
+
+            out.close();
+        }
+        catch(BadLocationException ble)
+        {
+            ble.printStackTrace();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/FileUtility.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/FileUtility.java
new file mode 100644
index 0000000000000000000000000000000000000000..dbb97fd31424cbd39233c64a673655cd96965de9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/FileUtility.java
@@ -0,0 +1,703 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.awt.Component;
+import java.io.*;
+import java.lang.reflect.Array;
+import java.util.*;
+
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileFilter;
+
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+
+/**
+ * A file utility for various file related actions.
+ *
+ * @author  Markus Ostman
+ * @author  Michael Kolling
+ */
+public class FileUtility
+{
+    /** 
+     * Enum used to indicate file write capabilities on Windows.
+     * @author polle
+     * @see FileUtility#getVistaWriteCapabilities(File)
+     */
+    public enum WriteCapabilities {READ_ONLY, NORMAL_WRITE, VIRTUALIZED_WRITE, UNKNOWN};
+
+    private static final String sourceSuffix = ".java";
+
+    private static JFileChooser pkgChooser = null;
+    private static JFileChooser pkgChooserNonBlueJ = null;
+    private static JFileChooser fileChooser = null;
+    private static PackageChooser directoryChooser = null;
+    private static JFileChooser multiFileChooser = null;
+    
+
+
+    public static File getPackageName(Component parent)
+    {
+        JFileChooser chooser = getPackageChooser();
+
+        if (chooser.showOpenDialog(parent) != JFileChooser.APPROVE_OPTION) {
+            return null;
+        }
+        PrefMgr.setProjectDirectory(
+                         chooser.getSelectedFile().getParentFile().getPath());
+        
+        return chooser.getSelectedFile();
+    }
+
+    public static File getNonBlueJDirectoryName(Component parent)
+    {
+        JFileChooser chooser = getNonBlueJPackageChooser();
+
+        if (chooser.showOpenDialog(parent) != JFileChooser.APPROVE_OPTION) {
+            return null;
+        }
+        return chooser.getSelectedFile();
+    }
+
+    /**
+     *  Get file(s) from the user, using a file selection dialogue.
+     *  If cancelled or an invalid name was specified, return null.
+     *  @return a File array containing the selected files
+     */
+    public static File[] getMultipleFiles(Component parent, String title,
+            String buttonLabel, FileFilter filter)
+    {
+        JFileChooser newMultiChooser = getMultipleFileChooser();
+
+        newMultiChooser.setDialogTitle(title);
+
+        if(filter == null)
+            filter = newMultiChooser.getAcceptAllFileFilter();
+        newMultiChooser.setFileFilter(filter);
+        
+        int result = newMultiChooser.showDialog(parent, buttonLabel);
+
+        if (result == JFileChooser.APPROVE_OPTION) {
+            
+            return newMultiChooser.getSelectedFiles();
+        }
+        else if (result == JFileChooser.CANCEL_OPTION)
+            return null;
+        else {
+            DialogManager.showError(parent, "error-no-name");
+            return null;
+        }
+    }
+    
+    /**
+     *  Get a file name from the user, using a file selection dialogue.
+     *  If cancelled or an invalid name was specified, return null.
+     */
+    public static File getFile(Component parent, String title,
+                                   String buttonLabel, FileFilter filter,
+                                   boolean rememberDir)
+    {
+        JFileChooser newChooser = getFileChooser(false, filter);
+        
+        newChooser.setDialogTitle(title);
+
+        int result = newChooser.showDialog(parent, buttonLabel);
+
+        if (result == JFileChooser.APPROVE_OPTION) {
+            if (rememberDir) {
+                PrefMgr.setProjectDirectory(
+                      newChooser.getSelectedFile().getParentFile().getPath());
+            }
+            return newChooser.getSelectedFile();
+        }
+        else if (result == JFileChooser.CANCEL_OPTION) {
+            return null;
+        }
+        else {
+            DialogManager.showError(parent, "error-no-name");
+            return null;
+        }
+    }
+    
+    public static String getFileName(Component parent, String title,
+            String buttonLabel, FileFilter filter,
+            boolean rememberDir)
+    {
+        File file = getFile(parent, title, buttonLabel, filter, rememberDir);
+        if (file == null)
+            return null;
+        else
+            return file.getPath();
+    }
+    
+    /**
+     *  Get a directory name from the user, using a file selection dialogue.
+     *  If cancelled or an invalid name was specified, return null.
+     *  
+     *  @param parent   The parent component for the dialog display
+     *  @param buttonLabel  The label for the select button
+     *  @param existingOnly  Whether only existing directories should be
+     *                       selectable
+     *  @param rememberDir  Whether to remember the parent directory of
+     *                      the selected directory across sessions 
+     */
+    public static File getDirName(Component parent, String title,
+            String buttonLabel, boolean existingOnly, boolean rememberDir)
+    {
+        return getDirName(parent, title, buttonLabel, null, existingOnly, rememberDir);
+    }
+    
+    /**
+     *  Get a directory name from the user, using a file selection dialogue.
+     *  If cancelled or an invalid name was specified, return null.
+     *  
+     *  @param parent   The parent component for the dialog display
+     *  @param buttonLabel  The label for the select button
+     *  @param startDir The directory to show in the file chooser to begin with
+     *  @param existingOnly  Whether only existing directories should be
+     *                       selectable
+     *  @param rememberDir  Whether to remember the parent directory of
+     *                      the selected directory across sessions 
+     */
+    public static File getDirName(Component parent, String title,
+            String buttonLabel, File startDir, boolean existingOnly, boolean rememberDir)
+    {
+        PackageChooser newChooser = getDirectoryChooser();
+        if (startDir != null)
+        {
+            newChooser.setCurrentDirectory(startDir);
+        }
+        newChooser.setFileFilter(newChooser.getAcceptAllFileFilter());
+        newChooser.setAllowNewFiles(! existingOnly);
+        
+        newChooser.setDialogTitle(title);
+
+        int result = newChooser.showDialog(parent, buttonLabel);
+
+        if (result == JFileChooser.APPROVE_OPTION) {
+            if (rememberDir) {
+                PrefMgr.setProjectDirectory(
+                      newChooser.getSelectedFile().getParentFile().getPath());
+            }
+            return newChooser.getSelectedFile();
+        }
+        else if (result == JFileChooser.CANCEL_OPTION) {
+            return null;
+        }
+        else {
+            DialogManager.showError(parent, "error-no-name");
+            return null;
+        }
+    }
+
+
+    public static FileFilter getJavaSourceFilter()
+    {
+        return new JavaSourceFilter();
+    }
+
+    /**
+     * Get a file chooser which can be used to select files or directories,
+     * and which knows about BlueJ packages.<p>
+     * 
+     * The caller should use setDialogTitle() to set an appropriate title
+     * for the returned chooser.
+     * 
+     * @param directoriesOnly  True to return a chooser which only allows
+     *                         selecting directories
+     * @param filter  The file filter to use, may be null to allow 'all files'
+     * 
+     * @return  A file chooser
+     */
+    private static JFileChooser getFileChooser(boolean directoriesOnly, FileFilter filter)
+    {
+        JFileChooser newChooser;
+        
+        if (directoriesOnly) {
+            newChooser = getDirectoryChooser();
+        }
+        else {
+            newChooser = getFileChooser();
+            newChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+        }
+
+        if(filter == null) {
+            filter = newChooser.getAcceptAllFileFilter();
+        }
+        newChooser.setFileFilter(filter);
+        
+        return newChooser;
+    }
+    
+    
+    /**
+     * Return a BlueJ package chooser, i.e. a file chooser which
+     * recognises BlueJ packages and treats them differently.
+     */
+    private static JFileChooser getPackageChooser()
+    {
+        if(pkgChooser == null) {
+            pkgChooser = new PackageChooserStrict(new File(PrefMgr.getProjectDirectory()));
+        }
+        pkgChooser.setDialogTitle(Config.getString("pkgmgr.openPkg.title"));
+        pkgChooser.setApproveButtonText(Config.getString("pkgmgr.openPkg.buttonLabel"));
+
+        return pkgChooser;
+    }
+
+    /**
+     * Return a BlueJ package chooser, i.e. a file chooser which
+     * recognises BlueJ packages and treats them differently.
+     */
+    private static JFileChooser getNonBlueJPackageChooser()
+    {
+        if(pkgChooserNonBlueJ == null)
+            pkgChooserNonBlueJ = new PackageChooser(new File(PrefMgr.getProjectDirectory()), true, true);
+
+        pkgChooserNonBlueJ.setDialogTitle(Config.getString("pkgmgr.openNonBlueJPkg.title"));
+        pkgChooserNonBlueJ.setApproveButtonText(Config.getString("pkgmgr.openNonBlueJPkg.buttonLabel"));
+
+        return pkgChooserNonBlueJ;
+    }
+
+    /**
+     * return a file chooser for choosing any directory
+     */
+    private static PackageChooser getDirectoryChooser()
+    {
+        if (directoryChooser == null) {
+            directoryChooser = new PackageChooser(new File(PrefMgr.getProjectDirectory()), false, false);
+        }
+        
+        return directoryChooser;
+    }
+
+    /**
+     * return a file chooser for choosing any file (default behaviour)
+     */
+    private static JFileChooser getFileChooser()
+    {
+        if(fileChooser == null) {
+            fileChooser = new BlueJFileChooser(PrefMgr.getProjectDirectory());
+        }
+
+        return fileChooser;
+    }
+
+    /**
+     * return a file chooser for choosing any directory (default behaviour)
+     * that is allows selection of multiple files
+     */
+    private static JFileChooser getMultipleFileChooser()
+    {
+        if(multiFileChooser == null) {
+            multiFileChooser = new BlueJFileChooser(PrefMgr.getProjectDirectory());
+            multiFileChooser.setMultiSelectionEnabled(true);
+        }
+
+        return multiFileChooser;
+    }
+    
+
+    private static class JavaSourceFilter extends FileFilter
+    {
+        /**
+         * This method only accepts files that are Java source files.
+         * Whether a file is a Java source file is determined by the fact that
+         * its filename ends with ".java".
+         */
+        public boolean accept(File pathname)
+        {
+            if (pathname.isDirectory() ||
+                pathname.getName().endsWith(sourceSuffix))
+                   return true;
+            else
+                return false;
+        }
+
+        public String getDescription()
+        {
+            return "Java Source";
+        }
+    }
+
+
+    /**
+     * Copy file 'source' to file 'dest'. The source file must exist,
+     * the destination file will be created. Returns true if successful.
+     */
+    public static void copyFile(String source, String dest)
+        throws IOException
+    {
+        File srcFile = new File(source);
+        File destFile = new File(dest);
+
+        copyFile(srcFile, destFile);
+    }
+
+
+    /**
+     * Copy file 'srcFile' to file 'destFile'. The source file must exist,
+     * the destination file will be created. Returns true if successful.
+     */
+    public static void copyFile(File srcFile, File destFile)
+        throws IOException
+    {
+        // check whether source and dest are the same
+        if(srcFile.equals(destFile)) {
+            return;  // don't bother - they are the same
+        }
+
+        InputStream in = null;
+        OutputStream out = null;
+        
+        try {
+            in = new BufferedInputStream(new FileInputStream(srcFile));
+            out = new BufferedOutputStream(new FileOutputStream(destFile));
+            copyStream(in, out);
+        } finally {
+            if(in != null) {
+                in.close();
+            }
+            if(out != null) {
+                out.close();
+            }
+        }
+    }
+
+
+    /**
+     * Copy stream 'in' to stream 'out'.
+     */
+    public static void copyStream(InputStream in, OutputStream out)
+        throws IOException
+    {
+        for(int c; (c = in.read()) != -1; )
+            out.write(c);
+    }
+
+
+    /**
+     * Copy (recursively) a whole directory.
+     */
+    public static final int NO_ERROR = 0;
+    public static final int DEST_EXISTS = 1;
+    public static final int SRC_NOT_DIRECTORY = 2;
+    public static final int COPY_ERROR = 3;
+
+    public static int copyDirectory(File srcFile, File destFile)
+    {
+        if(!srcFile.isDirectory())
+            return SRC_NOT_DIRECTORY;
+
+        if(destFile.exists())
+            return DEST_EXISTS;
+
+        if(!destFile.mkdir())
+            return COPY_ERROR;
+
+        String[] dir = srcFile.list();
+        for(int i=0; i<dir.length; i++) {
+            //String srcName = source + File.separator + dir[i];
+            File file = new File(srcFile, dir[i]);
+            if(file.isDirectory()) {
+                if(copyDirectory(file, new File(destFile, dir[i])) != NO_ERROR)
+                    return COPY_ERROR;
+            }
+            else {
+                File file2 = new File(destFile, dir[i]);
+                try {
+                    copyFile(file, file2);
+                }
+                catch (IOException ioe) {
+                    return COPY_ERROR;
+                }
+            }
+        }
+        return NO_ERROR;
+    }
+
+
+    /**
+     * Recursively copy all files from one directory to another.
+     * If destination is a sub directory of source directory then
+     * it returns without copying any files.
+     *
+     * @return An array contained each source file which was
+     *         not successfully copied or null if everything went well
+     */
+    public static File[] recursiveCopyFile(File srcDir, File destDir)
+    {
+        if (srcDir == null || destDir == null)
+            throw new IllegalArgumentException();
+
+        File parentDir = destDir.getParentFile();
+
+        // check to make sure that the destination is not a subdirectory
+        // of the source (which would lead to infinite recursion)
+        while(parentDir != null) {
+            if (parentDir.equals(srcDir))
+                return new File[] { srcDir };
+
+            parentDir = parentDir.getParentFile();
+        }
+
+        return actualRecursiveCopyFile(srcDir, destDir);
+    }
+
+    private static File[] actualRecursiveCopyFile(File srcDir, File destDir)
+    {
+        // remember every file which we don't successfully copy
+        List<File> failed = new ArrayList<File>();
+
+        // check whether source and dest are the same
+        if(srcDir.getAbsolutePath().equals(destDir.getAbsolutePath()))
+            return null;
+
+        if (!srcDir.isDirectory() || !destDir.isDirectory())
+            throw new IllegalArgumentException();
+
+        // get all entities in the source directory
+        File[] files = srcDir.listFiles();
+
+        for (int i=0; i < files.length; i++) {
+            // handle directories by recursively copying
+            if (files[i].isDirectory()) {
+
+                File newDir = new File(destDir, files[i].getName());
+
+                newDir.mkdir();
+
+                if (newDir.isDirectory()) {
+                    actualRecursiveCopyFile(files[i], newDir);
+                }
+                else {
+                    failed.add(files[i]);
+                }
+            }
+            else if(files[i].isFile()) {
+                // handle all other files
+                File newFile = new File(destDir, files[i].getName());
+
+                if (! newFile.exists()) {
+                    try {
+                        copyFile(files[i], newFile);
+                    }
+                    catch (IOException ioe) {
+                        failed.add(files[i]);
+                    }
+                }
+                else {
+                    failed.add(files[i]);
+                }
+            }
+        }
+
+        if (failed.size() > 0)
+            return (File [])failed.toArray(new File[0]);
+        else
+            return null;
+    }
+
+
+    /**
+     * Find a file with a given extension in a given directory or any
+     * subdirectory. Returns just one randomly selected file with that
+     * extension.
+     *
+     * @return   a file with the given extension in the given directory,
+     *           or 'null' if such a file cannot be found.
+     */
+    public static File findFile(File startDir, String suffix)
+    {
+        File[] files = startDir.listFiles();
+
+        // look for files here
+        for (int i=0; i < files.length; i++) {
+            if(files[i].isFile()) {
+                if(files[i].getName().endsWith(suffix))
+                    return files[i];
+            }
+        }
+
+        // if we didn't find one, search subdirectories
+        for (int i=0; i < files.length; i++) {
+            if (files[i].isDirectory()) {
+                File found = findFile(files[i], suffix);
+                if(found != null)
+                    return found;
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * Check whether a given directory contains a file with a given suffix.
+     * The search is NOT recursive.
+     *
+     * @return  true if a file with the given suffix exists in the given
+     *          directory.
+     */
+    public static boolean containsFile(File dir, String suffix)
+    {
+        if (dir == null)
+            throw new IllegalArgumentException();
+
+        File[] files = dir.listFiles();
+
+        if (files == null)
+            throw new IllegalArgumentException();
+
+        for (int i=0; i < files.length; i++) {
+            if(files[i].isFile() && files[i].getName().endsWith(suffix))
+                return true;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Delete a directory recursively.
+     * This method will delete all files and subdirectories in any
+     * directory without asking questions. Use with care.
+     *
+     * @param directory   The directory that will be deleted.
+     *
+     */
+    public static void deleteDir(File directory)
+    {
+        File[] fileList = directory.listFiles();
+
+        //If it is a file or an empty directory, delete
+        if(fileList == null || Array.getLength(fileList) == 0){
+            try{
+                directory.delete();
+            }catch (SecurityException se){
+                Debug.message("Trouble deleting: "+directory+se);
+            }
+        }
+        else{
+            //delete all subdirectories
+            for(int i=0;i<Array.getLength(fileList);i++){
+                deleteDir(fileList[i]);
+            }
+            //then delete the directory (when it is empty)
+            try{
+                directory.delete();
+            }catch (SecurityException se){
+                Debug.message("Trouble deleting: "+directory+se);
+            }
+        }
+    }
+    
+    /**
+     * Find the relative path from some parent directory to a file nested within.
+     * For instance, for parent "/a/b" and file "/a/b/c/d/somefile.java" returns
+     * "c/d/somefile.java".
+     * 
+     * @param parent  The containing directory
+     * @param file    The file to get the relative path to
+     * @return   The relative path between parent and file
+     */
+    public static String makeRelativePath(File parent, File file)
+    {
+        String filePath = file.getAbsolutePath();
+        String parentPath = parent.getAbsolutePath();
+        
+        if (filePath.startsWith(parentPath)) {
+            // Strip parent path and path separator
+            filePath = filePath.substring(parentPath.length() + 1);
+        }
+        
+        return filePath;
+    }
+
+    /**
+     * Get the file write capabilities of the given directory. <br>
+     * To find the capabilities, this method will try creating a
+     * temporary file in the directory. <br>
+     * See trac tickets 147 and 150 for more details.
+     * 
+     * @param dir
+     *            Directory to check.
+     * @return The capabilities of this directory. Will return
+     *         {@link WriteCapabilities#UNKNOWN} if the file is not an existing
+     *         directory.
+     */
+    public static WriteCapabilities getVistaWriteCapabilities(File dir) 
+    {
+        if(!dir.isDirectory()) {
+            return WriteCapabilities.UNKNOWN;
+        }
+        WriteCapabilities capabilities = WriteCapabilities.UNKNOWN;
+
+        File tmpFile = null;
+        try {
+            tmpFile = File.createTempFile("bluej", null, dir);
+            tmpFile.deleteOnExit();
+            if(isVirtualized(tmpFile)) {
+                capabilities = WriteCapabilities.VIRTUALIZED_WRITE;
+            } else {
+                capabilities = WriteCapabilities.NORMAL_WRITE;
+            }
+        } catch (IOException e) {
+            // We could not write the file
+            capabilities = WriteCapabilities.READ_ONLY;
+        } finally {
+            if(tmpFile != null) {
+                tmpFile.delete();
+            }
+        }
+        return capabilities;
+    }
+
+    /**
+     * Check whether the given file is virtualized by Windows (Vista).
+     * 
+     */
+    private static boolean isVirtualized(File file)
+    {
+        boolean isVirtualized = false;
+
+        // Virtualization only happens on Windows Vista (or later)
+        if (Config.isModernWinOS()) {
+            try {
+                String canonicalPath = file.getCanonicalPath();
+                int colonIndex = canonicalPath.indexOf(":");
+                if (colonIndex > 0) {
+                    String pathPart = canonicalPath.substring(colonIndex + 1);
+                    String virtualStore = System.getenv("localappdata") + File.separator  + "VirtualStore";
+                    String virtualTmpFilePath = virtualStore + pathPart;
+                    isVirtualized = new File(virtualTmpFilePath).exists();
+                }
+            } catch (IOException e) {
+                Debug.reportError(
+                        "Error when testing for Windows virtualisation.", e);
+            }
+        }
+        return isVirtualized;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/FixedMultiLineLabel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/FixedMultiLineLabel.java
new file mode 100644
index 0000000000000000000000000000000000000000..15c6058a8787bcb178bad368189d9427e272917e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/FixedMultiLineLabel.java
@@ -0,0 +1,102 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ ** A multi-line Label-like Swing component. This class is similar to a
+ ** MultiLineLabel, but it has a fixed numer of rows.
+ **
+ ** @author Michael Kolling
+ **/
+
+public class FixedMultiLineLabel extends MultiLineLabel
+{
+    protected JLabel[] labels;
+    protected int rows;
+
+    /**
+     ** Constructor - make a multiline label
+     **/
+    public FixedMultiLineLabel(String text, float alignment, int numRows)
+    {
+	super(null, alignment);
+	rows = numRows;
+	labels = new JLabel[rows];
+	for(int i=0; i<rows; i++) {
+	    labels[i] = new JLabel(" ");
+            labels[i].setAlignmentX(alignment);
+	    add(labels[i]);
+	}
+	addText(text);
+    }
+
+    /**
+     ** Constructor, defaults to left justified text
+     **/
+    public FixedMultiLineLabel(String text, int numRows)
+    {
+	this(text, LEFT_ALIGNMENT, numRows);
+    }
+
+    /**
+     ** Constructor, empty with the given alignment
+     **/
+    public FixedMultiLineLabel(float alignment, int numRows)
+    {
+	this(null, alignment, numRows);
+    }
+
+    /**
+     ** Constructor - make an empty multiline label
+     **/
+    public FixedMultiLineLabel(int numRows)
+    {
+	this(null, LEFT_ALIGNMENT, numRows);
+    }
+	
+    public void setText(String text)
+    {
+	addText(text);
+    }
+	
+    public void addText(String text)
+    {
+	int lines = 0;
+
+	if(text != null) {
+	    String strs[] = Utility.splitLines(text);
+	    lines = (strs.length < rows ? strs.length : rows);
+	    Font font = new Font("SansSerif", fontAttributes, 12);
+
+	    for (int i = 0; i < lines; i++) {
+		labels[i].setText((strs[i].length() == 0 ? " " : strs[i]));
+		labels[i].setFont(font);
+	    }
+	}
+	
+	for (int i = lines; i < rows; i++)
+	    labels[i].setText(" ");
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/GeneralCache.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/GeneralCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..d73d74aca600631a701965e10c2fff078269ca5e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/GeneralCache.java
@@ -0,0 +1,102 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A general cache, which caches a fixed number of key/value combinations, and which
+ * uses a recently-used strategy to determine which entries to keep.
+ * 
+ * @author Davin McCall
+ */
+public class GeneralCache<K,V>
+{
+    private Map<K,V> cacheMap = new HashMap<K,V>();
+    private List<K> cachedKeys = new LinkedList<K>();
+    private int cacheSize;
+    
+    /**
+     * Construct a cache to cache the given number of items.
+     */
+    public GeneralCache(int cacheSize)
+    {
+        this.cacheSize = cacheSize;
+    }
+    
+    /**
+     * Retrieve an entry from the cache. If no value for the given key is cached,
+     * the return is null. To determine if a null return was due to a null value
+     * or to the cache not containing a value, use containsKey().
+     */
+    public V get(K key)
+    {
+        V rval = cacheMap.get(key);
+        if (rval != null) {
+            // Mark the retrieved key as recently used
+            for (Iterator<K> i = cachedKeys.iterator(); ; ) {
+                K k = i.next();
+                if (k.equals(key)) {
+                    i.remove();
+                    cachedKeys.add(key);
+                    break;
+                }
+            }
+        }
+        return rval;
+    }
+    
+    /**
+     * Check whether a value for the given key is currently cached.
+     */
+    public boolean containsKey(K key)
+    {
+        return cacheMap.containsKey(key);
+    }
+    
+    /**
+     * Put an item in the cache. The given key must not already have a cached value.
+     */
+    public void put(K key, V value)
+    {
+        if (cachedKeys.size() >= cacheSize) {
+            K toRemove = cachedKeys.remove(0);
+            cacheMap.remove(toRemove);
+        }
+        
+        cacheMap.put(key, value);
+        cachedKeys.add(key);
+    }
+    
+    /**
+     * Remove all cache entries.
+     */
+    public void clear()
+    {
+        cacheMap.clear();
+        cachedKeys.clear();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/GradientFillPanel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/GradientFillPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..d937782bdf19101bfa5e7fcfa7de35920bf65245
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/GradientFillPanel.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.awt.Color;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.LayoutManager;
+
+import javax.swing.JPanel;
+
+/**
+ * A small extension to JPanel that uses a gradient fill for the background
+ * 
+ * This should be passed in a call to setContentPane() for a JFrame to take effect --
+ * coupled with setting all panels inside the frame to non-opaque
+ * @author Neil Brown
+ *
+ */
+public class GradientFillPanel extends JPanel
+{
+    public GradientFillPanel(LayoutManager layout)
+    {
+        super(layout);
+    }
+
+    public void paintComponent(Graphics g)
+    {
+        super.paintComponent(g);
+        
+        if (g instanceof Graphics2D) {
+            Graphics2D g2d = (Graphics2D)g;
+            
+            int w = getWidth();
+            int h = getHeight();
+            
+            GradientPaint gp = new GradientPaint(
+                w/4, 0, new Color(236, 236, 236),
+                w*3/4, h, new Color(187, 182, 173));
+
+            g2d.setPaint(gp);
+            g2d.fillRect(0, 0, w, h);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/GrowableBox.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/GrowableBox.java
new file mode 100644
index 0000000000000000000000000000000000000000..86fe9f1e04acadb1b420799e249b832d686e4494
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/GrowableBox.java
@@ -0,0 +1,227 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import bluej.Config;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentEvent;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.border.Border;
+
+/**
+ * A box that can be used to dynamically (from the UI) add and remove
+ * components in either a horizonatal or vertical direction.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: GrowableBox.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class GrowableBox extends Box
+{
+    private ComponentFactory componentFactory;
+    private JComponent emptyGrowable;
+    private Border emptyBorder;
+    private static Insets buttonInsets = new Insets(0, 2, 0, 2);	
+    private static Font buttonFont = new Font("Monospaced", Font.BOLD, 12);	
+    private static String addText = "+";
+    private static ImageIcon addIcon;
+    private static String removeText = "-";
+    private static ImageIcon removeIcon;    
+  
+    /**
+     * Creates a growable panel along the specifed axis. 
+     * By default it includes two buttons to add new components. These are removed when new components are added.
+     * 
+     * @see ComponentFactory
+     * @see javax.swing.BoxLayout#X_AXIS
+     * @see javax.swing.BoxLayout#Y_AXIS
+     * @see javax.swing.Box#Box(int)
+     * @param axis The X_AXIS or Y_AXIS
+     * @param componentFactory The factory to create new components
+     */
+    public GrowableBox(ComponentFactory componentFactory, int axis, int gap) {
+        super(axis);        
+        this.componentFactory = componentFactory;
+        emptyBorder = BorderFactory.createEmptyBorder(0,0,gap,0);
+        emptyGrowable = new JPanel();
+        emptyGrowable.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
+        
+        JButton addButton = new JButton();
+        JButton removeButton = new JButton();        
+        initButtons(addButton, removeButton);
+        removeButton.setEnabled(false);
+        emptyGrowable.add(addButton);
+        emptyGrowable.add(removeButton);
+        addButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                createNewComponent(0);
+            }
+        });
+        clear();
+    }
+
+    /**
+     * Clears the GrowableBox to its initial state.
+     */
+    public void clear() {     
+        removeAll();
+        createNewComponent(0);
+        validate();
+    }
+
+    /**
+     * Inserts a new component at the given position.
+     *
+     */
+    public void createNewComponent(int index) {
+        JButton addButton = new JButton();
+        JButton removeButton = new JButton();
+        initButtons(addButton, removeButton);
+        final JComponent component = componentFactory.createComponent(addButton, removeButton);
+        addButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                int index = getIndex(component);
+                createNewComponent(index + 1);
+            }
+        });
+        removeButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                removeGrowableComponent(component);
+            }
+        });
+        addGrowableComponent(index, component);
+    }
+    
+    /**
+     * Returns the number of components - not counting the emptyComponent which is dislayed if all other components are removed.
+     * @return
+     */
+    public int getComponentCountWithoutEmpty() {
+        int count = getComponentCount();
+        if (count == 1 && getComponent(0) == emptyGrowable) {
+            return 0;
+        } else {
+            return count;
+        }
+    }
+
+    public ComponentFactory getComponentFactory() {
+        return componentFactory;
+    }
+    
+    /**
+     * Intialises the buttons to get the correct look.
+     * 
+     * @param addButton
+     * @param removeButton
+     */
+    private void initButtons(JButton addButton, JButton removeButton) {
+        Utility.changeToMacButton(addButton);
+        addButton.setFont(buttonFont);
+        addButton.setText(addText);
+        addButton.setIcon(addIcon);
+        Utility.changeToMacButton(removeButton);
+    	removeButton.setFont(buttonFont);
+        removeButton.setText(removeText);
+        removeButton.setIcon(removeIcon);
+        if(!Config.isMacOSLeopard()) {
+            addButton.setMargin(buttonInsets);    //needed before MacOS 10.5
+            removeButton.setMargin(buttonInsets);
+        }
+    }
+
+    private void addGrowableComponent(int index, JComponent growableComponent) {        
+        if (getComponentCount() > 0 && getComponent(0) == emptyGrowable) {
+            removeAll();
+        }
+        add(growableComponent, index);     
+        
+        if(index != getComponentCount()-1) {
+            //this is not the last component
+            growableComponent.setBorder(emptyBorder);
+        } else {
+            //This is last component so no border is needed.
+            //But we need to set border on the nextlast
+            int nextLastIndex = index - 1;
+            if(nextLastIndex >= 0) {
+                JComponent nextLast = (JComponent) getComponent(nextLastIndex);
+                nextLast.setBorder(emptyBorder);
+            }
+        }            
+        
+        validate();
+        repaint();
+        fireResizedEvent();
+    }
+
+    private void removeGrowableComponent(JComponent growableComponent) {
+        int index = getIndex(growableComponent);
+        if(index == getComponentCount()-1) {
+            //About to remove last component.
+            //So we remove border from the soon to be last component.
+            int nextLastIndex = index - 1;
+            if(nextLastIndex >= 0) {
+                JComponent nextLast = (JComponent) getComponent(nextLastIndex);
+                nextLast.setBorder(null);
+            }
+        }
+        
+        remove(growableComponent);
+        if (getComponentCount() == 0) {
+            addGrowableComponent(0,emptyGrowable);
+        }
+        validate();
+        repaint();
+        fireResizedEvent();
+    }
+
+    /**
+     * To make sure that containers can listen for resize events.
+     *
+     */
+    private void fireResizedEvent() {
+        ComponentEvent e = new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED);
+        Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(e);
+    }
+
+    private int getIndex(Component c) {
+        Component[] components = getComponents();
+        for (int i = 0; i < components.length; i++) {
+            Component component = components[i];
+            if (component == c) {
+                return i;
+            }
+        }
+        return -1;
+    }    
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaNames.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaNames.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f840d76a616b30392d4f516599d85acd14f677a
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaNames.java
@@ -0,0 +1,326 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Some generally useful utility methods to do with dealing with
+ * java names.
+ *
+ * @author  Andrew Patterson
+ */
+public class JavaNames
+{
+    private static Set<String> javaKeywords;
+    
+    static {
+        javaKeywords = new HashSet<String>();
+        String[] keywords = new String[] {"abstract", "assert", "boolean", "break", "byte",
+                "case", "catch", "char", "class", "const", "continue", "default", "do",
+                "double", "else", "enum", "extends", "final", "finally", "float", "for",
+                "goto", "if", "implements", "import", "instanceof", "int", "interface",
+                "long", "native", "new", "package", "private", "protected", "public",
+                "return", "short", "static", "strictfp", "super", "switch", "synchronized",                 
+                "this", "throw", "throws", "transient", "try", "void", "volatile", "while",
+                "false", "null", "true"
+        };
+        
+        
+        Collections.addAll(javaKeywords, keywords);
+    }
+    
+    /**
+     * Check whether a string is a valid Java identifier
+     */
+    public static boolean isIdentifier(String str)
+    {
+        if (str.length() == 0) {
+            return false;
+        }
+        
+        if (!Character.isJavaIdentifierStart(str.charAt(0))) {
+            return false;
+        }
+        
+        for (int i=1; i < str.length(); i++) {
+            if (! Character.isJavaIdentifierPart(str.charAt(i))) {
+                return false;
+            }
+        }
+        
+        if (isJavaKeyword(str)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Check whether a string is valid Java qualified identifier
+     * ie "java.util" or "util" or "com.sun.test" or the empty string
+     * but not ".java" or "java..util" or "com.sun.".
+     */
+    public static boolean isQualifiedIdentifier(String str)
+    {
+        if (str.length() == 0) {
+            return true;
+        }
+
+        StringTokenizer st = new StringTokenizer(str, ".");
+
+        while(st.hasMoreTokens()) {
+            if(!JavaNames.isIdentifier(st.nextToken())) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Strips package prefix's from full class name. This works only for
+     * class names, not generic types.
+     *
+     * @return the stripped class name.
+     */
+    public static String stripPrefix(String fullClassName)
+    {
+        if(fullClassName != null) {
+            int index = fullClassName.lastIndexOf(".");
+            if(index >= 0) {
+                return fullClassName.substring(++index);
+            }
+        }
+
+        return fullClassName;
+    }
+
+    /**
+     * Strip the given suffix (such as ".java" or ".class") from the given name
+     */
+    public static String stripSuffix(String name, String suffix)
+    {
+        int s = name.lastIndexOf(suffix);
+
+        if(s > 0 && (s == name.length() - suffix.length())) {
+            return name.substring(0, s);
+        }
+        else {
+            return name;
+        }
+    }
+
+    /**
+     * Return the base item from a fully qualified Java name.
+     *
+     * java.util.ArrayList --> ArrayList
+     * java.util           --> util
+     * ""                  --> ""
+     */
+    public static String getBase(String qualifiedName)
+    {
+        int index = qualifiedName.lastIndexOf(".");
+        if(index >= 0)
+            return qualifiedName.substring(++index);
+
+        return qualifiedName;
+    }
+
+    /**
+     * Return the prefix (all but the base name) from a
+     * fully qualified Java name. Examples:
+     *
+     * <pre>
+     * java.util.ArrayList   returns   java.util
+     * ""                    returns   ""
+     * ArrayList             returns   ""
+     * </pre>
+     */
+    public static String getPrefix(String qualifiedName)
+    {
+        if(qualifiedName == null) {
+            throw new NullPointerException();
+        }
+
+        int index = qualifiedName.lastIndexOf(".");
+        if(index > 0) {
+            return qualifiedName.substring(0, index);
+        }
+        else {
+            return "";
+        }
+    }
+
+    /**
+     * Convert a filename into a fully qualified Java name
+     * by considering the filename relative to a base directory.
+     * Returns null if the file is outside the base
+     * directory.
+     *
+     *<p>The behaviour of this function is not guaranteed if
+     * you pass in a directory name. It is meant for filenames
+     * like /foo/bar/p1/s1/TestName.java
+     *
+     * <p>An example of its use is if your baseDir was the
+     * directory /foo/bar and you passed in
+     * /foo/bar/p1/s1/TestName.java the function would
+     * return p1.s1.TestName
+     *
+     * <p>Makes no guarantee that the returned name is a valid
+     * Java identifier (ie. some of the directory names used
+     * may not be valid java identifiers but no check is made
+     * for this).
+     */
+    public static String convertFileToQualifiedName(File baseDir, File f)
+    {
+        File pathFile = f.getAbsoluteFile();
+        File parent = null;
+        String name = "";
+
+        while((parent = pathFile.getParentFile()) != null) {
+            if(pathFile.equals(baseDir)) {
+                return name;
+            }
+
+            if (name == "") {
+                name = pathFile.getName();
+
+                int firstDot = name.indexOf('.');
+                if (firstDot >= 0) {
+                    name = name.substring(0, firstDot);
+                }
+            }
+            else {
+                name = pathFile.getName() + "." + name;
+            }
+
+            pathFile = parent;
+        }
+
+        return null;
+    }
+    
+    /**
+     * Convert a qualifed name to a file. This is mostly only useful for
+     * packages, as other files have a filename extension with a dot in it.
+     */
+    public static File convertQualifiedNameToFile(String name, File root)
+    {
+        int n = 0;
+        int i;
+        
+        File f = root;
+        
+        i = name.indexOf('.', n);
+        while (i != -1) {
+            String namePart = name.substring(n, i);
+            f = new File(f, namePart);
+            n = i + 1;
+            i = name.indexOf('.', n);
+        }
+        
+        return new File(f, name.substring(n));
+    }
+
+    /**
+     * Fix up Java class names as returned by Class.getName()
+     *
+     * <p>The Class.getName() functions are okay for non-array
+     * classes (we don't need to do anything for them), but are in a funny
+     * format for arrays. "String[]", for example, is shown as
+     * "[Ljava.lang.String;". See the Class.getName() documentation for
+     * details. Here, we transform the array names into standard Java syntax.
+     */
+    public static String typeName(String className)
+    {
+        if(!(className.charAt(0) == '['))
+            return className;
+
+        String name = "";
+        while (className.startsWith("[")) {
+            className = className.substring(1);
+            name = name + "[]";
+        }
+        switch (className.charAt(0)) {
+            case 'L' : name = className.substring(1, className.length()-1)
+                       + name;
+        break;
+            case 'B' : name = "byte" + name;
+            break;
+            case 'C' : name = "char" + name;
+            break;
+            case 'D' : name = "double" + name;
+            break;
+            case 'F' : name = "float" + name;
+            break;
+            case 'I' : name = "int" + name;
+            break;
+            case 'J' : name = "long" + name;
+            break;
+            case 'S' : name = "short" + name;
+            break;
+            case 'Z' : name = "boolean" + name;
+            break;
+        }
+        return name;
+    }
+    
+    /**
+     * Combine two identifiers, such as a package and a class name, to produce a
+     * qualified name. This works correctly even if either of the identifiers is
+     * empty (or null).
+     */
+    public static String combineNames(String firstPart, String secondPart)
+    {
+        if (firstPart == null || firstPart.length() == 0) {
+            return secondPart;
+        }
+        else if (secondPart == null || secondPart.length() == 0) {
+            return firstPart;
+        }
+        else {
+            return firstPart + "." + secondPart;
+        }
+    }
+
+    /**
+     * From an array type, figure out the type of the elements in the array. For
+     * instance, if you have an array type of "Integer[]" this method will
+     * return "Integer".
+     * 
+     * @param arrayType A string describing the array type. For instance "Integer[]".
+     */
+    public static String getArrayElementType(String arrayType)
+    {
+        return JavaNames.stripSuffix(arrayType, "[]");
+    }
+    
+    /**
+     * Check whether the given string is a Java keyword / reserved word.
+     */
+    public static boolean isJavaKeyword(String word)
+    {
+        return javaKeywords.contains(word);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaReflective.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaReflective.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f5ebe131f0747cf7131043ac79fb1da1bb10ceb
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaReflective.java
@@ -0,0 +1,423 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.debugger.gentype.FieldReflective;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.JavaPrimitiveType;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.MethodReflective;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * A reflective for GenTypeClass which uses the standard java reflection API.  
+ * 
+ * @author Davin McCall
+ */
+public class JavaReflective extends Reflective
+{
+    private Class<?> c;
+    
+    public int hashCode()
+    {
+        return c.hashCode();
+    }
+    
+    public boolean equals(Object other)
+    {
+        if (other instanceof JavaReflective) {
+            JavaReflective jrOther = (JavaReflective) other;
+            return jrOther.c == c;
+        }
+        return false;
+    }
+    
+    public JavaReflective(Class<?> c)
+    {
+        this.c = c;
+    }
+    
+    public String getName()
+    {
+        return c.getName();
+    }
+    
+    public String getSimpleName()
+    {
+        if (c.isArray()) {
+            return c.getComponentType().getName().replace('$', '.') + "[]";
+        }
+        else {
+            return c.getName().replace('$', '.');
+        }
+    }
+
+    @Override
+    public boolean isInterface()
+    {
+        return c.isInterface();
+    }
+    
+    @Override
+    public boolean isStatic()
+    {
+        return Modifier.isStatic(c.getModifiers());
+    }
+    
+    @Override
+    public boolean isPublic()
+    {
+        return Modifier.isPublic(c.getModifiers());
+    }
+    
+    public List<GenTypeDeclTpar> getTypeParams()
+    {
+        return JavaUtils.getJavaUtils().getTypeParams(c);
+    }
+    
+    public Reflective getArrayOf()
+    {
+        String rname;
+        if (c.isArray())
+            rname = "[" + c.getName();
+        else
+            rname = "[L" + c.getName() + ";";
+        
+        try {
+            ClassLoader cloader = c.getClassLoader();
+            Class<?> arrClass = Class.forName(rname, false, cloader);
+            return new JavaReflective(arrClass);
+        }
+        catch (ClassNotFoundException cnfe) {}
+        
+        return null;
+    }
+    
+    public Reflective getRelativeClass(String name)
+    {
+        try {
+            ClassLoader cloader = c.getClassLoader();
+            if (cloader == null)
+                cloader = ClassLoader.getSystemClassLoader();
+            Class<?> cr = cloader.loadClass(name);
+            return new JavaReflective(cr);
+        }
+        catch (ClassNotFoundException cnfe) {
+            return null;
+        }
+    }
+
+    public List<Reflective> getSuperTypesR()
+    {
+        List<Reflective> l = new ArrayList<Reflective>();
+        
+        // Arrays must be specially handled
+        if (c.isArray()) {
+            Class<?> ct = c.getComponentType();  // could be primitive, but won't matter
+            JavaReflective ctR = new JavaReflective(ct);
+            List<Reflective> componentSuperTypes = ctR.getSuperTypesR();
+            Iterator<Reflective> i = componentSuperTypes.iterator();
+            while (i.hasNext()) {
+                JavaReflective componentSuperType = (JavaReflective) i.next();
+                l.add(componentSuperType.getArrayOf());
+            }
+        }
+        
+        Class<?> superclass = c.getSuperclass();
+        if( superclass != null )
+            l.add(new JavaReflective(superclass));
+
+        Class<?> [] interfaces = c.getInterfaces();
+        for( int i = 0; i < interfaces.length; i++ ) {
+            l.add(new JavaReflective(interfaces[i]));
+        }
+        
+        // Interfaces with no direct superinterfaces have a supertype of Object
+        if (superclass == null && interfaces.length == 0 && c.isInterface())
+            l.add(new JavaReflective(Object.class));
+        
+        return l;
+    }
+
+    public List<GenTypeClass> getSuperTypes()
+    {
+        List<GenTypeClass> l = new ArrayList<GenTypeClass>();
+
+        // Arrays must be specially handled
+        if (c.isArray()) {
+            Class<?> ct = c.getComponentType();   // could be primitive (is ok)
+            JavaReflective ctR = new JavaReflective(ct);
+            List<GenTypeClass> componentSuperTypes = ctR.getSuperTypes(); // generic types
+            Iterator<GenTypeClass> i = componentSuperTypes.iterator();
+            while (i.hasNext()) {
+                GenTypeClass componentSuperType = i.next();
+                l.add(componentSuperType.getArray());
+            }
+        }
+
+        GenTypeClass superclass = null;
+        try {
+            superclass = JavaUtils.getJavaUtils().getSuperclass(c);
+            if( superclass != null ) {
+                l.add(superclass);
+            }
+        }
+        catch (ClassNotFoundException cnfe) {}
+        
+        GenTypeClass[] interfaces;
+        try {
+            interfaces = JavaUtils.getJavaUtils().getInterfaces(c);
+            for( int i = 0; i < interfaces.length; i++ ) {
+                l.add(interfaces[i]);
+            }
+        }
+        catch (ClassNotFoundException cnfe) {
+            interfaces = new GenTypeClass[0];
+        }
+
+        // Interfaces with no direct superinterfaces have a supertype of Object
+        if (superclass == null && interfaces.length == 0 && c.isInterface()) {
+            l.add(new GenTypeClass(new JavaReflective(Object.class)));
+        }
+        
+        return l;
+    }
+    
+    /**
+     * Get the underlying class (as a java.lang.Class object) that this
+     * reflective represents.
+     */
+    public Class<?> getUnderlyingClass()
+    {
+        return c;
+    }
+
+    public boolean isAssignableFrom(Reflective r)
+    {
+        if (r instanceof JavaReflective) {
+            return c.isAssignableFrom(((JavaReflective)r).getUnderlyingClass());
+        }
+        else {
+            return false;
+        }
+    }
+    
+    @Override
+    public Map<String,FieldReflective> getDeclaredFields()
+    {
+        try {
+            Field [] fields = c.getDeclaredFields();
+            Map<String,FieldReflective> rmap = new HashMap<String,FieldReflective>();
+            for (int i = 0; i < fields.length; i++) {
+                try {
+                    JavaType fieldType = JavaUtils.getJavaUtils().getFieldType(fields[i]);
+                    FieldReflective fref = new FieldReflective(fields[i].getName(), fieldType,
+                            fields[i].getModifiers());
+                    rmap.put(fields[i].getName(), fref);
+                }
+                catch (ClassNotFoundException cnfe) {
+                    // Can happen if a type parameter cannot be found
+                }
+            }
+
+            // See JLS section 10.7: arrays have a "public final int length" field
+            if (c.isArray()) {
+                rmap.put("length", new FieldReflective("length", JavaPrimitiveType.getInt(), Modifier.PUBLIC | Modifier.FINAL));
+            }
+
+            return rmap;
+        }
+        catch (LinkageError le) {
+            // getDeclaredFields() can throw a LinkageError
+            return Collections.emptyMap();
+        }
+    }
+    
+    @Override
+    public Map<String,Set<MethodReflective>> getDeclaredMethods()
+    {
+        try {
+            Method [] methods = c.getDeclaredMethods();
+            Map<String,Set<MethodReflective>> rmap = new HashMap<String,Set<MethodReflective>>();
+            for (Method method : methods) {
+                if (method.isSynthetic()) {
+                    continue;
+                }
+
+                JavaType rtype;
+                try {
+                    rtype = JavaUtils.getJavaUtils().getReturnType(method);
+                }
+                catch (ClassNotFoundException cnfe) {
+                    // Type parameter missing
+                    rtype = JavaUtils.getJavaUtils().getRawReturnType(method);
+                }
+                List<GenTypeDeclTpar> tpars = JavaUtils.getJavaUtils().getTypeParams(method);
+
+                // We need to create a map from each type parameter name to its type
+                // as a GenTypeDeclTpar
+                Map<String,GenTypeDeclTpar> tparMap = new HashMap<String,GenTypeDeclTpar>();
+                storeTparMappings(tpars, tparMap);
+                if (! Modifier.isStatic(method.getModifiers())) {
+                    getTparMapping(method.getDeclaringClass(), tparMap);
+                }
+
+                try {
+                    JavaType [] paramTypes = JavaUtils.getJavaUtils().getParamGenTypes(method, false);
+                    List<JavaType> paramTypesList = new ArrayList<JavaType>(paramTypes.length);
+                    for (JavaType paramType : paramTypes) {
+                        paramTypesList.add(paramType.mapTparsToTypes(tparMap).getUpperBound());
+                    }
+
+                    rtype = rtype.mapTparsToTypes(tparMap).getUpperBound();
+
+                    String name = method.getName();
+                    MethodReflective mr = new MethodReflective(name, rtype, tpars, paramTypesList,
+                            this,
+                            JavaUtils.getJavaUtils().isVarArgs(method),
+                            method.getModifiers());
+                    Set<MethodReflective> rset = rmap.get(method.getName());
+                    if (rset == null) {
+                        rset = new HashSet<MethodReflective>();
+                        rmap.put(method.getName(), rset);
+                    }
+                    rset.add(mr);
+                }
+                catch (ClassNotFoundException cnfe) {
+                    continue;
+                }
+            }
+
+            // See JLS section 10.7: arrays have a "public Object clone()" method
+            if (c.isArray()) {
+                rmap.put("clone", Collections.singleton(new MethodReflective("clone", new GenTypeClass(new JavaReflective(Object.class)), new ArrayList<GenTypeDeclTpar>(), new ArrayList<JavaType>(), this, false, Modifier.PUBLIC)));
+            }
+
+            return rmap;
+        }
+        catch (LinkageError le) {
+            // getDeclaredMethods() can cause a LinkageError
+            return Collections.emptyMap();
+        }
+    }
+    
+    /**
+     * Store, into the specified map, a mapping from the enclosing method/class/constructor
+     * type parameter names to the corresponding type parameters. Existing entries in the
+     * map are not overwritten.
+     * 
+     * @param c        The type, whose enclosing entities type parameters are required
+     * @param tparMap  The map, into which the mappings from name to type parameter are to be stored
+     */
+    private void getTparMapping(Class<?> c, Map<String,GenTypeDeclTpar> tparMap)
+    {
+        JavaUtils ju = JavaUtils.getJavaUtils();
+        List<GenTypeDeclTpar> tpars = ju.getTypeParams(c);
+        storeTparMappings(tpars, tparMap);
+        
+        Method m = c.getEnclosingMethod();
+        Constructor<?> cc = c.getEnclosingConstructor();
+        c = c.getEnclosingClass();
+        
+        // Simple experimentation agrees with the documentation: the enclosing method/constructor
+        // cannot be non-null if the enclosing class is null (because the method/constructor must
+        // be enclosed by the enclosing class).
+        
+        while (c != null) {
+            if (m != null) {
+                tpars = ju.getTypeParams(m);
+                storeTparMappings(tpars, tparMap);
+                if (! Modifier.isStatic(m.getModifiers())) {
+                    c = m.getDeclaringClass();
+                }
+                m = null;
+            }
+            else if (cc != null) {
+                tpars = ju.getTypeParams(cc);
+                storeTparMappings(tpars, tparMap);
+                c = cc.getDeclaringClass();
+                cc = null;
+            }
+            
+            if (c != null) {
+                tpars = ju.getTypeParams(c);
+                storeTparMappings(tpars, tparMap);
+                c = c.getEnclosingClass();
+                if (c != null) {
+                    m = c.getEnclosingMethod();
+                    cc = c.getEnclosingConstructor();
+                }
+            }
+        }
+    }
+    
+    /**
+     * Store a set of mappings from type parameter names to the type parameter (GenTypeDeclTpar).
+     * Existing mappings are not overwritten.
+     * 
+     * @param tpars  The set of type parameters to create mappings for
+     * @param map    The map of name to type parameter
+     */
+    private void storeTparMappings(List<GenTypeDeclTpar> tpars, Map<String, ? super GenTypeDeclTpar> map)
+    {
+        for (GenTypeDeclTpar tpar : tpars) {
+            if (! map.containsKey(tpar.getTparName())) {
+                map.put(tpar.getTparName(), tpar);
+            }
+        }
+    }
+    
+    @Override
+    public List<Reflective> getInners()
+    {
+        Class<?>[] inners = c.getDeclaredClasses();
+        List<Reflective> innersR = new ArrayList<Reflective>(inners.length);
+        for (Class<?> inner : inners) {
+            innersR.add(new JavaReflective(inner));
+        }
+        return innersR;
+    }
+    
+    @Override
+    public Reflective getOuterClass()
+    {
+        Class<?> declaring = c.getDeclaringClass();
+        if (declaring != null) {
+            return new JavaReflective(declaring);
+        }
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaUtils.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..73f82d5ee43b891b42d08fd97857fee9d235f301
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaUtils.java
@@ -0,0 +1,709 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.GenTypeSolid;
+import bluej.debugger.gentype.JavaPrimitiveType;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+
+/**
+ * Utilities for dealing with reflection, which must behave differently for
+ * Java 1.4 / 1.5. Use the factory method "getJavaUtils" to retrieve an object
+ * to use. 
+ *   
+ * @author Davin McCall
+ */
+public abstract class JavaUtils
+{
+    private static JavaUtils jutils;
+    
+    /**
+     * Factory method. Returns a JavaUtils object.
+     * @return an object supporting the appropriate feature set
+     */
+    public static JavaUtils getJavaUtils()
+    {
+        if( jutils != null ) {
+            return jutils;
+        }
+        
+        jutils = new JavaUtils15();
+        return jutils;
+    }
+    
+    /**
+     * Get a "signature" description of a method.
+     * Looks like:  void method(int, int, int)
+     *   (ie. excludes parameter names)
+     * @param method The method to get the signature for
+     * @return the signature string
+     */
+    public static String getSignature(Method method)
+    {
+        String name = getFQTypeName(method.getReturnType()).replace('$', '.') + " " + method.getName();
+        Class<?>[] params = method.getParameterTypes();
+        return makeSignature(name, params);
+    }
+
+    /**
+     * Get a fully-qualified type name. For array types return the base type
+     * name plus the appropriate number of "[]" qualifiers.
+     */
+    static public String getFQTypeName(Class<?> type)
+    {
+        Class<?> primtype = type;
+        int dimensions = 0;
+        while (primtype.isArray()) {
+            dimensions++;
+            primtype = primtype.getComponentType();
+        }
+        StringBuffer sb = new StringBuffer();
+        sb.append(primtype.getName());
+        for (int i = 0; i < dimensions; i++)
+            sb.append("[]");
+        return sb.toString();
+    }
+
+    /**
+     * Build the signature string. Format: name(type,type,type)
+     */
+    private static String makeSignature(String name, Class<?>[] params)
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append(name);
+        sb.append("(");
+        for (int j = 0; j < params.length; j++) {
+            String typeName = getFQTypeName(params[j]).replace('$', '.');
+            sb.append(typeName);
+            if (j < (params.length - 1))
+                sb.append(", ");
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    /**
+     * Get a "signature" description of a constructor.
+     * Looks like:  ClassName(int, int, int)
+     *   (ie. excludes parameter names)
+     * @param cons the Constructor to get the signature for
+     * @return the signature string
+     */
+    public static String getSignature(Constructor<?> cons)
+    {
+        String name = JavaNames.getBase(cons.getName());
+        Class<?>[] params = cons.getParameterTypes();
+        return makeSignature(name, params);
+    }
+ 
+    /**
+     * Translate escape characters into their source representation.
+     * The result is suitable for inserting into Java source (between quotes).
+     */
+    public static String escapeString(String s)
+    {
+        StringBuffer outBuf = new StringBuffer();
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '\b') {
+                outBuf.append("\\b");
+            }
+            else if (c == '\t') {
+                outBuf.append("\\t");
+            }
+            else if (c == '\n') {
+                outBuf.append("\\n");
+            }
+            else if (c == '\f') {
+                outBuf.append("\\f");
+            }
+            else if (c == '\r') {
+                outBuf.append("\\r");
+            }
+            else if (c == '\\') {
+                outBuf.append("\\\\");
+            }
+            else if (c == '\"') {
+                outBuf.append('\"');
+            }
+            else if (c < 32) {
+                String uescape = Integer.toHexString(c);
+                uescape = "0000".substring(uescape.length()) + uescape;
+                outBuf.append("\\u" + uescape);
+            }
+            else {
+                outBuf.append(c);
+            }
+        }
+        
+        return outBuf.toString();
+    }
+    
+    /**
+     * Get a "short description" of a method. This is like the signature,
+     * but substitutes the parameter names for their types.
+     * 
+     * @param method   The method to get the description of
+     * @param paramnames  The parameter names of the method
+     * @return The description.
+     */
+    abstract public String getShortDesc(Method method, String [] paramnames)
+        throws ClassNotFoundException;
+
+    /**
+     * Get a "short description" of a method, and map class type parameters to
+     * the given types. A short description is like the signature, but
+     * substitutes the parameter names for their types. Generic method type
+     * parameters are left unmapped.
+     * 
+     * @param method   The method to get the description of
+     * @param paramnames The parameter names of the method
+     * @param tparams  The map (String -> GenType) for class type parameters
+     * @return The description.
+     */
+    abstract public String getShortDesc(Method method, String [] paramnames,
+            Map<String,GenTypeParameter> tparams) throws ClassNotFoundException;
+
+    /**
+     * Get a long String describing the method. A long description is
+     * similar to the short description, but it has type names and parameters
+     * included.
+     */
+    abstract public String getLongDesc(Method method, String [] paramnames)
+        throws ClassNotFoundException;
+    
+    /**
+     * Get a long String describing the method, with class type parameters
+     * mapped to their instantiation types. A long description is similar to a
+     * short description, but it has type names of parameters included.
+     * 
+     * @param method   The method to get the description of
+     * @param paramnames  The parameters names of the method
+     * @param tparams  The map (String -> GenType) for class type parameters
+     * @return The long description string.
+     */
+    abstract public String getLongDesc(Method method, String [] paramnames,
+            Map<String,GenTypeParameter> tparams) throws ClassNotFoundException;
+    
+    /**
+     * Get a "short description" of a constructor. This is like the signature,
+     * but substitutes the parameter names for their types.
+     * 
+     * @param constructor   The constructor to get the description of
+     * @return The description.
+     */
+    abstract public String getShortDesc(Constructor<?> constructor, String [] paramnames)
+        throws ClassNotFoundException;
+    
+    /**
+     * Get a long String describing the constructor. A long description is
+     * similar to the short description, but it has type names and parameters
+     * included.
+     */
+    abstract public String getLongDesc(Constructor<?> constructor, String [] paramnames)
+        throws ClassNotFoundException;
+    
+    abstract public boolean isVarArgs(Constructor<?> cons);
+    
+    abstract public boolean isVarArgs(Method method);    
+   
+    abstract public boolean isSynthetic(Method method);
+    
+    abstract public boolean isEnum(Class<?> cl);
+    
+    /**
+     * Get the return type of a method.
+     */
+    abstract public JavaType getReturnType(Method method) throws ClassNotFoundException;
+    
+    abstract public JavaType getRawReturnType(Method method);
+
+    /**
+     * Get the declared type of a field.
+     */
+    abstract public JavaType getFieldType(Field field) throws ClassNotFoundException;
+    
+    abstract public JavaType getRawFieldType(Field field);
+    
+    /**
+     * Get a list of the type parameters for a generic method.
+     * (return an empty list if the method is not generic).
+     * 
+     * @param method   The method fro which to find the type parameters
+     * @return  A list of GenTypeDeclTpar
+     */
+    abstract public List<GenTypeDeclTpar> getTypeParams(Method method);
+    
+    /**
+     * Get a list of the type parameters for a generic constructor.
+     * (return an empty list if the method is not generic).
+     * 
+     * @param method   The method fro which to find the type parameters
+     * @return  A list of GenTypeDeclTpar
+     */
+    abstract public List<GenTypeDeclTpar> getTypeParams(Constructor<?> cons);
+    
+    /**
+     * Get a list of the type parameters for a class. Return an empty list if
+     * the class is not generic.
+     * 
+     * @param cl the class
+     * @return A List of GenTypeDeclTpar
+     */
+    abstract public List<GenTypeDeclTpar> getTypeParams(Class<?> cl);
+    
+    /**
+     * Get the declared supertype of a class.
+     */
+    abstract public GenTypeClass getSuperclass(Class<?> cl) throws ClassNotFoundException;
+    
+    /**
+     * Get a list of the interfaces directly implemented by the given class.
+     * @param cl  The class for which to find the interfaces
+     * @return    An array of interfaces
+     */
+    abstract public GenTypeClass [] getInterfaces(Class<?> cl) throws ClassNotFoundException;
+    
+    /**
+     * Gets an array of nicely formatted strings with the types of the parameters.
+     * Include the ellipsis (...) for a varargs method.
+     * 
+     * @param method The method to get the parameters for.
+     */
+    abstract public String[] getParameterTypes(Method method) throws ClassNotFoundException;
+    
+    /**
+     * Get an array containing the argument types of the method.
+     * 
+     * In the case of a varargs method, the last argument will be an array
+     * type.
+     * 
+     * @param method  the method whose argument types to get
+     * @param raw     whether to return the raw versions of argument types
+     * @return  the argument types
+     */
+    abstract public JavaType[] getParamGenTypes(Method method, boolean raw) throws ClassNotFoundException;
+    
+    /**
+     * Gets an array of nicely formatted strings with the types of the parameters.
+     * Include the ellipsis (...) for a varargs constructor.
+     * 
+     * @param constructor The constructor to get the parameters for.
+     */
+    abstract public String[] getParameterTypes(Constructor<?> constructor) throws ClassNotFoundException;
+    
+    /**
+     * Get an array containing the argument types of the method.
+     * 
+     * In the case of a varargs method, the last argument will be an array
+     * type.
+     * 
+     * @param method  the method whose argument types to get
+     * @return  the argument types
+     */
+    abstract public JavaType[] getParamGenTypes(Constructor<?> constructor) throws ClassNotFoundException;
+    
+    /**
+     * Change a list of type parameters (with bounds) into a map, which maps
+     * the name of the parameter to its bounding type.
+     * 
+     * @param tparams   A list of GenTypeDeclTpar
+     * @return          A map (String -> GenTypeSolid)
+     */
+    public static Map<String,GenTypeSolid> TParamsToMap(List<GenTypeDeclTpar> tparams)
+    {
+        Map<String,GenTypeSolid> rmap = new HashMap<String,GenTypeSolid>();
+        for( Iterator<GenTypeDeclTpar> i = tparams.iterator(); i.hasNext(); ) {
+            GenTypeDeclTpar n = i.next();
+            rmap.put(n.getTparName(), n.getBound().mapTparsToTypes(rmap).getUpperBound().asSolid());
+        }
+        return rmap;
+    }
+    
+    /**
+     * Check whether a member of some container type can be accessed from another type
+     * according to its modifiers.
+     * 
+     * @param container  The type containing the member to which access is being checked
+     * @param targetType The type of the expression from which the member is accessed
+     * @param accessor   The type trying to access the member
+     * @param modifiers  The modifiers of the member
+     * @param isStatic   True if the access is a in static context; false if not
+     * 
+     * @return  true if the access is allowed, false otherwise
+     */
+    public static boolean checkMemberAccess(Reflective container, GenTypeSolid targetType,
+            Reflective accessor, int modifiers, boolean isStatic)
+    {
+        // Access from a static context can only access static members
+        if (isStatic && !Modifier.isStatic(modifiers))
+            return false;
+        
+        if (Modifier.isPublic(modifiers)) {
+            return true;
+        }
+        
+        if (accessor == null) {
+            return false;
+        }
+        
+        String accessorName = accessor.getName();
+        if (! Modifier.isPrivate(modifiers)) {
+            String cpackage = JavaNames.getPrefix(container.getName());
+            if (accessorName.startsWith(cpackage)
+                    && accessorName.indexOf('.', cpackage.length() + 1) == -1) {
+                // Classes are in the same package, and the member is not private: access allowed
+                return true;
+            }
+        }
+        
+        // access class == container class, then access is always allowed
+        if (accessorName.equals(container.getName())) {
+            return true;
+        }
+        
+        Reflective outer = accessor.getOuterClass();
+        if (outer != null) {
+            // Inner classes can access outer class members with outer class privileges
+            isStatic |= accessor.isStatic();
+            if (checkMemberAccess(container, targetType, outer, modifiers, isStatic)) {
+                return true;
+            }
+        }
+        
+        // Protected access is allowed if the targetType is a subtype of the acessType
+        Set<Reflective> targetSupers = new HashSet<Reflective>();
+        targetType.erasedSuperTypes(targetSupers);
+        boolean allowProtected = false;
+        for (Reflective ref : targetSupers) {
+            if (accessor.isAssignableFrom(ref)) {
+                allowProtected = true;
+                break;
+            }
+        }
+        
+        List<Reflective> supers = accessor.getSuperTypesR();
+        Set<String> done = new HashSet<String>();
+        while (! supers.isEmpty()) {
+            Reflective r = supers.remove(0);
+            if (done.add(r.getName())) {
+                if (r.getName().equals(container.getName())) {
+                    if (Modifier.isProtected(modifiers)) {
+                        return allowProtected;
+                    }
+                } else {
+                    // We need to check super classes of our super-classes
+                    // as if the method is protected we will be allowed access 
+                    for (Reflective rParent : r.getSuperTypesR()) {
+                        supers.add(rParent);
+                    }
+                }
+            }
+        }
+        
+        return false;
+    }
+
+    /**
+     * Make a descriptive signature. This includes the method/constructor name (which may
+     * be preceded by type parameters), and parameter types or names or types and names.
+     * (The type is always substituted if the name is missing). 
+     * 
+     * @param name       The method/constructor name (including preceding
+     *                          type parameters if any)
+     * @param paramTypes   The parameter types
+     * @param paramNames   The parameter names (may be null)
+     * @param includeTypeNames   True if the parameter type should always be included
+     * @param isVarArgs      True if the method is varargs (requires ellipsis insertion)
+     */
+    protected static String makeDescription(String name, String[] paramTypes, String[] paramNames, boolean includeTypeNames, boolean isVarArgs)
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append(name);
+        sb.append("(");
+        for (int j = 0; j < paramTypes.length; j++) {
+            boolean typePrinted = false;
+            if (isVarArgs && j == paramTypes.length - 1) {
+                if (includeTypeNames || paramNames == null || paramNames[j] == null) {
+                    sb.append(paramTypes[j].substring(0, paramTypes[j].length() - 2));
+                    sb.append(" ");
+                }
+                sb.append("...");
+                typePrinted = true;
+            }
+            else if (includeTypeNames || paramNames == null || paramNames[j] == null) {                              
+                sb.append(paramTypes[j]);
+                typePrinted = true;
+            }
+            
+            if (paramNames != null && paramNames[j] != null) {
+                if (typePrinted)
+                    sb.append(" ");
+                sb.append(paramNames[j]);
+            }
+            if (j < (paramTypes.length - 1))
+                sb.append(", ");
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+    
+    /**
+     * Convert a javadoc comment to a string with just the comment body, i.e. strip the
+     * leading asterisks.
+     */
+    public static String javadocToString(String javadoc)
+    {
+        String eol = System.getProperty("line.separator");
+        
+        if (javadoc == null || javadoc.length() < 5) {
+            return null;
+        }
+        
+        StringBuffer outbuf = new StringBuffer();
+        
+        String str = javadoc;
+        if (javadoc.charAt(0) == '/') {
+            if (javadoc.charAt(1) == '*') {
+                if (javadoc.charAt(2) == '*') {
+                    // remove "/**" and "*/"
+                    str = javadoc.substring(3, javadoc.length() - 2);
+                }
+                else {
+                    // remove "/*" and "*/"
+                    str = javadoc.substring(2, javadoc.length() - 2);
+                }
+            }
+        }
+        
+        int nl = str.indexOf('\n');
+        int cr = str.indexOf('\r');
+        int pos = 0;
+        while (nl != -1 || cr != -1) {
+            int lineEnd = Math.min(nl, cr);
+            lineEnd = (nl == -1) ? cr : lineEnd;
+            lineEnd = (cr == -1) ? nl : lineEnd;
+            
+            String line = str.substring(pos, lineEnd);
+            line = stripLeadingStars(line);
+            
+            outbuf.append(line);
+            outbuf.append(eol);
+            
+            pos = lineEnd + 1;
+            if (pos == nl) {
+                pos++;
+            }
+
+            nl = str.indexOf('\n', pos);
+            cr = str.indexOf('\r', pos);
+        }
+        
+        String line = stripLeadingStars(str.substring(pos)).trim();
+        if (line.length() > 0) {
+            outbuf.append(line);
+        }
+        
+        return outbuf.toString();
+    }
+    
+    /**
+     * Convert javadoc comment body (as extracted by javadocToString for instance)
+     * to HTML suitable for display by HTMLEditorKit.
+     */
+    public static String javadocToHtml(String javadocString)
+    {
+        // find the first block tag
+        int i;
+        for (i = 0; i < javadocString.length(); i++) {
+            // Here we are the start of the line
+            while (i < javadocString.length() && Character.isWhitespace(javadocString.charAt(i))) {
+                i++;
+            }
+            if (i >= javadocString.length() || javadocString.charAt(i) == '@') {
+                break;
+            }
+            while (i < javadocString.length()
+                    && javadocString.charAt(i) != '\n'
+                    && javadocString.charAt(i) != '\r') {
+                i++;
+            }
+        }
+        
+        if (i >= javadocString.length()) {
+            return makeCommentColour(javadocString);
+        }
+        
+        // Process the block tags
+        String header = javadocString.substring(0, i);
+        String blocksText = javadocString.substring(i);
+        String[] lines = Utility.splitLines(blocksText);
+
+        List<String> blocks = getBlockTags(lines);
+
+        StringBuilder rest = new StringBuilder();
+        StringBuilder params = new StringBuilder();
+        params.append("<h3>Parameters</h3>").append("<table border=0>");
+        boolean hasParamDoc = false;
+
+        for (String block : blocks) {
+            if (block.startsWith("param ")) {
+                int p = "param".length();
+                // Find the parameter name
+                while (Character.isWhitespace(block.charAt(p))) {
+                    p++;
+                }
+                int k = p;
+                while (k < block.length() && !Character.isWhitespace(block.charAt(k))) {
+                    k++;
+                }
+                String paramName = block.substring(p, k);
+                String paramDesc = block.substring(k);
+
+                params.append("<tr><td valign=\"top\">&nbsp;&nbsp;&nbsp;");
+                params.append(makeCommentColour(paramName));
+                params.append("</td><td>");
+                params.append(makeCommentColour(" - " + paramDesc));
+                params.append("</td></tr>");
+                hasParamDoc = true;
+            } else {
+                rest.append(convertBlockTag(block)).append("<br>");
+            }
+        }           
+
+        params.append("</table><p>");
+
+        String result = makeCommentColour(header) + (hasParamDoc ? params.toString() : "<p>") + rest.toString();
+        return result;
+    }
+    
+    private static String makeCommentColour(String text)
+    {
+        return "<font color='#994400'>" + text + "</font>";
+    }
+
+    /**
+     * For a set of text lines representing block tags in a a javadoc comment, with some block
+     * tags potentially flowing over more than one line, return a list of Strings corresponding
+     * to each block tag with its complete text.
+     */
+    private static List<String> getBlockTags(String[] lines)
+    {
+        LinkedList<String> blocks = new LinkedList<String>();
+        String cur = "";
+        for (String line : lines) {
+            line = line.trim();
+            if (line.startsWith("@")) {
+                if (false == cur.isEmpty()) {
+                    blocks.addLast(cur);
+                }
+                cur = line.substring(1);
+            } else {
+                //If it doesn't start with an at, it's part of the previous tag
+                cur += " " + line;
+            }
+        }
+        blocks.addLast(cur);
+        return blocks;
+    }
+    
+    private static String convertBlockTag(String block)
+    {        
+        int k = 0;
+        while (k < block.length() && !Character.isWhitespace(block.charAt(k)))
+            k++;
+        
+        String r = "<b>" + block.substring(0, k) + "</b> - " + makeCommentColour(block.substring(k));
+        
+        return r;
+    }
+    
+    /**
+     * Strip leading asterisk characters (and any preceding whitespace) from a single
+     * line of text.
+     */
+    private static String stripLeadingStars(String s)
+    {
+        for (int i = 0; i < s.length(); i++) {
+            if (s.charAt(i) == '*') {
+                do {
+                    i++;
+                } while (i < s.length() && s.charAt(i) == '*');
+                s = s.substring(i);
+                break;
+            }
+            if (! Character.isWhitespace(s.charAt(i))) {
+                break;
+            }
+        }
+        return s;
+    }
+    
+    /**
+     * Get a GenType corresponding to the (raw) class c
+     */
+    public static JavaType genTypeFromClass(Class<?> c)
+    {
+        if (c.isPrimitive()) {
+            if (c == boolean.class)
+                return JavaPrimitiveType.getBoolean();
+            if (c == char.class)
+                return JavaPrimitiveType.getChar();
+            if (c == byte.class)
+                return JavaPrimitiveType.getByte();
+            if (c == short.class)
+                return JavaPrimitiveType.getShort();
+            if (c == int.class)
+                return JavaPrimitiveType.getInt();
+            if (c == long.class)
+                return JavaPrimitiveType.getLong();
+            if (c == float.class)
+                return JavaPrimitiveType.getFloat();
+            if (c == double.class)
+                return JavaPrimitiveType.getDouble();
+            if (c == void.class)
+                return JavaPrimitiveType.getVoid();
+            Debug.message("getReturnType: Unknown primitive type");
+        }
+        if (c.isArray()) {
+            JavaType componentT = genTypeFromClass(c.getComponentType());
+            return componentT.getArray();
+        }
+        return new GenTypeClass(new JavaReflective(c));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaUtils14.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaUtils14.java
new file mode 100644
index 0000000000000000000000000000000000000000..a079a0ae1a52dad09b5759adcce7c2e1beec12df
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaUtils14.java
@@ -0,0 +1,52 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+/**
+ * Java 1.4 version of JavaUtils
+ * 
+ * @author Davin McCall
+ */
+public class JavaUtils14
+{
+    /**
+     * Gets nicely formatted strings describing the parameter types.
+     */
+    public static String[] getParameterTypes(Class<?>[] params)
+    {
+        String[] parameterTypes = new String[params.length];
+        for (int j = 0; j < params.length; j++) {
+            String typeName = getTypeName(params[j]);
+            parameterTypes[j] = typeName;
+        }
+        return parameterTypes;
+    }
+
+    /**
+     * Get a type name, with prefix stripped. For array types return the base
+     * type name plus the appropriate number of "[]" qualifiers.
+     */
+    public static String getTypeName(Class<?> type)
+    {
+        return JavaNames.stripPrefix(JavaUtils.getFQTypeName(type));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaUtils15.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaUtils15.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce2555bfd64764d41e032e71a9f73362e92152a5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/JavaUtils15.java
@@ -0,0 +1,660 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import bluej.debugger.gentype.*;
+
+/**
+ * Java 1.5+ version of JavaUtils.
+ * 
+ * @author Davin McCall
+ */
+public class JavaUtils15 extends JavaUtils
+{
+    /*
+     * Make signatures for methods, constructors
+     */
+    
+    /*
+     * Make descriptions of methods
+     */
+    
+    /**
+     * Get a short or long method description which maps type parameters to types using
+     * the supplied map. 
+     */
+    public String getDescription(Method method, String [] paramnames,
+            Map<String,? extends GenTypeParameter> tparams, boolean longDesc)
+        throws ClassNotFoundException
+    {
+        // If tparams is null, the parent object is raw.
+        if(tparams == null) {
+            String name = JavaUtils14.getTypeName(method.getReturnType()) + " " + method.getName();
+            Class<?>[] params = method.getParameterTypes();
+            String[] paramTypes = JavaUtils14.getParameterTypes(params);
+            return makeDescription(name, paramTypes, paramnames, longDesc, false);
+        }
+        
+        // Don't want to modify the map which was passed in, so make a copy:
+        Map<String,GenTypeParameter> newMap = new HashMap<String,GenTypeParameter>(tparams);
+
+        // add any method type parameters into the map, replacing existing
+        // map entries.
+        List<GenTypeDeclTpar> myParams = getTypeParams(method);
+        for(Iterator<GenTypeDeclTpar> i = myParams.iterator(); i.hasNext(); ) {
+            GenTypeDeclTpar tpar = i.next();
+            newMap.put(tpar.getTparName(), tpar);
+        }
+        
+        // assemble the type parameters, return type, method name, parameters
+        String name = getTypeParameters(method);
+        JavaType rtype = getReturnType(method);
+        name += rtype.mapTparsToTypes(newMap).toString(true) + " " + method.getName();
+        JavaType[] paramTypes = getParamGenTypes(method, false);
+        String[] paramTypeNames = new String[paramTypes.length];
+        for(int i = 0; i < paramTypes.length; i++) {
+            paramTypeNames[i] = paramTypes[i].mapTparsToTypes(newMap).toString(true);
+        }
+        
+        return makeDescription(name, paramTypeNames, paramnames, longDesc, method.isVarArgs());
+    }
+
+    @Override
+    public String getShortDesc(Method method, String [] paramnames, Map<String,GenTypeParameter> tparams)
+        throws ClassNotFoundException
+    {
+        return getDescription(method, paramnames, tparams, false);
+    }
+
+    @Override
+    public String getLongDesc(Method method, String [] paramnames, Map<String,GenTypeParameter> tparams)
+        throws ClassNotFoundException
+    {
+        return getDescription(method, paramnames, tparams, true);
+    }
+    
+    @Override
+    public String getShortDesc(Method method, String [] paramnames)
+        throws ClassNotFoundException
+    {
+        try {
+            String name = getTypeParameters(method);
+            name += getTypeName(method.getGenericReturnType()) + " " + method.getName();
+
+            // Get the names without introducing ellipsis for varargs
+            Type[] paramTypes = method.getGenericParameterTypes();       
+            String[] paramTypeNames = getParameterTypes(paramTypes, false);
+
+            return makeDescription(name, paramTypeNames, paramnames, false, method.isVarArgs());
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+    }
+
+    @Override
+    public String getLongDesc(Method method, String [] paramnames) throws ClassNotFoundException
+    {
+        try {
+            String name = getTypeParameters(method);
+            name += getTypeName(method.getGenericReturnType()) + " " + method.getName();
+
+            // Get the names without introducing ellipsis for varargs
+            Type[] paramTypes = method.getGenericParameterTypes();       
+            String[] paramTypeNames = getParameterTypes(paramTypes, false);
+
+            // String[] paramTypes = getParameterTypes(method);
+            return makeDescription(name, paramTypeNames, paramnames, true, method.isVarArgs());
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+    }
+    
+    /*
+     * Make descriptions of constructors
+     */
+    
+    /**
+     * Make a constructor description (short or long).
+     */
+    public String getDescription(Constructor<?> constructor, String [] paramnames, boolean longDesc)
+        throws ClassNotFoundException
+    {
+        String name = getTypeParameters(constructor);
+        name += constructor.getName();        
+        name += typeParamsToString(constructor.getDeclaringClass().getTypeParameters(), false); 
+
+        // Get the names without introducing ellipsis for varargs
+        Type[] paramTypes = constructor.getGenericParameterTypes();       
+        String[] paramTypeNames = getParameterTypes(paramTypes, false);
+
+        //String[] paramTypes = getParameterTypes(constructor);
+        return makeDescription(name, paramTypeNames, paramnames, longDesc, constructor.isVarArgs());
+    }
+    
+    @Override
+    public String getShortDesc(Constructor<?> constructor, String [] paramnames)
+        throws ClassNotFoundException
+    {
+        return getDescription(constructor, paramnames, false);
+    }
+
+    @Override
+    public String getLongDesc(Constructor<?> constructor, String [] paramnames)
+        throws ClassNotFoundException
+    {
+        return getDescription(constructor, paramnames, true);
+    }
+    
+    /*
+     * Check various attributes of constructors / methods
+     */
+    
+    @Override
+    public boolean isVarArgs(Constructor<?> cons)
+    {
+        return cons.isVarArgs();
+    }
+    
+    @Override
+    public boolean isVarArgs(Method method)
+    {
+        return method.isVarArgs();
+    }
+
+    @Override
+    public boolean isSynthetic(Method method)
+    {
+        return method.isSynthetic();
+    }
+    
+    @Override
+    public boolean isEnum(Class<?> cl)
+    {
+        return cl.isEnum();
+    }
+    
+    @Override
+    public JavaType getReturnType(Method method) throws ClassNotFoundException
+    {
+        try {
+            Type rt = method.getGenericReturnType();
+            return genTypeFromType(rt);
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+    }
+    
+    @Override
+    public JavaType getRawReturnType(Method method)
+    {
+        Class<?> c = method.getReturnType();
+        return JavaUtils.genTypeFromClass(c);
+    }
+    
+    @Override
+    public JavaType getFieldType(Field field) throws ClassNotFoundException
+    {
+        try {
+            return genTypeFromType(field.getGenericType());
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+    }
+    
+    @Override
+    public JavaType getRawFieldType(Field field)
+    {
+        Class<?> c = field.getType();
+        return JavaUtils.genTypeFromClass(c);
+    }
+    
+    @Override
+    public List<GenTypeDeclTpar> getTypeParams(Method method)
+    {
+        return getTypeParams((GenericDeclaration) method);
+    }
+    
+    @Override
+    public List<GenTypeDeclTpar> getTypeParams(Constructor<?> cons)
+    {
+        return getTypeParams((GenericDeclaration) cons);
+    }
+
+    @Override
+    public List<GenTypeDeclTpar> getTypeParams(Class<?> cl)
+    {
+        return getTypeParams((GenericDeclaration) cl);
+    }
+    
+    @Override
+    public GenTypeClass getSuperclass(Class<?> cl) throws ClassNotFoundException
+    {
+        try {
+            Type sc = cl.getGenericSuperclass();
+            if( sc == null ) {
+                return null;
+            }
+            return (GenTypeClass)genTypeFromType(sc);
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+    }
+    
+    @Override
+    public GenTypeClass [] getInterfaces(Class<?> cl) throws ClassNotFoundException
+    {
+        try {
+            Type [] classes = cl.getGenericInterfaces();
+            GenTypeClass [] gentypes = new GenTypeClass[classes.length];
+
+            for( int i = 0; i < classes.length; i++ ) {
+                gentypes[i] = (GenTypeClass)genTypeFromType(classes[i]);
+            }
+
+            return gentypes;
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+    }    
+    
+    @Override
+    public String[] getParameterTypes(Method method) throws ClassNotFoundException
+    {
+        try {
+            Type [] params = method.getGenericParameterTypes();
+            boolean isVarArgs = isVarArgs(method);
+            return getParameterTypes(params, isVarArgs);
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+    }
+    
+    @Override
+    public JavaType[] getParamGenTypes(Method method, boolean raw) throws ClassNotFoundException
+    {
+        try {
+            Type [] params;
+            if (raw) {
+                params = method.getParameterTypes();
+            }
+            else {
+                params = method.getGenericParameterTypes();
+            }
+            JavaType [] gentypes = new JavaType[params.length];
+            for(int i = 0; i < params.length; i++) {
+                gentypes[i] = (JavaType) genTypeFromType(params[i]);
+            }
+            return gentypes;
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+    }
+
+    @Override
+    public String[] getParameterTypes(Constructor<?> constructor) throws ClassNotFoundException
+    {
+        try {
+            Type [] params = constructor.getGenericParameterTypes();
+            boolean isVarArgs = isVarArgs(constructor);
+            return getParameterTypes(params, isVarArgs);
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+
+    }
+
+    @Override
+    public JavaType[] getParamGenTypes(Constructor<?> constructor) throws ClassNotFoundException
+    {
+        try {
+            Type [] params = constructor.getGenericParameterTypes();
+            JavaType [] gentypes = new JavaType[params.length];
+            for(int i = 0; i < params.length; i++) {
+                gentypes[i] = (JavaType) genTypeFromType(params[i]);
+            }
+            return gentypes;
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+    }
+
+    /* -------------- Internal methods ---------------- */
+    
+    /**
+     * Get the type parameters for any GenericDeclaration implementor. This
+     * includes Methods, Constructors and Classes.
+     */
+    private List<GenTypeDeclTpar> getTypeParams(GenericDeclaration decl)
+    {
+        List<GenTypeDeclTpar> rlist = new ArrayList<GenTypeDeclTpar>();
+        TypeVariable<?> [] tvars = decl.getTypeParameters();
+
+        Map<String,GenTypeDeclTpar> tvarMap = new HashMap<String,GenTypeDeclTpar>();
+
+        for (TypeVariable<?> tvar : tvars) {
+            tvarMap.put(tvar.getName(), new GenTypeDeclTpar(tvar.getName()));
+        }
+
+        for( int i = 0; i < tvars.length; i++ ) {
+            // find the bounds.
+            Type [] bounds = tvars[i].getBounds();
+            GenTypeSolid [] upperBounds = new GenTypeSolid[bounds.length];
+            for (int j = 0; j < bounds.length; j++) {
+                upperBounds[j] = (GenTypeSolid) genTypeFromType(bounds[j], tvarMap);
+            }
+
+            // add the type parameter to the list.
+            GenTypeDeclTpar tpar = tvarMap.get(tvars[i].getName());
+            tpar.setBounds(upperBounds);
+
+            rlist.add(tpar);
+        }
+        return rlist;
+    }
+    
+    /**
+     * Gets nicely formatted strings describing the parameter types.
+     */
+    private String[] getParameterTypes(Type[] params, boolean isVarArgs) throws ClassNotFoundException
+    {
+        String[] parameterTypes = new String[params.length];
+        for (int j = 0; j < params.length; j++) {
+            String typeName = getTypeName(params[j]);
+            if (isVarArgs && j == (params.length - 1)) {
+                typeName = createVarArg(typeName);
+            }
+            parameterTypes[j] = typeName;
+        }
+        return parameterTypes;
+    }
+
+    /**
+     * Express the given type as a string.
+     */
+    static private String getTypeName(Type type) throws ClassNotFoundException
+    {
+        try {
+            StringBuffer sb = new StringBuffer();
+            Type primtype = type;
+            int dimensions = 0;
+            while(primtype instanceof GenericArrayType) {
+                dimensions++;
+                primtype = ((GenericArrayType)primtype).getGenericComponentType();
+            }
+
+            if(primtype instanceof Class<?>) {
+                sb.append(JavaUtils14.getTypeName((Class<?>)primtype));
+            }
+            else if(primtype instanceof ParameterizedType) {
+                sb.append(getTypeName((ParameterizedType)primtype));
+            }
+            else if(primtype instanceof TypeVariable<?>) {
+                sb.append(((TypeVariable<?>)primtype).getName());
+            }
+            else if(primtype instanceof WildcardType) {
+                sb.append(getTypeName((WildcardType)primtype));
+            }
+            else {
+                Debug.message("getTypeName(): Unknown type: " + primtype.getClass().getName());
+            }
+
+            while( dimensions > 0 ) {
+                sb.append("[]");
+                dimensions--;
+            }
+            return sb.toString();
+        }
+        catch (TypeNotPresentException tnpe) {
+            throw new ClassNotFoundException(tnpe.typeName(), tnpe.getCause());
+        }
+    }
+
+    static private String getTypeName(ParameterizedType type)
+        throws ClassNotFoundException
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getTypeName(type.getRawType()));
+        sb.append('<');
+        
+        Type [] argTypes = type.getActualTypeArguments();
+        for(int i = 0; i < argTypes.length; i++) {
+            sb.append(getTypeName(argTypes[i]));
+            if( i != argTypes.length - 1 ) {
+                sb.append(',');
+            }
+        }
+        
+        sb.append('>');
+        return sb.toString();
+    }
+
+    static private String getTypeName(WildcardType type) throws ClassNotFoundException
+    {
+        StringBuffer sb = new StringBuffer();
+        Type[] upperBounds = type.getUpperBounds();
+        Type[] lowerBounds = type.getLowerBounds();
+        // The check for lowerBounds[0] == null is necessary. Appears to be
+        // a bug in Java 1.5 beta2.
+        if( lowerBounds.length == 0 || lowerBounds[0] == null ) {
+            
+            // An unbounded wildcard by reflection appears as
+            // "? extends java.lang.Object". We check for that case and
+            // reduce it back to unbounded. This is not necessarily correct
+            // seeing as it could have been declared with "extends", but that
+            // would be superfluous and will hopefully prove to be uncommon.
+            if( upperBounds.length == 0 || upperBounds[0] == null || upperBounds[0].equals(Object.class)) {
+                sb.append("?"); // unbounded wildcard
+            }
+            else {
+                sb.append("? extends ");
+                sb.append(getTypeName(upperBounds[0]));
+                if( upperBounds.length != 1 )
+                    Debug.message("getTypeName: multiple upper bounds for wildcard type?");
+            }
+        } else {
+            sb.append("? super ");
+            if( lowerBounds[0] == null ) {
+                Debug.message("lower bound[0] is null??");
+                sb.append("[null type]");
+            }
+            else
+                sb.append(getTypeName(lowerBounds[0]));
+            if( upperBounds.length != 0 && upperBounds[0] != null && upperBounds[0] != Object.class) {
+                Debug.message("getTypeName: upper and lower bound?");
+                Debug.message("upper bound is: " + upperBounds[0]);
+            }
+            if( lowerBounds.length != 1 )
+                Debug.message("getTypeName: multiple lower bounds for wildcard type?");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Convert a type name into its vararg form. For instance,
+     * "int []" becomes "int ...".
+     */
+    static private String createVarArg(String typeName)
+    {
+        String lastArrayStripped = typeName.substring(0,typeName.length()-2);
+        return lastArrayStripped + " ...";        
+    }
+
+    /**
+     * Get the type parameters for a generic method. For example, for the
+     * method:   <code>&lt;T&gt; addAll(List&lt;T&gt;)</code>
+     * this would return "&lt;T&gt; " (including the trailing space).
+     * Returns the empty string for a non-generic method.
+     * 
+     * @param method  The method to retrieve the parameters of
+     * @return the parameters (or an empty string)
+     */
+    static private String getTypeParameters(Method method)
+        throws ClassNotFoundException
+    {
+        return typeParamsToString(method.getTypeParameters(), true);
+    }
+    
+    static private String getTypeParameters(Constructor<?> cons)
+        throws ClassNotFoundException
+    {
+        return typeParamsToString(cons.getTypeParameters(), true);
+    }
+    
+    /**
+     * Convert a TypeVariable array into a string representing a type parameter sequence,
+     * surrounded by angle brackets, with an optional trailing space (omitted if there
+     * are no type parameters).
+     */
+    static private String typeParamsToString(TypeVariable<?> [] tparams, boolean extraSpace)
+        throws ClassNotFoundException
+    {
+        if( tparams.length != 0 ) {
+            String name = "<";
+            for( int i = 0; i < tparams.length; i++ ) {
+                TypeVariable<?> type = tparams[i];
+                name += type.getName();        
+                Type[] upperBounds = type.getBounds();
+
+                // An unbounded type by reflection appears as
+                // " extends java.lang.Object". We check for that case and
+                // reduce it back to unbounded. This is not necessarily correct
+                // seeing as it could have been declared with "extends", but that
+                // would be superfluous and will hopefully prove to be uncommon.
+                if (upperBounds.length == 0 || upperBounds[0] == null
+                        || upperBounds[0].equals(Object.class)) {
+                    //add nothing
+                } else {
+                    name += " extends " + getTypeName(upperBounds[0]);
+                    for (int j = 1; j < upperBounds.length; j++) {
+                        name += " & " + getTypeName(upperBounds[j]);
+                    }
+                }
+                               
+                if( i != tparams.length - 1 ) {
+                    name += ',';
+                }
+            }
+            name += ">";
+            if (extraSpace) {
+                name += " ";
+            }
+            return name;
+        }
+        else {
+            return "";
+        }
+    }
+
+    /**
+     * Build a GenType structure from a "Type" object.
+     */
+    private static JavaType genTypeFromType(Type t)
+    {
+        return (JavaType) genTypeFromType(t, new HashMap<String,GenTypeParameter>());
+    }
+    
+    /**
+     * Build a GenType structure from a "Type" object, using the given backTrace
+     * stack to avoid infinite recursion.
+     */
+    private static GenTypeParameter genTypeFromType(Type t, Map<String,? extends GenTypeParameter> tvars)
+    {
+        if (t instanceof Class<?>) {
+            return JavaUtils.genTypeFromClass((Class<?>)t);
+        }
+        
+        if (t instanceof TypeVariable<?>) {
+            TypeVariable<?> tv = (TypeVariable<?>) t;
+            GenTypeParameter existingTpar = tvars.get(tv.getName());
+            if (existingTpar != null) {
+                return existingTpar;
+            }
+            
+            return new GenTypeTpar(tv.getName());
+        }
+        if (t instanceof WildcardType) {
+            WildcardType wtype = (WildcardType)t;
+            Type[] upperBounds = wtype.getUpperBounds();
+            Type[] lowerBounds = wtype.getLowerBounds();
+            // The check for lowerBounds[0] == null is necessary. Appears to be
+            // a bug in Java 1.5 beta2.
+            if (lowerBounds.length == 0 || lowerBounds[0] == null) {
+                if (upperBounds.length == 0 || upperBounds[0] == null) {
+                    return new GenTypeUnbounded();
+                }
+                else {
+                    GenTypeSolid gtp = (GenTypeSolid)genTypeFromType(upperBounds[0], tvars);
+                    if( upperBounds.length != 1 ) {
+                        Debug.message("GenTypeFromType: multiple upper bounds for wildcard type?");
+                    }
+                    return new GenTypeExtends(gtp);
+                }
+            } else {
+                if (upperBounds.length != 0 && upperBounds[0] != null && upperBounds[0] != Object.class) {
+                    Debug.message("getTypeName: upper and lower bound?");
+                }
+                if (lowerBounds.length != 1) {
+                    Debug.message("getTypeName: multiple lower bounds for wildcard type?");
+                }
+                GenTypeParameter lbound = genTypeFromType(lowerBounds[0], tvars);
+                return new GenTypeSuper((GenTypeSolid) lbound);
+            }
+        }
+        if( t instanceof ParameterizedType ) {
+            ParameterizedType pt = (ParameterizedType)t;
+            Class<?> rawtype = (Class<?>)pt.getRawType();
+            Type [] argtypes = pt.getActualTypeArguments();
+            List<GenTypeParameter> arggentypes = new ArrayList<GenTypeParameter>();
+            
+            // Convert the Type [] into a List of GenType
+            for( int i = 0; i < argtypes.length; i++ )
+                arggentypes.add(genTypeFromType(argtypes[i], tvars));
+            
+            // Check for outer type
+            GenTypeClass outer = null;
+            if (pt.getOwnerType() != null) {
+                outer = (GenTypeClass) genTypeFromType(pt.getOwnerType());
+            }
+            
+            return new GenTypeClass(new JavaReflective(rawtype), arggentypes, outer);
+        }
+        
+        // Assume we have an array
+        GenericArrayType gat = (GenericArrayType)t;
+        JavaType componentType = (JavaType) genTypeFromType(gat.getGenericComponentType(), tvars);
+        
+        return componentType.getArray();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MiksGridLayout.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MiksGridLayout.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3182f41ecb6feb8fd09b47f99f2ee0cebf81c30
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MiksGridLayout.java
@@ -0,0 +1,257 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+import java.awt.*;
+
+/**
+ * MiksGridLayout - a grid layout with non-homogenous column widths.
+ * 
+ * @version $Id: mergeCopyTarget64862.tmp 5416 2007-12-11 15:40:37Z cecilia $
+ */
+public class MiksGridLayout extends GridLayout
+{
+    // Specifies which row receives additional vertical space
+    private int verticalExpandingRow = -1;
+    
+    /**
+     * Creates a grid layout with the specified number of rows and 
+     * columns.
+     */
+    public MiksGridLayout(int rows, int cols)
+    {
+        this(rows, cols, 0, 0);
+    }
+
+    /**
+     * Creates a grid layout with the specified number of rows and columns,
+     * and the given gap between each column and row.
+     */
+    public MiksGridLayout(int rows, int cols, int hgap, int vgap)
+    {
+        super(rows, cols, hgap, vgap);
+    }
+    
+    // Sets which row receives additional vertical space
+    // (by default it is the last one)
+    public void setVerticallyExpandingRow(int row)
+    {
+        verticalExpandingRow = row;
+    }
+
+    /** 
+     * Determines the preferred size of the container argument using 
+     * this grid layout. 
+     */
+    public Dimension preferredLayoutSize(Container parent)
+    {
+        synchronized (parent.getTreeLock()) {
+            Insets insets = parent.getInsets();
+            int ncomponents = parent.getComponentCount();
+            int nrows = getRows();
+            int ncols = getColumns();
+            
+            if (nrows > 0) {
+                ncols = (ncomponents + nrows - 1) / nrows;
+            } else {
+                nrows = (ncomponents + ncols - 1) / ncols;
+            }
+
+            int[] colWidth = new int[ncols];
+            int[] rowHeight = new int[nrows];
+
+            for(int i = 0; i < ncomponents; i++) {
+                Component comp = parent.getComponent(i);
+                Dimension d = comp.getPreferredSize();
+                int row = i / ncols;
+                int col = i % ncols;
+                if (rowHeight[row] < d.height) {
+                    rowHeight[row] = d.height;
+                }
+                if (colWidth[col] < d.width) {
+                    colWidth[col] = d.width;
+                }
+            }            
+            
+            int allColWidth = 0;
+            for(int col = 0; col < ncols; col++) {
+                allColWidth += colWidth[col];
+            }
+            
+            int allRowHeight = 0;
+            for(int row = 0; row < nrows; row++) {
+                allRowHeight += rowHeight[row];
+            }
+            
+            return new Dimension(insets.left + insets.right + allColWidth + (ncols-1)*getHgap(), 
+                         insets.top + insets.bottom + allRowHeight + (nrows-1)*getVgap());
+        }
+    }
+
+    /**
+     * Determines the minimum size of the container argument using this 
+     * grid layout. 
+     */
+    public Dimension minimumLayoutSize(Container parent)
+    {
+        synchronized (parent.getTreeLock()) {
+            Insets insets = parent.getInsets();
+            int ncomponents = parent.getComponentCount();
+            int nrows = getRows();
+            int ncols = getColumns();
+            
+            if (nrows > 0) {
+                ncols = (ncomponents + nrows - 1) / nrows;
+            } else {
+                nrows = (ncomponents + ncols - 1) / ncols;
+            }
+
+            int[] colWidth = new int[ncols];
+            int[] rowHeight = new int[nrows];
+
+            for(int i = 0; i < ncomponents; i++) {
+                Component comp = parent.getComponent(i);
+                Dimension d = comp.getMinimumSize();
+                int row = i / ncols;
+                int col = i % ncols;
+                if (rowHeight[row] < d.height) {
+                    rowHeight[row] = d.height;
+                }
+                if (colWidth[col] < d.width) {
+                    colWidth[col] = d.width;
+                }
+            }            
+            
+            int allColWidth = 0;
+            for(int col = 0; col < ncols; col++) {
+                allColWidth += colWidth[col];
+            }
+            
+            int allRowHeight = 0;
+            for(int row = 0; row < nrows; row++) {
+                allRowHeight += rowHeight[row];
+            }
+            
+            return new Dimension(insets.left + insets.right + allColWidth + (ncols-1)*getHgap(), 
+                         insets.top + insets.bottom + allRowHeight + (nrows-1)*getVgap());
+        }
+    }
+
+    /** 
+     * Lays out the specified container using this layout. 
+     */
+    public void layoutContainer(Container parent)
+    {
+        synchronized (parent.getTreeLock()) {
+            Insets insets = parent.getInsets();
+            int ncomponents = parent.getComponentCount();
+            int nrows = getRows();
+            int ncols = getColumns();
+            int hgap = getHgap();
+            int vgap = getVgap();
+            boolean ltr = parent.getComponentOrientation().isLeftToRight();
+            
+            if(!ltr)
+                throw new IllegalArgumentException("Orientation oher than left-to-right not supported");
+        
+            if (ncomponents == 0) {
+                return;
+            }
+            if (nrows > 0) {
+                ncols = (ncomponents + nrows - 1) / nrows;
+            } else {
+                nrows = (ncomponents + ncols - 1) / ncols;
+            }
+            
+            // compute the width of each column (max width of component in column)
+
+            int[] colWidth = new int[ncols];
+
+            for(int col = 0; col < ncols; col++) {
+                int w = 0;
+                for (int i = col ; i < ncomponents ; i+=ncols) {
+                    Component comp = parent.getComponent(i);
+                    Dimension d = comp.getPreferredSize();
+                    if (w < d.width) {
+                        w = d.width;
+                    }
+                }
+                colWidth[col] = w;
+            }
+
+            int colSum = 0;     // all columns except last one
+            for(int col = 0; col < ncols-1; col++) {
+                colSum += colWidth[col];
+            }
+
+            int[] rowHeight = new int[nrows];
+            int rowSum = 0;
+            
+            // compute the height of each row (max width of component in row)
+
+            for(int row = 0; row < nrows; row++) {
+                int h = 0;
+                for (int i = row*ncols ; (i < (row+1)*ncols) && (i < ncomponents) ; i++) {
+                    Component comp = parent.getComponent(i);
+                    Dimension d = comp.getPreferredSize();
+                    if (h < d.height) {
+                        h = d.height;
+                    }
+                }
+                rowHeight[row] = h;
+            }
+            
+            //The row that soaks up the extra space:
+            int soakRow = verticalExpandingRow == -1 ? nrows-1 : verticalExpandingRow;
+
+            rowSum = 0;     // all rows except soakRow
+            for(int row = 0; row < nrows; row++) {
+                if (row != soakRow)
+                    rowSum += rowHeight[row];
+            }
+
+            int parentWidth = parent.getWidth() - (insets.left + insets.right);
+            int parentHeight = parent.getHeight() - (insets.top + insets.bottom);
+            
+            // set width of last column to take all the remaining space
+            colWidth[ncols-1] = (parentWidth - (ncols - 1) * hgap) - colSum;
+            if(colWidth[ncols-1] < 0)
+                colWidth[ncols-1] = 0;
+                
+            // set height of soakRow to take all the remaining space
+            rowHeight[soakRow] = (parentHeight - (nrows - 1) * vgap) - rowSum;
+            if(rowHeight[soakRow] < 0)
+                rowHeight[soakRow] = 0;
+            
+            for (int r = 0, y = insets.top ; r < nrows ; y += rowHeight[r] + vgap, r++) {
+                int x = insets.left;
+                for (int c = 0; c < ncols ; c++) {
+                    int i = r * ncols + c;
+                    if (i < ncomponents) {
+                        parent.getComponent(i).setBounds(x, y, colWidth[c], rowHeight[r]);
+                    }
+                    x += colWidth[c] + hgap;
+                }
+            }
+        }
+    }
+    
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MultiIterator.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MultiIterator.java
new file mode 100644
index 0000000000000000000000000000000000000000..fbe3666fdedc812dbfd6daa72b51be74ef96a8fb
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MultiIterator.java
@@ -0,0 +1,75 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * A multiplexing Iterator.
+ * @author Michael Cahill
+ * @author Michael Kolling
+ */
+public class MultiIterator<T> implements Iterator<T>
+{
+    @Override
+  public void forEachRemaining(Consumer<? super T> action) {
+    // TODO Auto-generated method stub
+    
+  }
+
+    List<Iterator<? extends T>> iterations;
+    int current;
+	
+    public MultiIterator(List<Iterator<? extends T>> iterations)
+    {
+        this.iterations = iterations;
+        current = 0;
+    }
+	
+    public boolean hasNext()
+    {
+        for( ; current < iterations.size(); current++)
+            if((iterations.get(current)).hasNext())
+                return true;
+	
+        return false;
+    }
+
+    public T next()
+    {
+        for( ; current < iterations.size(); current++) {
+            Iterator<? extends T> it = iterations.get(current);
+            if(it.hasNext()) {
+                return it.next();
+            }
+        }
+		
+        return null;
+    }
+    
+    public void remove()
+    {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MultiLineLabel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MultiLineLabel.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8bcf73cd19c4e4ddfe636e31258e0113cb34190
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MultiLineLabel.java
@@ -0,0 +1,150 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ ** @version $Id: MultiLineLabel.java 6215 2009-03-30 13:28:25Z polle $
+ ** @author Justin Tan
+ ** A multi-line Label-like AWT component.
+ **/
+public class MultiLineLabel extends JPanel
+{
+    protected int fontAttributes = Font.PLAIN;
+    protected float alignment;
+    protected Color col = null;
+	protected int spacing = 0;
+    
+    /**
+     ** Constructor - make a multiline label
+     **/
+    public MultiLineLabel(String text, float alignment)
+    {
+        this.alignment = alignment;
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+        if(text != null)
+            setText(text);
+    }
+
+    /**
+     ** Constructor, defaults to centered text
+     **/
+    public MultiLineLabel(String text)
+    {
+        this(text, LEFT_ALIGNMENT);
+    }
+
+    /**
+     * Constructor, empty with the given alignment
+     */
+    public MultiLineLabel(float alignment)
+    {
+        this(null, alignment);
+    }
+
+    /**
+     * Constructor, empty with the given alignment and line spacing
+     */
+    public MultiLineLabel(float alignment, int spacing)
+    {
+        this(null, alignment);
+        this.spacing = spacing;
+    }
+
+    /**
+     ** Constructor - make an empty multiline label
+     **/
+    public MultiLineLabel()
+    {
+        this(null, LEFT_ALIGNMENT);
+    }
+	
+    public void setText(String text)
+    {
+        // clear the existing lines from the panel
+        removeAll();
+        addText(text);
+    }
+	
+    public void addText(String text)
+    {
+        addText(text, 12);
+    }
+    
+    public void addText(String text, int size)
+    {
+        if(spacing > 0)
+            add(Box.createVerticalStrut(spacing));
+
+        String strs[] = Utility.splitLines(text);
+        JLabel l;
+        Font font = new Font("SansSerif", fontAttributes, size);
+
+        for (int i = 0; strs != null && i < strs.length; i++) {
+            l = new JLabel(strs[i]);
+            l.setFont(font);
+            l.setAlignmentX(alignment);
+
+            if (col != null)
+                l.setForeground(col);
+
+            add(l);
+        }   
+    }
+    
+    public void addText(String text, boolean bold, boolean italic)
+    {
+        int oldAttributes = fontAttributes;
+        setBold(bold);
+        setItalic(italic);
+        addText(text);
+        fontAttributes = oldAttributes;
+    }
+
+    public void setForeground(Color col)
+    {
+        this.col = col;    
+        Component[] components = this.getComponents();
+        for (int i = 0; i < components.length; i++) {
+			Component component = components[i];
+			component.setForeground(col);
+		}
+    }
+    	
+    public void setItalic(boolean italic)
+    {
+        if(italic)
+           fontAttributes |= Font.ITALIC;
+        else
+            fontAttributes &= ~Font.ITALIC;
+    }
+	
+    public void setBold(boolean bold)
+    {
+        if(bold)
+            fontAttributes |= Font.BOLD;
+        else
+            fontAttributes &= ~Font.BOLD;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MultiWrapLabel.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MultiWrapLabel.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8cf71eb90e35de6350b5050968046d0d1fe22b7
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/MultiWrapLabel.java
@@ -0,0 +1,334 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.awt.Dimension;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.geom.Rectangle2D;
+
+import javax.swing.JComponent;
+
+/**
+ * A label which supports multiple lines of text, and which wraps text if
+ * it is too long (longer than the label width). An arbitrary wrapping width
+ * can also be specified.
+ * 
+ * @author Davin McCall
+ * @version $Id: MultiWrapLabel.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class MultiWrapLabel extends JComponent
+{
+    private static String lineSep = System.getProperty("line.separator");
+    
+    private String text;
+    private int wrapWidth;
+    
+    /**
+     * Create an empty MultiWrapLabel.
+     */
+    public MultiWrapLabel()
+    {
+        text = "";
+        wrapWidth = -1;
+    }
+    
+    /**
+     * Create a MultiWrapLabel to display the given text.
+     */
+    public MultiWrapLabel(String text)
+    {
+        this.text = text;
+        wrapWidth = -1;
+    }
+    
+    /**
+     * Set the text which this MultiWrapLabel should display.
+     */
+    public void setText(String text)
+    {
+        this.text = text;
+        invalidate();
+    }
+    
+    /**
+     * Set the desired wrap width for this MultiWrapLabel. This also determines
+     * the preferred width of the label. Text will be wrapped at the given width,
+     * unless the width of the label is less than the given width, in which case
+     * text will be wrapped at the width of the label instead.
+     * 
+     * Specify -1 to indicate there is no preferred wrap width. In this case the
+     * preferred width of the label will be the length of the longest line of text
+     * in the label, and text will always wrap at the width of the label.
+     * 
+     * @param wrapWidth  The desired wrapping width, or -1 for no specific width.
+     */
+    public void setWrapWidth(int wrapWidth)
+    {
+        this.wrapWidth = wrapWidth;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.Component#getMaximumSize()
+     */
+    public Dimension getMaximumSize()
+    {
+        if (isMaximumSizeSet()) {
+            return super.getMaximumSize();
+        }
+        else {
+            return getPreferredSize();
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.Component#getMinimumSize()
+     */
+    public Dimension getMinimumSize()
+    {
+        if (isMinimumSizeSet()) {
+            return super.getMinimumSize();
+        }
+        else {
+            return getPreferredSize();
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see java.awt.Component#getPreferredSize()
+     */
+    public Dimension getPreferredSize()
+    {
+        if (isPreferredSizeSet()) {
+            return super.getPreferredSize();
+        }
+        else if (wrapWidth != -1) {
+            return getPreferredSizeWrapped();
+        }
+        else {
+            // The preferred size is the width of the longest line, and
+            // the summed height of all lines.
+            double height = 0f;
+            double width = 0f;
+            
+            FontMetrics metrics = getFontMetrics(getFont());
+            int npos = 0;
+            while (npos < text.length()) {
+                int end = text.indexOf(lineSep, npos);
+                if (end == -1) {
+                    end = text.length();
+                }
+                String line = text.substring(npos, end);
+                
+                Rectangle2D lineRect = metrics.getStringBounds(line, getGraphics());
+                if (lineRect.getWidth() > width) {
+                    width = lineRect.getWidth();
+                }
+                height += lineRect.getHeight();
+                npos = end + lineSep.length();
+            }
+            
+            return new Dimension((int) width + 1, (int) height);
+        }
+    }
+    
+    /**
+     * Get the preferred size, given that a particular wrapping width is desired.
+     */
+    private Dimension getPreferredSizeWrapped()
+    {
+        Graphics ng = getGraphics();
+        
+        int myWidth = wrapWidth;
+        
+        FontMetrics metrics = getFontMetrics(getFont());
+        int npos = 0;
+        int currentY = 0;
+        while (npos < text.length()) {
+            int end = text.indexOf(lineSep, npos);
+            if (end == -1) {
+                end = text.length();
+            }
+            String line = text.substring(npos, end);
+            
+            Rectangle2D lineRect = metrics.getStringBounds(line, ng);
+            int lineAmount;
+            int lineHeight = (int) lineRect.getHeight();
+            if (lineRect.getWidth() > myWidth) {
+                int lbound = 0;
+                int hbound = line.length();
+                int lboundw = 0;
+                int hboundw = (int) lineRect.getWidth();
+                
+                // Perform an intelligent binary search to find how much of the line
+                // can actually fit in the current width
+                while (hbound - lbound > 1) {
+                    int middle = lbound + (hbound - lbound) * (hboundw - lboundw) / (myWidth - lboundw);
+                    if (middle <= lbound) {
+                        middle = lbound + 1;
+                    }
+                    if (middle >= hbound) {
+                        middle = hbound - 1;
+                    }
+                    
+                    lineRect = metrics.getStringBounds(line, 0, middle, ng);
+                    int middlew = (int) lineRect.getWidth();
+                    if (middlew > myWidth) {
+                        hbound = middle;
+                        hboundw = middlew;
+                    }
+                    else {
+                        lbound = middle;
+                        lboundw = middlew;
+                        lineHeight = (int) lineRect.getHeight();
+                    }
+                }
+
+                lineAmount = lbound;
+
+                // Wrap words at word boundaries...
+                int priorSpace = line.indexOf(' ', 1);
+                while (priorSpace != -1 && priorSpace <= lbound) {
+                    lineAmount = priorSpace - 1;
+                    priorSpace = line.indexOf(' ', priorSpace + 1);
+                }
+                
+                if (lineAmount <= 0) {
+                    lineAmount = 1;
+                }
+            }
+            else {
+                lineAmount = line.length();
+            }
+            
+            currentY += lineHeight;
+            if (lineAmount < line.length()) {
+                npos += lineAmount;
+                if (text.charAt(npos) == ' ') {
+                    npos++;
+                }
+            }
+            else {
+                npos = end + lineSep.length();
+            }
+        }
+        
+        return new Dimension(wrapWidth, currentY);
+    }
+    
+    /* (non-Javadoc)
+     * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
+     */
+    protected void paintComponent(Graphics g)
+    {
+        Graphics ng = g.create();
+        ng.setPaintMode();
+        
+        int myWidth = getWidth();
+        
+        if (isOpaque()) {
+            ng.setColor(getBackground());
+            ng.fillRect(0, 0, myWidth, getHeight());
+        }
+
+        if (wrapWidth != -1 && wrapWidth < myWidth) {
+            myWidth = wrapWidth;
+        }
+        
+        ng.setFont(getFont());
+        FontMetrics metrics = getFontMetrics(getFont());
+        int npos = 0;
+        int currentX = 0;
+        int currentY = 0;
+        while (npos < text.length()) {
+            int end = text.indexOf(lineSep, npos);
+            if (end == -1) {
+                end = text.length();
+            }
+            String line = text.substring(npos, end);
+            
+            Rectangle2D lineRect = metrics.getStringBounds(line, ng);
+            int lineAmount;
+            int lineHeight = (int) lineRect.getHeight();
+            if (lineRect.getWidth() > myWidth) {
+                int lbound = 0;
+                int hbound = line.length();
+                int lboundw = 0;
+                int hboundw = (int) lineRect.getWidth();
+                
+                // Perform an intelligent binary search to find how much of the line
+                // can actually fit in the current width
+                while (hbound - lbound > 1) {
+                    int middle = lbound + (hbound - lbound) * (hboundw - lboundw) / (myWidth - lboundw);
+                    if (middle <= lbound) {
+                        middle = lbound + 1;
+                    }
+                    if (middle >= hbound) {
+                        middle = hbound - 1;
+                    }
+                    
+                    lineRect = metrics.getStringBounds(line, 0, middle, ng);
+                    int middlew = (int) lineRect.getWidth();
+                    if (middlew > myWidth) {
+                        hbound = middle;
+                        hboundw = middlew;
+                    }
+                    else {
+                        lbound = middle;
+                        lboundw = middlew;
+                        lineHeight = (int) lineRect.getHeight();
+                    }
+                }
+                
+                lineAmount = lbound;
+                
+                // Wrap words at word boundaries...
+                int priorSpace = line.indexOf(' ', 1);
+                while (priorSpace != -1 && priorSpace <= lbound) {
+                    lineAmount = priorSpace;
+                    priorSpace = line.indexOf(' ', priorSpace + 1);
+                }
+                
+                if (lineAmount == 0) {
+                    lineAmount = 1;
+                }
+            }
+            else {
+                lineAmount = line.length();
+            }
+            
+            float ascent = metrics.getLineMetrics(line, 0, lineAmount, ng).getAscent();
+            ng.drawString(line.substring(0, lineAmount), currentX, (int)(currentY + ascent));
+            currentY += lineHeight;
+            if (lineAmount < line.length()) {
+                npos += lineAmount;
+                if (text.charAt(npos) == ' ') {
+                    npos++;
+                }
+            }
+            else {
+                npos = end + lineSep.length();
+            }
+        }
+        
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/OvalIcon.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/OvalIcon.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ceccfd7c04448a05d2b47689787ed150d69cd75
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/OvalIcon.java
@@ -0,0 +1,70 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * Return a filled oval as an Icon
+ *
+ * @author  Andrew Patterson
+ * @cvs     $Id: OvalIcon.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class OvalIcon implements Icon
+{
+    private static OvalIcon redIcon = new OvalIcon(Color.red);
+    private static OvalIcon blankIcon = new OvalIcon(null);
+
+    public static OvalIcon getRedOvalIcon()
+    {
+        return redIcon;        
+    }
+
+    public static OvalIcon getBlankOvalIcon()
+    {
+        return blankIcon;
+    }
+
+    private Color color;
+
+    public OvalIcon (Color c) {
+       color = c;
+    }
+
+    public void paintIcon (Component c, Graphics g, int x, int y)
+    {
+  if(color != null) {
+  int width = getIconWidth();
+  int height = getIconHeight();
+   g.setColor (color);
+  g.fillOval (x, y, width, height);
+  }
+}
+public int getIconWidth() {
+  return 10;
+}
+public int getIconHeight() { 
+  return 10;
+}
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/PackageChooser.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/PackageChooser.java
new file mode 100644
index 0000000000000000000000000000000000000000..c86767d1149a274022a456add0ceb83cae924795
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/PackageChooser.java
@@ -0,0 +1,275 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.Icon;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.plaf.FileChooserUI;
+import javax.swing.plaf.basic.BasicFileChooserUI;
+
+import bluej.Config;
+import bluej.pkgmgr.Package;
+import bluej.utility.filefilter.DirectoryFilter;
+import bluej.utility.filefilter.JavaSourceFilter;
+
+/**
+ * A file chooser for opening packages.
+ *
+ * Extends the behaviour of JFileChooser in the following ways:
+ * 
+ * <ul>
+ * <li>Only directories (either BlueJ packages or plain ones) are displayed.
+ * <li>BlueJ packages are displayed with a different icon.
+ * </ul>
+ *
+ * @author  Michael Kolling
+ * @author  Axel Schmolitzky
+ * @author  Markus Ostman
+ */
+class PackageChooser extends JFileChooser
+{
+    static private final Icon classIcon = Config.getFixedImageAsIcon("class-icon.png");
+    static private final Icon packageIcon = Config.getFixedImageAsIcon("package-icon.png");
+
+    static private final String previewLine1 = Config.getString("utility.packageChooser.previewPane1");
+    static private final String previewLine2 = Config.getString("utility.packageChooser.previewPane2");
+
+    private PackageDisplay displayPanel;
+    private boolean allowNewFiles = true;
+
+    /**
+     * Create a new PackageChooser.
+     * 
+     * @param startDirectory 	the directory to start the package selection in.
+     * @param preview           whether to show the package structure preview pane
+     * @param showArchives      whether to allow choosing jar and zip files
+     */
+    public PackageChooser(File startDirectory, boolean preview, boolean showArchives)
+    {
+        super(startDirectory);
+
+        if (showArchives) {
+            setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+        }
+        else {
+            setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+        }
+        setFileView(new PackageFileView());
+        
+        if (preview) {
+            displayPanel = new PackageDisplay(startDirectory);
+
+            setAccessory(displayPanel);
+
+            addPropertyChangeListener(new PropertyChangeListener() {
+                public void propertyChange(PropertyChangeEvent e) {
+                    if (!(e.getNewValue() instanceof File)) {
+                        return;
+                    }
+                    File dir = (File)e.getNewValue();
+                    if (dir == null) {
+                        return;
+                    }
+                    if (dir.getName().equals("")) {
+                        return;
+                    }
+
+                    displayPanel.setDisplayDirectory(dir.getAbsoluteFile());
+
+                    // if (e.getPropertyName().equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) { }
+                    // if (e.getPropertyName().equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) { }
+                }
+            });
+        }
+    }
+    
+    /**
+     * Set whether this chooser should allow new (non-existing) files to
+     * be selected. This does not actually prevent the user from specifying
+     * a non-existing file, it just tweaks UI behaviour a bit.
+     */
+    public void setAllowNewFiles(boolean allowNewFiles)
+    {
+        this.allowNewFiles = allowNewFiles;
+    }
+    
+    /* (non-Javadoc)
+     * @see javax.swing.JFileChooser#accept(java.io.File)
+     */
+    public boolean accept(File f)
+    {
+        if (f.isDirectory())
+            return true;
+        
+        String fname = f.getName();
+        return fname.endsWith(".jar") || fname.endsWith(".JAR") ||
+                fname.endsWith(".zip") || fname.endsWith(".ZIP")
+                || (Config.isGreenfoot() && (fname.endsWith(".gfar") || fname.endsWith(".GFAR") || 
+                        fname.endsWith(".sb")));
+    }
+
+    /**
+     *  A directory was double-clicked. If this is a BlueJ package, consider
+     *  this a package selection and accept it as the "Open" action, otherwise
+     *  just traverse into the directory.
+     */
+    public void setCurrentDirectory(File dir)   // redefined
+    {
+        if (Package.isPackage(dir)) {
+            setSelectedFile(dir);
+            super.approveSelection();
+        }
+        else{
+            super.setCurrentDirectory(dir);
+            if (allowNewFiles) {
+                // Hack to make file chooser behave slightly nicer. The default behaviour is to put
+                // the directory name, without a trailing slash, in the filename field.
+                // See ticket #127
+                FileChooserUI ui = getUI();
+                if (ui instanceof BasicFileChooserUI) {
+                    BasicFileChooserUI mui = (BasicFileChooserUI) ui;
+                    mui.setFileName("");
+                }
+            }
+        }
+    }
+    
+    /**
+     * Approve the selection. We have this mainly so that derived classes
+     * can call it...
+     */
+    protected void approved()
+    {
+        super.approveSelection();
+    }
+    
+    class PackageDisplay extends JList
+    {
+        // number of lines at the top to display a header
+        // explaining what the PackageDisplay is
+        final int headerLines = 3;
+
+        // index of the last class displayed (after this all list items are packages
+        // and hence will have a different icon)
+        int lastClass = 0;
+
+        PackageDisplay(File displayDir)
+        {
+            this.setPreferredSize(new Dimension(150,200));
+            this.setCellRenderer(new MyListRenderer());
+
+            setDisplayDirectory(displayDir);
+        }
+
+        @Override
+        protected void processMouseEvent(MouseEvent e) { }
+        @Override
+        protected void processMouseMotionEvent(MouseEvent e) { }
+
+        void setDisplayDirectory(File displayDir)
+        {
+            if (displayDir == null)
+                return;
+
+            int maxDisplay = 3;
+            File subDirs[] = displayDir.listFiles(new DirectoryFilter());
+            File srcFiles[] = displayDir.listFiles(new JavaSourceFilter());
+            List<String> listVec = new ArrayList<String>();
+
+            // headerLines is 3
+            listVec.add(previewLine1);
+            listVec.add(previewLine2);
+            listVec.add(" ");
+
+            if(subDirs != null) {
+                for(lastClass=0; lastClass<srcFiles.length && lastClass<maxDisplay; lastClass++) {
+                    String javaFileName =
+                       JavaNames.stripSuffix(srcFiles[lastClass].getName(), ".java");
+
+                    // check if the name would be a valid java name
+                    if (!JavaNames.isIdentifier(javaFileName))
+                        continue;
+
+                    // files with a $ in them signify inner classes (which we want to ignore)
+                    if (javaFileName.indexOf('$') == -1)
+                        listVec.add(javaFileName);
+                }
+            }
+
+            if(srcFiles != null) {
+                for(int i=0; i<subDirs.length && i<maxDisplay; i++) {
+                    // first check if the directory name would be a valid package name
+                    if (!JavaNames.isIdentifier(subDirs[i].getName()))
+                        continue;
+
+                    listVec.add(subDirs[i].getName());
+
+                    // now display sub sub dirs
+                    File subSubDirs[] = subDirs[i].listFiles(new DirectoryFilter());
+
+                    if (subSubDirs != null) {
+                        for(int j=0; j<subSubDirs.length; j++) {
+                            // first check if the directory name would be a valid package name
+                            if (!JavaNames.isIdentifier(subSubDirs[j].getName()))
+                                continue;
+
+                            listVec.add(subDirs[i].getName() + "." + subSubDirs[j].getName());
+                        }
+                    }
+                }
+            }
+
+            setListData(listVec.toArray());
+        }
+
+        class MyListRenderer extends DefaultListCellRenderer
+        {
+            public Component getListCellRendererComponent(JList list, Object value, int index,
+                                                    boolean isSelected, boolean cellHasFocus)
+            {
+                Component s = super.getListCellRendererComponent(list, value, index,
+                                                                    isSelected, cellHasFocus);
+
+                if (index < headerLines)
+                    ;
+                else if ((index-headerLines) < lastClass)
+                    ((JLabel)s).setIcon(classIcon);
+                else
+                    ((JLabel)s).setIcon(packageIcon);
+
+                return s;
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/PackageChooserStrict.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/PackageChooserStrict.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c17324d7fb6bf1b85ff564e24a3abe552ff0522
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/PackageChooserStrict.java
@@ -0,0 +1,72 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import bluej.pkgmgr.Package;
+
+import java.io.File;
+
+/**
+ * A file chooser for opening packages (with strict behaviour with
+ * regards clicking on BlueJ packages).
+ *
+ * <p>Behaves the same as a PackageChooser but with the added restriction
+ * that only BlueJ package directories, and archives, are an acceptable
+ * selection. Double clicking on a BlueJ package will open it rather
+ * than traverse into it.
+ *
+ * @author Michael Kolling
+ * @author Axel Schmolitzky
+ * @author Markus Ostman
+ * @version $Id: PackageChooserStrict.java 6347 2009-05-20 15:22:43Z polle $
+ */
+public class PackageChooserStrict extends PackageChooser
+{
+    /**
+     * Create a new strict PackageChooser.
+     *
+     * @param startDirectory the directory to start the package selection in.
+     */
+    public PackageChooserStrict(File startDirectory)
+    {
+        super(startDirectory, false, true);
+    }
+
+    /**
+     *  Selection approved by button-click. Check whether the selected
+     *  directory is a BlueJ package. If so, let it be opened.
+     */
+    public void approveSelection()   // redefined
+    {
+        File selectedFile = getSelectedFile();
+        if (selectedFile.isFile()) {
+            // it must be an archive (jar or zip)
+            approved();
+        }
+        else if (Package.isPackage(getSelectedFile())) {
+    	    approved();
+        }
+        else {
+            super.setCurrentDirectory(getSelectedFile());
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/PackageFileView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/PackageFileView.java
new file mode 100644
index 0000000000000000000000000000000000000000..a4175ca1e2326173a02ea3c85849b61284a48b5e
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/PackageFileView.java
@@ -0,0 +1,97 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import bluej.Config;
+import bluej.pkgmgr.Package;
+
+import javax.swing.*;
+import javax.swing.filechooser.*;
+import java.io.File;
+
+/**
+ * A FileView subclass that enables BlueJ packages to be displayed with a
+ * distinct icon in a FileChooser.
+ *
+ * @author Michael Kolling
+ * @see FileUtility
+ * @version $Id: PackageFileView.java 7860 2010-07-15 02:45:20Z davmac $
+ */
+public class PackageFileView extends FileView
+{
+    static final Icon bluejProjectIcon = Config.getFixedImageAsIcon("bluej-project.png");
+    static final Icon greenfootProjectIcon = Config.getFixedImageAsIcon("greenfoot-project.png");
+
+    /**
+     * The name of the file.  Do nothing special here. Let the system file
+     * view handle this. (All methods that return null get then handled by
+     * the system.)
+     */
+    @Override
+    public String getName(File f)
+    {
+        return null;
+    }
+
+    /**
+     * A human readable description of the file.
+     */
+    @Override
+    public String getDescription(File f)
+    {
+        return null;
+    }
+
+    /**
+     * A human readable description of the type of the file.
+     */
+    @Override
+    public String getTypeDescription(File f)
+    {
+        return null;
+    }
+
+    /**
+     * Here we return proper BlueJ package icons for BlueJ packages.
+     * Everything else gets handled by the system (by returning null).
+     */
+    @Override
+    public Icon getIcon(File f)
+    {
+        if (Config.isMacOS() && f.getAbsolutePath().equals("/net")) {
+            // On MacOS this path is a special mapping; looking for a particular
+            // file inside it can cause a significant delay.
+            return null;
+        }
+        
+        if(Package.isPackage(f))
+            if (Config.isGreenfoot()) {
+                return greenfootProjectIcon;
+            }
+            else {
+                return bluejProjectIcon;
+            }
+        else {
+            return null;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/Queue.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/Queue.java
new file mode 100644
index 0000000000000000000000000000000000000000..d5b2f4b5922cb995a6d7e9e2b68c91e0ad59925f
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/Queue.java
@@ -0,0 +1,84 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+/**
+ ** General purpose Queue class
+ **
+ ** $Id: Queue.java 6215 2009-03-30 13:28:25Z polle $
+ **/
+
+public class Queue
+{
+    private Elem head;
+    private Elem tail;
+	
+    public Queue()
+    {
+	head = null;
+	tail = null;
+    }
+	
+    public synchronized void enqueue(Object data)
+    {
+	if(tail == null)
+	    head = tail = new Elem(data);
+	else
+	    {
+		tail.next = new Elem(data);
+		tail = tail.next;
+	    }
+    }
+	
+    public synchronized Object dequeue()
+    {
+	Object ret = null;
+		
+	if(head != null)
+	    {
+		ret = head.data;
+		head = head.next;
+		if(head == null)
+		    tail = null;
+	    }
+		
+	return ret;
+    }
+	
+    public synchronized boolean isEmpty()
+    {
+	return tail == null;
+    }
+	
+    class Elem
+    {
+	Object data;
+	Elem next;
+	
+	Elem(Object data)
+	{
+	    this.data = data;
+	    this.next = null;
+	}
+    }
+}
+
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/SortedProperties.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/SortedProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..d36416b4424764f749af3d9647ec122e45cc7e43
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/SortedProperties.java
@@ -0,0 +1,131 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * A properties object which outputs its entries in sorted order
+ * (allowing the resulting files to exist in CVS repositories without
+ *  so much clashing)
+ *
+ * @author  Andrew Patterson
+ */
+public class SortedProperties extends Properties
+{
+    private static final String specialSaveChars = "=: \t\r\n\f#!";
+
+    /**
+     * Converts unicodes to encoded \\uxxxx
+     * and writes out any of the characters in specialSaveChars
+     * with a preceding slash
+     */
+    private String saveConvert(String theString)
+    {
+        char aChar;
+        int len = theString.length();
+        StringBuffer outBuffer = new StringBuffer(len*2);
+
+        for(int x=0; x<len; ) {
+            aChar = theString.charAt(x++);
+            switch(aChar) {
+            case '\\':
+                outBuffer.append('\\'); outBuffer.append('\\');
+                continue;
+            case '\t':
+                outBuffer.append('\\'); outBuffer.append('t');
+                continue;
+            case '\n':
+                outBuffer.append('\\'); outBuffer.append('n');
+                continue;
+            case '\r':
+                outBuffer.append('\\'); outBuffer.append('r');
+                continue;
+            case '\f':
+                outBuffer.append('\\'); outBuffer.append('f');
+                continue;
+            default:
+                if ((aChar < 20) || (aChar > 127)) {
+                    outBuffer.append('\\');
+                    outBuffer.append('u');
+                    outBuffer.append(toHex((aChar >> 12) & 0xF));
+                    outBuffer.append(toHex((aChar >> 8) & 0xF));
+                    outBuffer.append(toHex((aChar >> 4) & 0xF));
+                    outBuffer.append(toHex((aChar >> 0) & 0xF));
+                }
+                else {
+                    if (specialSaveChars.indexOf(aChar) != -1) {
+                        outBuffer.append('\\');
+                    }
+                    outBuffer.append(aChar);
+                }
+            }
+
+        }
+        return outBuffer.toString();
+    }
+
+    /**
+     * Convert a nibble to a hex character
+     * @param   nibble  the nibble to convert.
+     */
+    private static char toHex(int nibble)
+    {
+        return hexDigit[(nibble & 0xF)];
+    }
+
+    /** A table of hex digits */
+    private static final char[] hexDigit = {
+        '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+    };
+
+    @SuppressWarnings("unchecked")
+    public void store(OutputStream out, String header) throws IOException
+    {
+        BufferedWriter awriter;
+        awriter = new BufferedWriter(new OutputStreamWriter(out, "8859_1"));
+        if (header != null) {
+            awriter.write("#" + header);
+            awriter.newLine();
+        }
+
+        // Properties maps String to String, but unfortunately doesn't implement
+        // Map<String,String> - so we need to use the raw TreeMap constructor.
+        @SuppressWarnings("rawtypes")
+        TreeMap<String,String> tm = new TreeMap(this);
+
+        Iterator<Map.Entry<String,String>> it = tm.entrySet().iterator();
+
+        while(it.hasNext())
+        {
+            Map.Entry<String,String> mapEntry = it.next();
+
+            String key = saveConvert(mapEntry.getKey());
+            String val = saveConvert(mapEntry.getValue());
+
+            awriter.write(key + "=" + val);
+            awriter.newLine();
+        }
+        awriter.flush();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/SwingWorker.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/SwingWorker.java
new file mode 100644
index 0000000000000000000000000000000000000000..c504516875a50990bff20c3e2f6020a314df8bdb
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/SwingWorker.java
@@ -0,0 +1,152 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import javax.swing.SwingUtilities;
+
+/**
+ * This is the 3rd version of SwingWorker (also known as
+ * SwingWorker 3), an abstract class that you subclass to
+ * perform GUI-related work in a dedicated thread.  For
+ * instructions on and examples of using this class, see:
+ * 
+ * http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
+ *
+ * Note that the API changed slightly in the 3rd version:
+ * You must now invoke start() on the SwingWorker after
+ * creating it.
+ */
+public abstract class SwingWorker {
+    private Object value;  // see getValue(), setValue()
+
+    /** 
+     * Class to maintain reference to current worker thread
+     * under separate synchronization control.
+     */
+    private static class ThreadVar {
+        private Thread thread;
+        ThreadVar(Thread t) { thread = t; }
+        synchronized Thread get() { return thread; }
+        synchronized void clear() { thread = null; }
+    }
+
+    private ThreadVar threadVar;
+
+    /** 
+     * Get the value produced by the worker thread, or null if it 
+     * hasn't been constructed yet.
+     */
+    protected synchronized Object getValue() { 
+        return value; 
+    }
+
+    /** 
+     * Set the value produced by worker thread 
+     */
+    private synchronized void setValue(Object x) { 
+        value = x; 
+    }
+
+    /** 
+     * Compute the value to be returned by the <code>get</code> method. 
+     */
+    public abstract Object construct();
+
+    /**
+     * Called on the event dispatching thread (not on the worker thread)
+     * after the <code>construct</code> method has returned.
+     */
+    public void finished() {
+    }
+
+    /**
+     * A new method that interrupts the worker thread.  Call this method
+     * to force the worker to stop what it's doing.
+     */
+    public void interrupt() {
+        Thread t = threadVar.get();
+        if (t != null) {
+            t.interrupt();
+        }
+        threadVar.clear();
+    }
+
+    /**
+     * Return the value created by the <code>construct</code> method.  
+     * Returns null if either the constructing thread or the current
+     * thread was interrupted before a value was produced.
+     * 
+     * @return the value created by the <code>construct</code> method
+     */
+    public Object get() {
+        while (true) {  
+            Thread t = threadVar.get();
+            if (t == null) {
+                return getValue();
+            }
+            try {
+                t.join();
+            }
+            catch (InterruptedException e) {
+                Thread.currentThread().interrupt(); // propagate
+                return null;
+            }
+        }
+    }
+
+
+    /**
+     * Start a thread that will call the <code>construct</code> method
+     * and then exit.
+     */
+    public SwingWorker() {
+        final Runnable doFinished = new Runnable() {
+           public void run() { finished(); }
+        };
+
+        Runnable doConstruct = new Runnable() { 
+            public void run() {
+                try {
+                    setValue(construct());
+                }
+                finally {
+                    threadVar.clear();
+                }
+
+                SwingUtilities.invokeLater(doFinished);
+            }
+        };
+
+        Thread t = new Thread(doConstruct);
+        threadVar = new ThreadVar(t);
+    }
+
+    /**
+     * Start the worker thread.
+     */
+    public void start() {
+        Thread t = threadVar.get();
+        if (t != null) {
+            t.start();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/Utility.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/Utility.java
new file mode 100644
index 0000000000000000000000000000000000000000..0940976757204b6553c1e9b8f72d7f2e0f58afa2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/Utility.java
@@ -0,0 +1,1106 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011,2012  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility;
+
+import java.awt.Component;
+import java.awt.Desktop;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Shape;
+import java.awt.Window;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.lang.management.ManagementFactory;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+import javax.swing.AbstractButton;
+import javax.swing.border.Border;
+import javax.swing.text.TabExpander;
+
+import com.apple.eawt.Application;
+
+import bluej.Config;
+
+/**
+ * Some generally useful utility methods available to all of bluej.
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ */
+public class Utility
+{
+    /**
+     * Used to track which events have occurred for firstTimeThisRun()
+     */
+    private static Set<String> occurredEvents = new HashSet<String>();
+
+    /**
+     * Draw a thick rectangle - another of the things missing from the AWT
+     */
+    public static void drawThickRect(Graphics g, int x, int y, int width, int height, int thickness)
+    {
+        for (int i = 0; i < thickness; i++)
+            g.drawRect(x + i, y + i, width - 2 * i, height - 2 * i);
+    }
+    
+    /**
+     * Draw a thick rounded rectangle - another of the things missing from the AWT
+     */
+    public static void drawThickRoundRect(Graphics g, int x, int y, int width, int height, int arc, int thickness)
+    {
+        for (int i = 0; i < thickness; i++)
+            g.drawRoundRect(x + i, y + i, width - 2 * i, height - 2 * i, arc, arc);
+    }
+
+    /**
+     * Draw stripes over a rectangle - yet another thing missing from the AWT
+     */
+    public static void stripeRect(Graphics g, int x, int y, int width, int height, int separation, int thickness)
+    {
+        for (int offset = 0; offset < width + height; offset += separation)
+            for (int i = 0; i < thickness; i++, offset++) {
+                int x1, y1, x2, y2;
+
+                if (offset < height) {
+                    x1 = x;
+                    y1 = y + offset;
+                }
+                else {
+                    x1 = x + offset - height;
+                    y1 = y + height;
+                }
+
+                if (offset < width) {
+                    x2 = x + offset;
+                    y2 = y;
+                }
+                else {
+                    x2 = x + width;
+                    y2 = y + offset - width;
+                }
+
+                g.drawLine(x1, y1, x2, y2);
+            }
+    }
+
+    /**
+     * Draw a string at a given location on screen centered in a given
+     * rectangle.<br>
+     * Left justifies the string if it is too long to fit all of the string
+     * inside the rectangle.
+     */
+    public static void drawCentredText(Graphics g, String str, int x, int y, int width, int height)
+    {
+        FontMetrics fm = g.getFontMetrics();
+
+        Shape oldClip = g.getClip();
+        g.clipRect(x, y, width, height);
+        int xOffset = (width - fm.stringWidth(str)) / 2;
+        if (xOffset < 0) {
+            xOffset = 0;
+        }
+        // This is the space left around the text, divided by 2 (equal gap above and below)
+        // to get the top of the text, plus the ascent to get the baseline 
+        int yOffset = fm.getAscent() + ((height - fm.getAscent() - fm.getDescent()) / 2);
+        g.drawString(str, x + xOffset, y + yOffset);
+        g.setClip(oldClip);
+    }
+
+    /**
+     * Draw a string at a given location on screen right-aligned in a given
+     * rectangle.
+     */
+    public static void drawRightText(Graphics g, String str, int x, int y, int width, int height)
+    {
+        FontMetrics fm = g.getFontMetrics();
+
+        Shape oldClip = g.getClip();
+        g.clipRect(x, y, width, height);
+        g.drawString(str, x + width - fm.stringWidth(str), y + (height + fm.getAscent()) / 2);
+        g.setClip(oldClip);
+    }
+
+    /**
+     * Splits "string" by "Delimiter"
+     * 
+     * @param str - the string to be split
+     * @param delimiter - the field delimiter within str
+     * @returns an array of Strings
+     */
+    public static String[] split(String str, String delimiter)
+    {
+        List<String> strings = new ArrayList<String>();
+        int start = 0;
+        int len = str.length();
+        int dlen = delimiter.length();
+        int offset = str.lastIndexOf(delimiter); // First of all, find the
+        // Last occurance of the Delimiter
+        // Stop empty delimiters
+        if (dlen < 1)
+            return null;
+        else if (offset < 0) // one element
+        {
+            String[] result = {str};
+            return result;
+        }
+
+        //
+        // Append the delimiter onto the end if it doesn't already exit
+        //
+        if (len > offset + dlen) {
+            str += delimiter;
+            len += dlen;
+        }
+
+        do {
+            // Get the new Offset
+            offset = str.indexOf(delimiter, start);
+            strings.add(str.substring(start, offset));
+
+            // Get the new Start position
+            start = offset + dlen;
+        } while ((start < len) && (offset != -1));
+
+        // Convert the list into an Array of Strings
+        String result[] = new String[strings.size()];
+        strings.toArray(result);
+        return result;
+    }
+
+    /**
+     * Splits "string" into lines (stripping end-of-line characters)
+     * 
+     * @param str - the string to be split
+     * @returns an array of Strings
+     */
+    public static String[] splitLines(String str)
+    {
+        return (str == null ? null : split(str, "\n"));
+    }
+
+    /**
+     * Return a string in which all the quotable characters (tab, newline, ' and ",
+     * etc) are quoted, Java-style.
+     */
+    public static String quoteString(String src)
+    {
+        StringBuffer buf = new StringBuffer();
+
+        for (int i = 0; i < src.length(); i++) {
+            char c = src.charAt(i);
+            if (c == '\n')
+                buf.append("\\n");
+            else if (c == '\r')
+                buf.append("\\r");
+            else if (c == '\t')
+                buf.append("\\g");
+            else if (c < 32 || c > 128) {
+                // Character is outside normal ASCII range, output it as unicode
+                // escape sequence.
+                String n = Integer.toHexString(c);
+                n = "0000".substring(n.length()) + n;
+                buf.append("\\u");
+                buf.append(n);
+            }
+            else {
+                if (c == '\\' || c == '"' || c == '\'')
+                    buf.append('\\');
+                buf.append(src.charAt(i));
+            }
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * Translate a given, qualified class name into a URL where we believe its
+     * documentation to be, and display that URL in a web browser.
+     */
+    public static void showClassDocumentation(String classname, String suffix)
+    {
+        classname = classname.replace('.', '/');
+        String docURL = Config.getPropString("bluej.url.javaStdLib");
+        if (docURL.endsWith(".html")) {
+            int lastSlash = docURL.lastIndexOf('/');
+            if (lastSlash != -1)
+                docURL = docURL.substring(0, lastSlash + 1);
+        }
+        // Debug.message(docURL + classname + ".html" + suffix);
+        openWebBrowser(docURL + classname + ".html" + suffix);
+    }
+
+    /**
+     * Let the given URL be shown in a browser window.
+     * 
+     * @param url the URL or file path to be shown.
+     * @return true if the web browser could be started, false otherwise.
+     */
+    public static boolean openWebBrowser(String url)
+    {
+        if (Config.isWinOS()) { // Windows
+
+            String cmd;
+            // catering for stupid differences in Windows shells...
+            if (Config.osname.startsWith("Windows 9") || Config.osname.equals("Windows Me")) // win95/98/Me
+                cmd = "command.com";
+            else
+                // other
+                cmd = "cmd.exe";
+
+            try {
+                // more stupid Windows differences...
+                if (Config.osname.startsWith("Windows 98") || Config.osname.equals("Windows Me")) {
+                    Runtime.getRuntime().exec(new String[]{cmd, "/c", "start", '"' + url + '"'});
+                }
+                else {
+                    Runtime.getRuntime().exec(new String[]{cmd, "/c", "start", "\"\"", '"' + url + '"'});
+                }
+            }
+            catch (IOException e) {
+                Debug.reportError("could not start web browser. exc: " + e);
+                return false;
+            }
+        }
+        else { // Mac, Unix and other
+
+            // The string should be either a URL or a file path
+            try {
+                return openWebBrowser(new URL(url));
+            }
+            catch (MalformedURLException mfue) {
+                return openWebBrowser(new File(url));
+            }
+
+        }
+        return true;
+    }
+
+    /**
+     * Let the given URL be shown in a browser window.
+     * 
+     * @param url the URL to be shown.
+     * @return true if the web browser could be started, false otherwise.
+     */
+    public static boolean openWebBrowser(URL url)
+    {
+        if (Config.isWinOS()) {
+            // Windows
+            return openWebBrowser(url.toString());
+        }
+        else {
+            Exception exception = null;
+            
+            if (Desktop.isDesktopSupported()) {
+                try {
+                    Desktop.getDesktop().browse(url.toURI());
+                }
+                catch (IOException ioe) { exception = ioe; }
+                catch (URISyntaxException use) { exception = use; }
+            }
+            
+            if (exception == null) {
+                return true; // success
+            }
+            
+            if (Config.isMacOS()) {
+                Debug.reportError("could not start web browser. exc: " + exception);
+                return false;
+            }
+            
+            // Unix and other
+
+            String cmd = mergeStrings(Config.getPropString("browserCmd1"), url.toString());
+            String cmd2 = mergeStrings(Config.getPropString("browserCmd2"), url.toString());
+
+            Process p = null;
+            try {
+                p = Runtime.getRuntime().exec(cmd);
+            }
+            catch (IOException e) {
+                try {
+                    p = Runtime.getRuntime().exec(cmd2);
+                    cmd2 = null;
+                }
+                catch (IOException e2) {
+                    Debug.reportError("could not start web browser.  exc: " + e);
+                    return false;
+                }
+            }
+
+            final String command2 = cmd2;
+            final Process process = p;
+            new Thread() {
+                public void run()
+                {
+                    runUnixWebBrowser(process, command2);
+                }
+            }.start();
+        }
+        return true;
+    }
+
+    /**
+     * Wait for the given process to finish, try running the second command if
+     * it returns false.
+     * 
+     * @param p
+     * @param url
+     * @param cmd2
+     */
+    private static void runUnixWebBrowser(Process p, String cmd2)
+    {
+        try {
+            // wait for exit code. 0 indicates success, otherwise
+            // we try second command
+            int exitCode = p.waitFor();
+
+            if (exitCode != 0 && cmd2 != null && cmd2.length() > 0) {
+                p = Runtime.getRuntime().exec(cmd2);
+            }
+        }
+        catch (InterruptedException ie) {
+            Debug.reportError("cannot start web browser:");
+            Debug.reportError("caught exc " + ie);
+        }
+        catch (IOException ioe) {
+            Debug.reportError("cannot start web browser:");
+            Debug.reportError("caught exc " + ioe);
+        }
+    }
+
+    /**
+     * Let the given file be shown in a browser window.
+     * 
+     * @param file the file to be shown.
+     * @return true if the web browser could be started, false otherwise.
+     */
+    public static boolean openWebBrowser(File file)
+    {
+        if (Config.isWinOS()) { // Windows
+            return openWebBrowser(file.toString());
+        }
+        else { // Mac, Unix and other
+            try {
+                return openWebBrowser(file.toURI().toURL());
+            }
+            catch (MalformedURLException mfue) {
+                // This shouldn't happen.
+                return false;
+            }
+        }
+    }
+    
+    /**
+     * Method copied from Boot since we don't always have access to Boot here (if this method is called from the user VM for instance).
+     * 
+     * Calculate the bluejLibDir value by doing some reasoning on a resource 
+     * we know we have: the .class file for the Utility class.
+     *
+     * @return    the path of the BlueJ lib directory
+     */
+    private static File calculateBluejLibDir()
+    {
+        File bluejDir = null;
+        String bootFullName = Utility.class.getResource("Utility.class").toString();
+
+        try {
+            if (! bootFullName.startsWith("jar:")) {
+                // Boot.class is not in a jar-file. Find a lib directory somewhere
+                // above us to use
+                File startingDir = (new File(new URI(bootFullName)).getParentFile());
+                while((startingDir != null) &&
+                        !(new File(startingDir.getParentFile(), "lib").isDirectory())) {
+                    startingDir = startingDir.getParentFile();
+                }
+                
+                if (startingDir == null) {
+                    bluejDir = null;
+                }
+                else {
+                    bluejDir = new File(startingDir.getParentFile(), "lib");
+                }
+            }
+            else {
+                // The class is in a jar file, '!' separates the jar file name
+                // from the class name. Cut off the class name and the "jar:" prefix.
+                int classIndex = bootFullName.indexOf("!");
+                String bootName = bootFullName.substring(4, classIndex);
+                
+                File finalFile = new File(new URI(bootName));
+                bluejDir = finalFile.getParentFile();
+            }   
+        } 
+        catch (URISyntaxException use) { }
+        
+        return bluejDir;
+    }
+    
+    
+    /**
+     * Bring the current process to the front in the OS window stacking order.
+     * The given window will be brought to the front.
+     * 
+     * <p>This method can be called from the debug VM.
+     * 
+     * @param window   the window to be brought to the front. If null, the process
+     *                 is brought to the front.
+     */
+    public static void bringToFront(final Window window)
+    {
+        // If not showing at all we return now.
+        if (window != null) {
+            if (!window.isShowing() || !window.getFocusableWindowState()) {
+                return;
+            }
+            window.toFront();
+        }
+        
+        if (Config.isMacOS()) {
+            Application.getApplication().requestForeground(false);
+            return;
+        }
+
+        String pid = getProcessId();
+        boolean isWindows = Config.isWinOS();
+
+        if (isWindows) {
+            // Use WSH (Windows Script Host) to execute a javascript that brings
+            // a window to front.
+            File libdir = calculateBluejLibDir();
+            String[] command = new String[] {"cscript","\"" + libdir.getAbsolutePath() + "\\windowtofront.js\"",pid };
+            
+            final StringBuffer commandAsStr = new StringBuffer();
+            for (int i = 0; i < command.length; i++) {
+                commandAsStr.append(command[i] + " ");
+            }
+
+            try {
+                Process p = Runtime.getRuntime().exec(command);
+                new ExternalProcessLogger(command[0], commandAsStr.toString(), p).start();
+                if (isWindows) {
+                    // An apparent JDK bug causes us to lose the ability to receive
+                    // input if the script is executed while a popup window is showing.
+                    // In an attempt to avoid that we'll wait for the script to execute
+                    // now:
+                    new ProcessWaiter(p).waitForProcess(500);
+                }
+            }
+            catch (IOException e) {
+                Debug.reportError("While trying to launch \"" + command + "\", got this IOException:", e);
+            }
+            catch (InterruptedException ie) {}
+        }
+    }
+
+    private static class ExternalProcessLogger extends Thread
+    {
+        String commandAsStr;
+        String processName; 
+        Process p;
+        
+        public ExternalProcessLogger(String processName, String command, Process process)
+        {
+            this.processName = processName;
+            commandAsStr = command;
+            p = process;
+        }
+        
+        @Override
+        public void run()
+        {
+            BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
+            StringBuffer extra = new StringBuffer();
+
+            try {
+                char[] buf = new char[1024];
+                Thread.sleep(1000);
+
+                // discontinue if no data available or stream closed
+                if (br.ready()) {
+                    int len = br.read(buf);
+                    if (len != -1) {
+                        extra.append(buf, 0, len);
+                    }
+                }
+                
+                if (extra.length() != 0) {
+                    Debug.message("When trying to launch " + processName + ":" + commandAsStr);
+                    Debug.message(" This error was recieved: " + extra);
+                }
+            }
+            catch (InterruptedException ie) {}
+            catch (IOException ioe) {}
+            finally {
+                try {
+                    br.close();
+                }
+                catch (IOException ioe) {}
+            }
+        }
+    }
+    
+    /**
+     * A utility class to wait for an external process to complete.
+     * This allows waiting with a timeout, unlike the Process.waitFor()
+     * method. Simply create a ProcessWaiter, and then call {@code wait()}
+     * or {@code wait(long)} on the ProcessWaiter.
+     */
+    private static class ProcessWaiter
+    {
+        boolean complete = false;
+        
+        public ProcessWaiter(final Process p)
+        {
+            new Thread() {
+                public void run() {
+                    try {
+                        p.waitFor();
+                    }
+                    catch (InterruptedException ie) {}
+                    synchronized (ProcessWaiter.this) {
+                        complete = true;
+                        ProcessWaiter.this.notify();
+                    }
+                };
+            }.start();
+        }
+        
+        /**
+         * Wait for the process to complete, with the given timeout.
+         * If the timeout is 0, wait indefinitely.
+         */
+        public synchronized void waitForProcess(long timeout)
+            throws InterruptedException
+        {
+            while (! complete) {
+                wait(timeout);
+            }
+        }
+    }
+    
+    
+    /**
+     * Get the process ID of this process.
+     */
+    public static String getProcessId()
+    {
+        String pid = ManagementFactory.getRuntimeMXBean().getName();
+        // Strip the host name from the pid.
+        int atIndex = pid.indexOf("@");
+        if (atIndex != -1) {
+            pid = pid.substring(0, atIndex);
+        }
+        return pid;
+    }
+
+   
+    /**
+     * merge s2 into s1 at position of first '$'
+     */
+    public static String mergeStrings(String s1, String s2)
+    {
+        int pos = s1.indexOf('$');
+        if (pos == -1)
+            return s1;
+        else
+            return s1.substring(0, pos) + s2 + s1.substring(pos + 1);
+    }
+
+    /**
+     * merge strings in s2 into s1 at positions of '$'
+     */
+    public static String mergeStrings(String s1, String s2[])
+    {
+        for (int current = 0; current < s2.length; current++) {
+            s1 = mergeStrings(s1, s2[current]);
+        }
+
+        return s1;
+    }
+
+    /**
+     * Converts tabs in a String into a specified number of spaces. It assumes
+     * that beginning of String is the starting point of tab offsets.
+     * 
+     * @param original the String to convert
+     * @param tabSize number of spaces to be inserted in place of tab
+     * @return the String with spaces replacing tabs (if tabs present).
+     */
+    public static String convertTabsToSpaces(String originalString, int tabSize)
+    {
+        // if there are tab(s) in the String
+        if (originalString.indexOf('\t') != -1) {
+            StringBuffer buffer = new StringBuffer(originalString);
+            for (int i = 0; i < buffer.length(); i++) {
+                if (buffer.charAt(i) == '\t') {
+                    buffer.deleteCharAt(i);
+                    // calculate how many spaces to add
+                    int numberOfSpaces = tabSize - (i % tabSize);
+                    for (int j = 0; j < numberOfSpaces; j++)
+                        buffer.insert(i, ' ');
+                }
+            }
+            return buffer.toString();
+        }
+        else
+            return originalString;
+    }
+    
+    /**
+     * Calculates how many spaces each tab in the given string turns into.
+     * 
+     * If there is a tab at character index N, the array entry N in the
+     * returned array will indicate how many spaces the tab converts into.
+     * The value of all other entries is undefined.
+     */
+    public static int[] calculateTabSpaces(String line, int tabSize)
+    {
+        // Bigger array than necessary, but we're only doing one line at a time:
+        int[] tabSpaces = new int[line.length()];
+        int curPos = 0;
+        for (int i = 0; i < line.length(); i++) {
+            if (line.charAt(i) == '\t') {
+                // calculate how many spaces to add
+                int numberOfSpaces = tabSize - (curPos % tabSize);
+                tabSpaces[i] = numberOfSpaces;
+                curPos += numberOfSpaces;
+            }
+            else {
+                curPos += 1;
+            }
+        }
+        return tabSpaces;
+    }
+    
+    /**
+     * Makes a TabExpander object that will turn tabs into the appropriate
+     * white-space, based on the original String.  This means that the tabs
+     * will get aligned to the correct tab-stops rather than just being
+     * converted into a set number of spaces.  Thus, the TabExpander will match
+     * the behaviour of the editor.
+     */
+    public static TabExpander makeTabExpander(String line, int tabSize, final FontMetrics fontMetrics)
+    {
+        final int[] tabSpaces = Utility.calculateTabSpaces(line, tabSize);
+        
+        return new TabExpander() {
+            @Override
+            public float nextTabStop(float x, int tabOffset) {
+                return x + tabSpaces[tabOffset] * fontMetrics.charWidth(' ');
+            }
+        };
+    }
+    
+    /**
+     * Given a String and an index into it, along with the pre-calculated tabSpaces array,
+     * advances the index by the given number of character widths.
+     * 
+     * If the String contains to tabs, this effectively adds advanceBy to index.
+     * 
+     * If the String does contain tabs, their width is taken into account
+     * as the index is advanced through the array.
+     * 
+     */
+    public static int advanceChars(String line, int[] tabSpaces, int index, int advanceBy)
+    {
+        while (advanceBy > 0 && index < line.length())
+        {
+            int width = (line.charAt(index) == '\t') ? tabSpaces[index] : 1;
+            advanceBy -= width;
+            index += 1;
+        }
+        return index;
+    }
+
+    /**
+     * Check if this is the first time a particular event (identified by the
+     * context string) has occurred during this run of BlueJ.
+     * 
+     * @param context Identifies the event (suggested:
+     *            fully-qualified-class-name:event-id)
+     * @return true the first time the method was called with the given context;
+     *         false every subsequent time.
+     */
+    public static boolean firstTimeThisRun(String context)
+    {
+        if (occurredEvents.contains(context))
+            return false;
+
+        occurredEvents.add(context);
+        return true;
+    }
+
+    /**
+     * Check if this is the first time a particular event (identified by the
+     * context string) has occurred "ever" (in this BlueJ installation).
+     * 
+     * @param context Identifies the event (a property name)
+     * @return true the first time the method was called with the given context;
+     *         false every subsequent time.
+     */
+    public static boolean firstTimeEver(String context)
+    {
+        boolean occurred = Config.getPropBoolean(context);
+        if (occurred) {
+            return false;
+        }
+
+        Config.putPropBoolean(context, true);
+        return true;
+    }
+
+    /**
+     * This method creates a MacOS button. It will create a "textured" button on
+     * MacOS 10.5 and newer and a "toolbar" button on older MasOS.
+     * 
+     * @param button The button that should be changed.
+     */
+    public static void changeToMacButton(AbstractButton button)
+    {
+        // available button styles, as of MacOS 10.5:
+        // square, gradient, bevel, textured, roundRect, recessed, help
+        // segmented styles:
+        // segmented, segmentedRoundRect, segmentedCapsule, segmentedTextured
+        // see: http://developer.apple.com/technotes/tn2007/tn2196.html
+
+        if (!Config.isMacOS()) {
+            return;
+        }
+
+        Border oldBorder = button.getBorder();
+
+        // the following works since MacOS 10.5
+        button.putClientProperty("JButton.buttonType", "square");
+
+        if (oldBorder == button.getBorder()) {
+            // if the border didn't change the "square" type probably doesn't
+            // exist, which means we are running on MacOS < 10.5. This means we
+            // should use the old pre-10.5 "toolbar" style instead.
+            button.putClientProperty("JButton.buttonType", "toolbar");
+        }
+        else {
+            // if we get to this point, the square button type is available, and
+            // we can continue configuring for that one.
+            button.setMargin(new Insets(3, 1, 3, 1));
+        }
+    }
+    
+    /**
+     * Attempt to determine the prefix folder of a zip or jar archive.
+     * That is, if all files in the archive are stored under a first-level
+     * folder, return the name of that folder; otherwise return null.
+     * 
+     * @param arName   The archive file
+     * @return         The prefix folder of the archive, or null.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public static String getArchivePrefixFolder(File arName)
+    throws FileNotFoundException, IOException
+    {
+        JarInputStream jarInStream = null;
+        FileInputStream is = null;
+        String prefixFolder = null;
+        try {
+            is = new FileInputStream(arName);
+            jarInStream = new JarInputStream(is);
+            
+            // Extract entries in the jar file
+            JarEntry je = jarInStream.getNextJarEntry();
+            while (je != null) {
+                String entryName = je.getName();
+                int slashIndex = entryName.indexOf('/');
+                if (slashIndex == -1) {
+                    prefixFolder = null;
+                    break;
+                }
+                
+                String prefix = entryName.substring(0, slashIndex);
+                if (prefixFolder == null)
+                    prefixFolder = prefix;
+                else if (! prefixFolder.equals(prefix)) {
+                    prefixFolder = null;
+                    break;
+                }
+                
+                je = jarInStream.getNextJarEntry();
+            }
+        }
+        catch (FileNotFoundException fnfe) {
+            throw fnfe;  // rethrow after processing finally block
+        }
+        catch (IOException ioe) {
+            throw ioe; // rethrow after processing finally block
+        }
+        finally {
+            if (jarInStream != null)
+                jarInStream.close();
+            if (is != null)
+                is.close();
+        }
+        
+        return prefixFolder;
+    }
+
+    /**
+     * Attempt to intelligently extract an archive (zip, jar).
+     *  
+     * @param archive  the archive file
+     * @param parent  parent component for dialogs
+     * 
+     * @return  the single folder containing the extracted archive contents,
+     *          or null if the archive couldn't be extracted (in which case
+     *          an error dialog is displayed).
+     */
+    public static File maybeExtractArchive(File archive, Component parent)
+    {
+        JarInputStream jarInStream = null;
+        File oPath = archive.getParentFile();
+    
+        try { 
+            // first need to determine the output path. If the jar file
+            // contains a root-level (eg bluej.pkg) entry, extract into a directory
+            // whose name is the basename of the archive file. Otherwise, if
+            // all entries have a common ancestor, extract to that directory
+            // (after checking it doesn't exist).
+            String prefixFolder = getArchivePrefixFolder(archive);
+            
+            if (prefixFolder == null) {
+                // Try to extract to directory which has same name as the jar
+                // file, with the .jar or .bjar extension stripped.
+                String archiveName = archive.getName();
+                int dotIndex = archiveName.lastIndexOf('.');
+                String strippedName = null;
+                if(dotIndex != -1) {
+                    strippedName = archiveName.substring(0, dotIndex);
+                } else {
+                    strippedName = archiveName;
+                }
+                oPath = new File(oPath, strippedName);
+                if (oPath.exists()) {
+                    DialogManager.showErrorWithText(parent, "jar-output-dir-exists", oPath.toString());
+                    return null;
+                }
+                else if (! oPath.mkdir()) {
+                    DialogManager.showErrorWithText(parent, "jar-output-no-write", archive.toString());
+                    return null;
+                }
+            }
+            else {
+                File prefixFolderFile = new File(oPath, prefixFolder);
+                if (prefixFolderFile.exists()) {
+                    DialogManager.showErrorWithText(parent, "jar-output-dir-exists", prefixFolderFile.toString());
+                    return null;
+                }
+                if (! prefixFolderFile.mkdir()) {
+                    DialogManager.showErrorWithText(parent, "jar-output-no-write", archive.toString());
+                    return null;
+                }
+            }
+            
+            // Need to extract the project somewhere, then open it
+            FileInputStream is = new FileInputStream(archive);
+            jarInStream = new JarInputStream(is);
+            
+            // Extract entries in the jar file
+            JarEntry je = jarInStream.getNextJarEntry();
+            while (je != null) {
+                File outFile = new File(oPath, je.getName());
+                
+                // An entry could represent a file or directory
+                if (je.getName().endsWith("/"))
+                    outFile.mkdirs();
+                else {
+                    outFile.getParentFile().mkdirs();
+                    OutputStream os = new FileOutputStream(outFile);
+                    
+                    // try to read 8k at a time
+                    byte [] buffer = new byte[8192];
+                    int rlength = jarInStream.read(buffer);
+                    while (rlength != -1) {
+                        os.write(buffer, 0, rlength);
+                        rlength = jarInStream.read(buffer);
+                    }
+                    
+                    jarInStream.closeEntry();
+                }
+                je = jarInStream.getNextJarEntry();
+            }
+            
+            // Now, the jar file may contain a bluej project, or it may
+            // be a regular jar file in which case we should convert it
+            // to a bluej project first.
+            
+            if (prefixFolder != null)
+                oPath = new File(oPath, prefixFolder);
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+            DialogManager.showError(parent, "jar-extraction-error");
+            return null;
+        }
+        finally {
+            try {
+                if (jarInStream != null)
+                    jarInStream.close();
+            }
+            catch (IOException ioe) {}
+        }
+        return oPath;
+    }
+    
+    /**
+     * Convert an array of files into a classpath string that can be used to start a VM.
+     * If files is null or files is empty then an empty string is returned.
+     * 
+     * @param files an array of files.
+     * @return a non null string, possibly empty.
+     */
+    public static final String toClasspathString(File[] files)
+    {
+        if ((files == null) || (files.length < 1)) {
+            return "";
+        }
+
+        boolean addSeparator = false; // Do not add a separator at the beginning
+        StringBuffer buf = new StringBuffer();
+
+        for (int index = 0; index < files.length; index++) {
+            File file = files[index];
+
+            // It may happen that one entry is null, strange, but just skip it.
+            if (file == null) {
+                continue;
+            }
+
+            if (addSeparator) {
+                buf.append(File.pathSeparatorChar);
+            }
+
+            buf.append(file.toString());
+
+            // From now on, you have to add a separator.
+            addSeparator = true;
+        }
+
+        return buf.toString();
+    }
+    
+    /**
+     * Transform an array of URL into an array of File. Any non-file URLs are skipped.
+     * 
+     * @param urls  an array of URL to be converted
+     * @return  a non null (but possibly empty) array of File
+     */
+    public static final File[] urlsToFiles(URL[] urls)
+    {
+        if ((urls == null) || (urls.length < 1)) {
+            return new File[0];
+        }
+
+        List<File> rlist = new ArrayList<File>();
+
+        for (int index = 0; index < urls.length; index++) {
+            URL url = urls[index];
+
+            // A class path is always without the qualifier file in front of it.
+            // However some characters (such as space) are encoded.
+            
+            if ("file".equals(url.getProtocol())) {
+                URI uri = URI.create(url.toString());
+                rlist.add(new File(uri));
+            }
+        }
+
+        return rlist.toArray(new File[rlist.size()]);
+    }
+
+    /**
+     * Break a quoted command-line string into separate arguments.
+     */
+    public static List<String> dequoteCommandLine(String str)
+    {
+        List<String> strings = new ArrayList<String>();
+        
+        int i = 0;
+        while (i < str.length()) {
+            // Skip white space
+            while (i < str.length() && Character.isWhitespace(str.charAt(i))) {
+                i++;
+            }
+            
+            StringBuffer arg = new StringBuffer();
+            char c;
+            
+            while (i < str.length()) {
+                c = str.charAt(i++);
+                if (c == '\\') {
+                    if (i < str.length()) {
+                        arg.append(str.charAt(i++));
+                    }
+                }
+                else if (c == '\"') {
+                    // Process quoted string
+                    while (i < str.length()) {
+                        c = str.charAt(i++);
+                        if (c == '\"') {
+                            break;
+                        }
+                        if (c == '\\') {
+                            if (i < str.length()) {
+                                arg.append(str.charAt(i++));
+                            }
+                        }
+                        else {
+                            arg.append(c);
+                        }
+                    }
+                }
+                else if (Character.isWhitespace(c)) {
+                    break;
+                }
+                else {
+                    arg.append(c);
+                }
+            }
+            strings.add(arg.toString());
+        }
+        
+        return strings;        
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/DirectoryFilter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/DirectoryFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..b069bfd78a9ddde50a8e2798ad4629fdd3e05331
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/DirectoryFilter.java
@@ -0,0 +1,43 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility.filefilter;
+
+import java.io.*;
+
+/**
+ * A FileFilter that only accepts directories.
+ * An instance of this class can be used as a parameter for
+ * the listFiles method of class File.
+ *
+ * @author Axel Schmolitzky
+ * @version $Id: DirectoryFilter.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class DirectoryFilter implements FileFilter
+{
+    /**
+     * This method only accepts directories.
+     */
+    public boolean accept(File pathname)
+    {
+        return pathname.isDirectory();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/JavaClassFilter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/JavaClassFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..9975279ed38fd32b10613524cfb26c1199d66278
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/JavaClassFilter.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility.filefilter;
+
+import java.io.*;
+
+/**
+ * A FileFilter that only accepts Java class files.
+ * An instance of this class can be used as a parameter for
+ * the listFiles method of class File.
+ *
+ * @author  Axel Schmolitzky
+ * @version $Id: JavaClassFilter.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class JavaClassFilter implements FileFilter
+{
+    /**
+     * This method only accepts files that are Java class files.
+     * Whether a file is a Java class file is determined by the fact that
+     * its filename ends with ".class".
+     */
+    public boolean accept(File pathname)
+    {
+        return pathname.getName().endsWith(".class");
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/JavaSourceFilter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/JavaSourceFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5270d08744398f8564eee06199c1a2adfa8f535
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/JavaSourceFilter.java
@@ -0,0 +1,48 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility.filefilter;
+
+import java.io.FileFilter;
+import java.io.File;
+
+ /**
+  * A FileFilter that only accepts Java source files.
+  * An instance of this class can be used as a parameter for
+  * the listFiles method of class File.
+  *
+  * @version $ $
+  * @author Axel Schmolitzky
+  * @see java.io.FileFilter
+  * @see java.io.File
+  */
+public class JavaSourceFilter implements FileFilter
+{
+    /**
+     * This method only accepts files that are Java source files.
+     * Whether a file is a Java source file is determined by the fact that
+     * its filename ends with ".java".
+     */
+    public boolean accept(File pathname)
+    {
+        return pathname.getName().endsWith(".java");
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/SubPackageFilter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/SubPackageFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec0bd18e22f790aaafd42edb8bfcf17daaac0780
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/utility/filefilter/SubPackageFilter.java
@@ -0,0 +1,46 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.utility.filefilter;
+
+import java.io.*;
+
+import bluej.pkgmgr.Package;
+
+/**
+ * A FileFilter that only accepts BlueJ package directories.
+ * An instance of this class can be used as a parameter for
+ * the listFiles method of class File.
+ *
+ * @author  Axel Schmolitzky
+ * @version $Id: SubPackageFilter.java 6347 2009-05-20 15:22:43Z polle $
+ */
+public class SubPackageFilter implements FileFilter
+{
+    /**
+     * This method only accepts directories.
+     */
+    public boolean accept(File pathname)
+    {
+        return (pathname.isDirectory() &&
+                 Package.isPackage(pathname));
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/CallableView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/CallableView.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1e76325dd2577f63d3a715cbd42af7b9f5ef6ef
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/CallableView.java
@@ -0,0 +1,132 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+
+/**
+ * A "callable" is the generalisation of a Constructor and a Method. This class
+ * contains aspects common to both of those.
+ * 
+ * @author Michael Kolling
+ *  
+ */
+public abstract class CallableView extends MemberView
+{
+    /**
+     * Constructor.
+     */
+    public CallableView(View view)
+    {
+        super(view);
+    }
+
+    /**
+     * @returns a boolean indicating whether this method has parameters
+     */
+    public abstract boolean hasParameters();
+    
+    /**
+     * @returns a boolean indicating whether this method uses var args
+     */
+    public abstract boolean isVarArgs();
+
+    /**
+     * Indicates whether the callable view has type parameters.
+     */
+    public abstract boolean isGeneric();
+
+    /**
+     * Indicates whether the callable view represents a constructor.
+     */
+    public abstract boolean isConstructor();
+    
+    /**
+     * Count of parameters
+     * @returns the number of parameters
+     */
+    public int getParameterCount()
+    {
+        return getParameters().length;
+    }
+
+    /**
+     * Get an array of Class objects representing parameter classes
+     * @return  array of Class objects
+     */
+    public abstract Class<?>[] getParameters();
+    
+    /**
+     * Get an array of GenType objects representing the parameter types of the
+     * callable. For a varargs callable, the last parameter type will be an
+     * array (and {@link #isVarArgs()} will return true).
+     * 
+     * @param raw  whether to return raw versions of the parameter types
+     * @return  the parameter types
+     */
+    public abstract JavaType[] getParamTypes(boolean raw);
+
+    /**
+     * Get the type parameters for this callable as an array of GenTypeDeclTpar
+     */
+    public abstract GenTypeDeclTpar[] getTypeParams() throws ClassNotFoundException;
+    
+    /**
+     * Gets an array of strings with the names of the parameters
+     * @return
+     */
+    public String[] getParamNames()
+    {
+        Comment c = getComment();
+        if( c == null )
+            return null;
+        return c.getParamNames();
+    }
+    
+    /**
+     * Gets an array of nicely formatted strings with the types of the parameters 
+     */
+    public abstract String[] getParamTypeStrings();
+    
+    /**
+     * Print the method to a formatting print writer.
+     */
+    public void print(FormattedPrintWriter out)
+    {
+        print(out, 0);
+    }
+
+    public void print(FormattedPrintWriter out, int indents)
+    {
+        Comment comment = getComment();
+        if(comment != null)
+            comment.print(out, indents);
+
+        out.setItalic(false);
+        out.setBold(true);
+        for(int i=0; i<indents; i++)
+            out.indentLine();
+        out.println(getLongDesc());
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/Comment.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/Comment.java
new file mode 100644
index 0000000000000000000000000000000000000000..a09f630bad92f90462d5a871c994da234e36d6c2
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/Comment.java
@@ -0,0 +1,129 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import bluej.utility.Utility;
+
+import java.util.*;
+
+/**
+ * Comment class - the source information associated with a class or field
+ * 
+ * @author Michael Cahill
+ */
+public final class Comment
+{
+    private String target;		// identifies what this comment is for
+    private String text;
+    private String paramnames[];
+
+    public void load(Properties p, String prefix)
+    {
+        target = p.getProperty(prefix + ".target", "<no target>");
+        text = p.getProperty(prefix + ".text");
+
+        String paramnamestring = p.getProperty(prefix + ".params");
+
+        if (paramnamestring != null) {
+            StringTokenizer st = new StringTokenizer(paramnamestring, " ");
+
+            paramnames = new String[st.countTokens()];
+            int i = 0;
+            while(st.hasMoreTokens()) {
+                paramnames[i] = st.nextToken();
+                i++;
+            }
+        }
+    }
+
+    public String getTarget()
+    {
+        return target;
+    }
+
+    public String getText()
+    {
+        return text;
+    }
+
+    public String getParamName(int i)
+    {
+        if (paramnames != null) {
+            if(i >= 0 && i < paramnames.length)
+                return paramnames[i];
+        }
+        return null;
+    }
+
+    public int getParamCount()
+    {
+        if (paramnames != null)
+            return paramnames.length;
+        return 0;
+    }
+    
+    public String[] getParamNames()
+    {
+        if (paramnames == null)
+            return null;
+        
+        return (String[]) paramnames.clone();
+    }
+
+    public void print(FormattedPrintWriter out)
+    {
+        print(out, 0);
+    }
+
+    public void print(FormattedPrintWriter out, int indents)
+    {
+        out.setBold(false);
+        out.setItalic(true);
+        if(text != null) {
+            String[] lines = Utility.splitLines(text);
+
+            // trim spaces
+            for(int i = 0; i < lines.length; i++)
+                lines[i] = lines[i].trim(); 
+
+            // remove blank lines front and back
+            int first = 0;
+            while (first<lines.length && lines[first].length() == 0)
+                first++;
+            int last = lines.length - 1;
+            while (last>=0 && lines[last].length() == 0)
+                last--;
+
+            // print the comment lines
+            for(int i = first; i<=last; i++) { 
+                for(int j=0; j<indents; j++)
+                    out.indentLine(); 
+                out.println("// " + lines[i]); 
+            } 
+        } 
+    } 
+    
+    public String toString()   // simply for testing
+    {
+        return text;
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/CommentList.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/CommentList.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3afac0afb4aafb09e7e02195e74fd259a324d31
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/CommentList.java
@@ -0,0 +1,97 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * CommentList class - maintains a list of BlueJ comments
+ *
+ * @author Michael Cahill
+ */
+public final class CommentList
+{
+    private List<Comment> comments;
+	
+    /**
+     * Constructor - create a CommentList with an initial list of comments.
+     */
+    public CommentList(List<Comment> comments)
+    {
+        this.comments = comments;
+    }
+	
+    /**
+     * Constructor - create an empty CommentList.
+     */
+    public CommentList()
+    {
+        this(new ArrayList<Comment>());
+    }
+	
+    public void addComment(Comment comment)
+    {
+        comments.add(comment);
+    }
+	
+    public void removeComment(Comment comment)
+    {
+        comments.remove(comment);
+    }
+	
+    public Iterator<Comment> getComments()
+    {
+        return comments.iterator();
+    }
+	
+    public int numComments()
+    {
+        return comments.size();
+    }
+	
+    public void load(String filename) throws IOException
+    {
+        FileInputStream input = new FileInputStream(filename);
+        load(input);
+        input.close();
+    }
+	
+    public void load(InputStream input) throws IOException
+    {
+        Properties props = new Properties();
+        props.load(input);
+    		
+        int numComments = Integer.parseInt(props.getProperty("numComments", "0"));
+        for(int i = numComments-1; i >= 0; i--)
+        {
+            Comment comment = new Comment();
+            comment.load(props, "comment" + i);
+            comments.add(comment);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/ConstructorView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/ConstructorView.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ab2da1a2fa3186ab44ced712386b213f9e3a889
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/ConstructorView.java
@@ -0,0 +1,165 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import java.lang.reflect.Constructor;
+import java.util.List;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.utility.JavaUtils;
+
+/**
+ * A representation of a Java constructor in BlueJ
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ */
+public final class ConstructorView extends CallableView
+{
+    protected Constructor<?> cons;
+
+    /**
+     * Constructor.
+     */
+    public ConstructorView(View view, Constructor<?> cons)
+    {
+        super(view);
+        this.cons = cons;
+    }
+
+    /**
+     * Returns a string describing this Constructor.
+     */
+    public String toString()
+    {
+        return cons.toString();
+    }
+
+    public int getModifiers()
+    {
+        return cons.getModifiers();
+    }
+
+    /**
+     * Returns a boolean indicating whether this method has parameters
+     */
+    public boolean hasParameters()
+    {
+        return (cons.getParameterTypes().length > 0);
+    }
+
+    public boolean isGeneric()
+    {
+        return !JavaUtils.getJavaUtils().getTypeParams(cons).isEmpty();
+    }
+    
+    public boolean isConstructor()
+    {
+        return true;
+    }
+
+    /**
+     * Returns a signature string in the format
+     *  name(type,type,type)
+     */
+    public String getSignature()
+    {
+        return JavaUtils.getSignature(cons);
+    }
+
+    /**
+     * Get a short String describing this member. A description is similar
+     * to the signature, but it has parameter names in it instead of types.
+     */
+    public String getShortDesc() 
+    {
+        try {
+            return JavaUtils.getJavaUtils().getShortDesc(cons, getParamNames());
+        }
+        catch (ClassNotFoundException cnfe) {
+            return ""; // TODO handle better
+        }
+    }
+
+    /**
+     * Get a long String describing this member. A long description is
+     * similar to the short description, but it has type names and parameters
+     * included.
+     */
+    public String getLongDesc() 
+    {
+        try {
+            return JavaUtils.getJavaUtils().getLongDesc(cons, getParamNames());
+        }
+        catch (ClassNotFoundException cnfe) {
+            return ""; // TODO handle better
+        }
+    }
+    
+    /**
+     * Get an array of Class objects representing constructor's parameters
+     * @returns array of Class objects
+     */
+    public Class<?>[] getParameters()
+    {
+        return cons.getParameterTypes();
+    }
+    
+    @Override
+    public String[] getParamTypeStrings() 
+    {
+        try {
+            return JavaUtils.getJavaUtils().getParameterTypes(cons);
+        }
+        catch (ClassNotFoundException cnfe) {
+            return new String[0]; // TODO handle better
+        }
+    }
+    
+    @Override
+    public JavaType[] getParamTypes(boolean raw)
+    {
+        try {
+            return JavaUtils.getJavaUtils().getParamGenTypes(cons);
+        }
+        catch (ClassNotFoundException cnfe) {
+            return new JavaType[0]; // TODO handle better
+        }
+    }
+    
+    @Override
+    public GenTypeDeclTpar[] getTypeParams()
+    {
+        JavaUtils jutils = JavaUtils.getJavaUtils();
+        List<GenTypeDeclTpar> tparams = jutils.getTypeParams(cons);
+        return tparams.toArray(new GenTypeDeclTpar[tparams.size()]);
+    }
+
+    /**
+     * Whether this method has a var arg.
+     */
+    public boolean isVarArgs()
+    {
+        return JavaUtils.getJavaUtils().isVarArgs(cons);
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/FieldView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/FieldView.java
new file mode 100644
index 0000000000000000000000000000000000000000..39e935d4290dd0146bac8abb1e5d3a2cfcc076cc
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/FieldView.java
@@ -0,0 +1,115 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import java.lang.reflect.*;
+
+/**
+ ** @version $Id: FieldView.java 6215 2009-03-30 13:28:25Z polle $
+ ** @author Michael Cahill
+ **
+ ** A representation of a Java field in BlueJ
+ **/
+public final class FieldView extends MemberView
+{
+    protected Field field;
+    protected View type;
+	
+    /**
+     ** Constructor.
+     **/
+    public FieldView(View view, Field field)
+    {
+	super(view);
+		
+	this.field = field;
+    }
+
+    /**
+     * Returns the Field being manipulated by this View.
+     * 
+     * @return the Field that this view represent.
+     */
+    public Field getField ()
+      {
+      return field;
+      }
+      
+    /**
+     ** Returns the name of this method as a String
+     **/
+    public String getName()
+    {
+	return field.getName();
+    }
+	
+    /**
+     ** Returns a Class object that represents the type of the field represented
+     **  by this object.
+     **/
+    public View getType()
+    {
+	if(type == null)
+	    type = View.getView(field.getType());
+		
+	return type;
+    }
+
+    /**
+     ** Returns a string describing this Method.
+     **/
+    public String toString()
+    {
+	return field.toString();
+    }
+	
+    public int getModifiers()
+    {
+	return field.getModifiers();
+    }
+	
+    public String getShortDesc()
+    {
+	StringBuffer sb = new StringBuffer();
+	sb.append(View.getTypeName(field.getType()));
+	sb.append(" ");
+	sb.append(field.getName());
+	return sb.toString();
+    }
+
+    public String getLongDesc()
+    {
+        return getShortDesc();        
+    }
+    
+    /**
+     ** Returns a string describing this Field in a human-readable format
+     **/
+    public String getSignature()
+    {
+	StringBuffer sb = new StringBuffer();
+	//		sb.append(View.getTypeName(field.getType()));
+	//		sb.append(" ");
+	sb.append(field.getName());
+	return sb.toString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/FormattedPrintWriter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/FormattedPrintWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..7ad5acb22cb92c22928c2de9e64c62e834b6a779
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/FormattedPrintWriter.java
@@ -0,0 +1,89 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ ** @version $Id: FormattedPrintWriter.java 6215 2009-03-30 13:28:25Z polle $
+ ** @author Michael Cahill
+ **
+ ** FormattedPrintWriter - provides formatting on top of a PrintWriter
+ **/
+public abstract class FormattedPrintWriter extends PrintWriter
+{
+	public FormattedPrintWriter(Writer out)
+	{
+		super(out);
+	}
+	
+	public FormattedPrintWriter(Writer out, boolean autoFlush)
+	{
+		super(out, autoFlush);
+	}
+	
+	public FormattedPrintWriter(OutputStream out)
+	{
+		super(out);
+	}
+	
+	public FormattedPrintWriter(OutputStream out, boolean autoFlush)
+	{
+		super(out, autoFlush);
+	}
+	
+	boolean bold = false;
+	public void setBold(boolean bold)
+	{
+		if(this.bold == bold)
+			return;	// nothing to do
+
+		if(bold)
+			startBold();
+		else
+			endBold();
+			
+		this.bold = bold;
+	}
+	protected abstract void startBold();
+	protected abstract void endBold();
+	
+	boolean italic = false;
+	public void setItalic(boolean italic)
+	{
+		if(this.italic == italic)
+			return;	// nothing to do
+
+		if(italic)
+			startItalic();
+		else
+			endItalic();
+			
+		this.italic = italic;
+	}
+	protected abstract void startItalic();
+	protected abstract void endItalic();
+
+	protected abstract void indentLine();
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/LabelPrintWriter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/LabelPrintWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e31e985e15a0c43a6b0472a21f296289a51879c
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/LabelPrintWriter.java
@@ -0,0 +1,87 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import bluej.utility.MultiLineLabel;
+import java.awt.Label;
+
+/**
+ ** @version $Id: LabelPrintWriter.java 6215 2009-03-30 13:28:25Z polle $
+ ** @author Michael Cahill
+ **
+ ** LabelPrintWriter - create a MultiLineLabel containing the output to a
+ ** 	FormattedPrintWriter
+ **/
+public class LabelPrintWriter extends FormattedPrintWriter
+{
+	MultiLineLabel label;
+	
+	public LabelPrintWriter(int align)
+	{
+		// PrintWriter needs to be passed a valid outputstream
+		// even if we are going to not actually print to it.
+		// We pass it the standard System output stream
+		super(System.out);
+
+		label = new MultiLineLabel(align);
+	}
+	
+	public LabelPrintWriter()
+	{
+		this(Label.LEFT);
+	}
+	
+	public MultiLineLabel getLabel()
+	{
+		return label;
+	}
+	
+	protected void startBold()
+	{
+		label.setBold(true);
+	}
+	
+	protected void endBold()
+	{
+		label.setBold(false);
+	}
+	
+	protected void startItalic()
+	{
+		label.setItalic(true);
+	}
+
+	protected void endItalic()
+	{
+		label.setItalic(false);
+	}
+
+	protected void indentLine()
+	{
+		label.addText("\t");
+	}
+	
+	public void println(String str)
+	{
+		label.addText(str);
+	}
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/MemberView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/MemberView.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b395e508940175c10361efa9be9e7546841d631
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/MemberView.java
@@ -0,0 +1,116 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * A representation of a Java class member in BlueJ.
+ *
+ * @author  Michael Cahill
+ */
+public abstract class MemberView
+{
+    private View view;
+    private Comment comment;
+
+    protected MemberView(View view)
+    {
+        if (view == null)
+            throw new NullPointerException();
+
+        this.view = view;
+    }
+
+    /**
+     * @return the View of the class or interface that declares this member.
+     */
+    public View getDeclaringView()
+    {
+        return view;
+    }
+
+    /**
+     * @return the name of the class or interface that declares this member.
+     */
+    public String getClassName()
+    {
+        return view.getQualifiedName();
+    }
+
+    /**
+     * Returns the Java language modifiers for the member or
+     * constructor represented by this Member, as an integer.  The
+     * Modifier class should be used to decode the modifiers in
+     * the integer.
+     * @see Modifier
+     */
+    public abstract int getModifiers();
+
+    /**
+     * Returns a string describing this member in a human-readable format
+     */
+    public abstract String getSignature();
+
+    /**
+     * Sets the (javadoc) comment for this Member
+     */
+    void setComment(Comment comment)
+    {
+        this.comment = comment;
+    }
+
+    /**
+     * Returns the (javadoc) comment for this Member
+     */
+    public Comment getComment()
+    {
+        if (view != null) {
+            view.loadComments();
+        }
+
+        return comment;
+    }
+
+    /**
+     * Get a short String describing this member
+     */
+    public abstract String getShortDesc();
+
+    /**
+     * Get a longer String describing this member
+     */
+    public abstract String getLongDesc();
+
+    /**
+     * @return a boolean indicating whether this member is static
+     */
+    public boolean isStatic()
+    {
+        return Modifier.isStatic(getModifiers());
+    }
+
+    public String toString()
+    {
+        return view.toString();
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/MethodView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/MethodView.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd87eaaf1b3ec8552db63ee70858d15f1d2c64e4
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/MethodView.java
@@ -0,0 +1,315 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Map;
+
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.JavaType;
+import bluej.utility.JavaUtils;
+
+/**
+ * A representation of a Java method in BlueJ
+ * 
+ * @author Michael Cahill
+ * @author Michael Kolling
+ */
+public class MethodView extends CallableView implements Comparable<MethodView>
+{
+    protected Method method;
+    protected View returnType;
+    private JavaType jtReturnType;
+
+    /**
+     * Constructor.
+     */
+    public MethodView(View view, Method method) throws ClassNotFoundException
+    {
+        super(view);
+        this.method = method;
+        jtReturnType = JavaUtils.getJavaUtils().getReturnType(method);
+    }
+
+    public Method getMethod()
+    {
+        return method;
+    }
+    
+    /**
+     * Returns a string describing this Method.
+     */
+    public String toString()
+    {
+        return method.toString();
+    }
+
+    public int getModifiers()
+    {
+        return method.getModifiers();
+    }
+
+    public boolean hasParameters()
+    {
+        return (method.getParameterTypes().length > 0);
+    }
+    
+    public boolean isConstructor()
+    {
+        return false;
+    }
+
+    /**
+     * Returns a signature string in the format
+     * "type name(type,type,type)".
+     */
+    @Override
+    public String getSignature()
+    {
+        return JavaUtils.getSignature(method);
+    }
+    
+    /**
+     * Get the "call signature", ie. the signature without the return type.
+     * This should not be made user visible, it is for internal purposes only.
+     * It is useful for locating methods which override a method in a super
+     * class, without having to worry about covariant returns and generic
+     * methods etc.
+     */
+    public String getCallSignature()
+    {
+        StringBuffer name = new StringBuffer();
+        name.append(method.getName());
+        name.append('(');
+        Class<?>[] params = method.getParameterTypes();
+        for(int i = 0; i < params.length; i++) {
+            name.append(params[i].getName());
+            if (i != params.length - 1) {
+                name.append(',');
+            }
+        }
+        name.append(')');
+        return name.toString();
+    }
+    
+    /**
+     * Get a short String describing this member. A description is similar
+     * to the signature, but it has parameter names in it instead of types.
+     */
+    @Override
+    public String getShortDesc()
+    {
+        try {
+            return JavaUtils.getJavaUtils().getShortDesc(method, getParamNames());
+        }
+        catch (ClassNotFoundException cnfe) {
+            return ""; // TODO handle.
+        }
+    }
+
+    /**
+     * Get a long String describing this member. A long description is
+     * similar to the short description, but it has type names and parameters
+     * included.
+     */
+    @Override
+    public String getLongDesc()
+    {
+        try {
+            return JavaUtils.getJavaUtils().getLongDesc(method, getParamNames());
+        }
+        catch (ClassNotFoundException cnfe) {
+            return ""; // TODO handle properly.
+        }
+    }
+    
+    /**
+     * Get a long String describing this member, with type parameters from the
+     * class mapped to the corresponding instantiation type. Type parameters
+     * not contained in the map are mapped to their erasure type; type
+     * parameters from a generic method are left unmapped.
+     * 
+     * @param genericParams  The map of String -> GenType
+     * @return  the signature string with type parameters mapped
+     */
+    public String getLongDesc(Map<String,GenTypeParameter> genericParams)
+    {
+        try {
+            if (genericParams == null && isStatic()) {
+                return JavaUtils.getJavaUtils().getLongDesc(method, getParamNames());
+            }
+            else {
+                return JavaUtils.getJavaUtils().getLongDesc(method, getParamNames(), genericParams);
+            }
+        }
+        catch (ClassNotFoundException cnfe) {
+            return ""; // TODO handle.
+        }
+    }
+
+    /**
+     * Get an array of Class objects representing method's parameters
+     * @returns array of Class objects
+     */
+    public Class<?>[] getParameters()
+    {
+        return method.getParameterTypes();
+    }
+    
+    @Override
+    public JavaType[] getParamTypes(boolean raw)
+    {
+        try {
+            JavaUtils jutils = JavaUtils.getJavaUtils();
+            JavaType [] ptypes = jutils.getParamGenTypes(method, raw);
+            return ptypes;
+        }
+        catch (ClassNotFoundException cnfe) {
+            return new JavaType[0]; // TODO handle better
+        }
+    }
+    
+    @Override
+    public GenTypeDeclTpar[] getTypeParams() throws ClassNotFoundException
+    {
+        JavaUtils jutils = JavaUtils.getJavaUtils();
+        List<GenTypeDeclTpar> tparams = jutils.getTypeParams(method);
+        return tparams.toArray(new GenTypeDeclTpar[0]);
+    }
+    
+    @Override
+    public String[] getParamTypeStrings()
+    {
+        try {
+            return JavaUtils.getJavaUtils().getParameterTypes(method);
+        }
+        catch (ClassNotFoundException cnfe) {
+            return new String[0]; // TODO handle better
+        }
+    }
+
+    /**
+     * Returns the name of this method as a String
+     */
+    public String getName()
+    {
+        return method.getName();
+    }
+
+    /**
+     * Check whether this is method returns void
+     */
+    public boolean isVoid()
+    {
+        return method.getReturnType() == void.class;
+    }
+
+    /**
+     * @returns if this method is the main method (a static void returning
+     * function called main with a string array as an argument)
+     */
+    public boolean isMain()
+    {
+        if (!isVoid()) {
+            return false;
+        }
+        if ("main".equals(getName())) {
+            Class<?>[] c = getParameters();
+            if (c.length != 1) {
+                return false;
+            }
+            if (c[0].isArray() && String.class.equals(c[0].getComponentType())) {
+                if (Modifier.isStatic(getModifiers()) && Modifier.isPublic(getModifiers())) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Whether this method has a var arg.
+     */
+    @Override
+    public boolean isVarArgs()
+    {
+        return JavaUtils.getJavaUtils().isVarArgs(method);
+    }
+    
+    /**
+     * Test whether the method is generic.
+     */
+    @Override
+    public boolean isGeneric()
+    {
+        return !JavaUtils.getJavaUtils().getTypeParams(method).isEmpty();
+    }
+
+    /**
+     * Returns a Class object that represents the formal return type
+     * of the method represented by this Method object.
+     */
+    public View getReturnType()
+    {
+        if (returnType == null) {
+            returnType = View.getView(method.getReturnType());
+        }
+        return returnType;
+    }
+    
+    /**
+     * Get the return type of this method.
+     */
+    public JavaType getGenericReturnType()
+    {
+        return jtReturnType;
+    }
+    
+    public void print(FormattedPrintWriter out, Map<String,GenTypeParameter> typeParams, int indents)
+    {
+        Comment comment = getComment();
+        if(comment != null) {
+            comment.print(out, indents);
+        }
+
+        out.setItalic(false);
+        out.setBold(true);
+        for(int i=0; i<indents; i++) {
+            out.indentLine();
+        }
+        
+        out.println(getLongDesc(typeParams));
+    }
+
+    // ==== Comparable interface ====
+    
+    /**
+     * Compare operation to provide alphabetical sorting by method name.
+     */
+    public int compareTo(MethodView other)
+    {
+        return method.getName().compareTo(other.method.getName());
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/TypeParamView.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/TypeParamView.java
new file mode 100644
index 0000000000000000000000000000000000000000..996b3e0189e74c3ab83f2dd51a4dcd299bdd8aa9
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/TypeParamView.java
@@ -0,0 +1,79 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import bluej.debugger.gentype.GenTypeDeclTpar;
+
+/**
+ * Represents a formal type parameter for a generic class
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: TypeParamView.java 6215 2009-03-30 13:28:25Z polle $
+ */
+public class TypeParamView
+{
+    protected GenTypeDeclTpar paramType;
+    protected View view;
+
+    /**
+     * Constructor.
+     * 
+     * @param view The view of the generic class to which this type parameter belongs
+     * @param paramType The type parameter
+     */
+    protected TypeParamView(View view, GenTypeDeclTpar paramType) {
+        if (view == null) {
+            throw new NullPointerException();
+        }
+        if (paramType == null) {
+            throw new NullPointerException();
+        }
+        this.view = view;
+        this.paramType = paramType;
+    }
+
+    /**
+     * Returns the name of this formal type parameter as a String
+     */
+    public String getName() {
+        return paramType.getTparName();
+    }
+
+    /**
+     * @return the View of the class or interface that declares this member.
+     */
+    public View getDeclaringView() {
+        return view;
+    }
+
+    /**
+     * Returns a string describing this type parameter. This includes name and bound as written in Java. <br>
+     * Eaxample: T extends Integer
+     */
+    public String toString() {
+        return paramType.toString(true);
+    }
+    
+    public GenTypeDeclTpar getParamType() {
+        return paramType;
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/View.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/View.java
new file mode 100644
index 0000000000000000000000000000000000000000..49b8d0f0eea4d56f8ffc98d0d8e71ddaf8b26ee5
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/View.java
@@ -0,0 +1,596 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009,2010,2011  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import bluej.debugger.gentype.GenTypeDeclTpar;
+import bluej.utility.JavaNames;
+import bluej.utility.JavaUtils;
+import bluej.views.View.MemberElement;
+
+
+/**
+ * A representation of a Java class in BlueJ.
+ * 
+ * <p>The methods in this class are generally thread-safe.
+ *
+ * @author  Michael Cahill
+ */
+public class View
+{
+    /** The class that this view is for **/
+    protected Class<?> cl;
+
+    protected FieldView[] fields;
+    protected FieldView[] allFields;
+    protected ConstructorView[] constructors;
+    protected MethodView[] methods;
+    protected MethodView[] allMethods;
+    protected TypeParamView[] typeParams;
+
+    protected Comment comment;
+
+    private static Map<Class<?>,View> views = new HashMap<Class<?>,View>();
+
+    /**
+     * Return a view of a class.
+     * This is the only way to obtain a View object.
+     * This method is thread-safe.
+     */
+    public static View getView(Class<?> cl)
+    {
+        if(cl == null)
+            return null;
+
+        // Debug.message("Started getView for class " + cl);
+
+        synchronized (views) {
+            View v = views.get(cl);
+            if(v == null) {
+                v = new View(cl);
+                views.put(cl, v);
+            }
+
+            // Debug.message("Ended getView for class " + cl);
+
+            return v;
+        }
+    }
+
+    /**
+     * Remove from the view cache, all views of classes
+     * which were loaded by the given class loader.
+     * This method is thread-safe.
+     */
+    public static void removeAll(ClassLoader loader)
+    {
+        synchronized (views) {
+            Iterator<View> it = views.values().iterator();
+
+            while(it.hasNext()) {
+                View v = it.next();
+
+                if (v.getClassLoader() == loader) {
+                    it.remove();
+                }
+            }
+        }
+    }
+
+    private View(Class<?> cl)
+    {
+        this.cl = cl;
+    }
+
+    private ClassLoader getClassLoader()
+    {
+        return cl.getClassLoader();
+    }
+
+    public String getQualifiedName()
+    {
+        return cl.getName();
+    }
+    
+    public String getPackageName()
+    {
+        String clName = cl.getName();
+        int i = clName.lastIndexOf('.');
+        if (i == -1)
+            return "";
+        else
+            return clName.substring(0, i);
+    }
+
+    /**
+     * Gets the Class this view is looking into.
+     * This is used to know the exact return type of a method and is consistent 
+     * with the Java Reflection API. Damiano
+     */
+    public Class<?> getViewClass ()
+    {
+        return cl;
+    }
+
+    public String getBaseName()
+    {
+        return JavaNames.getBase(cl.getName());
+    }
+
+    public View getSuper()
+    {
+        return getView(cl.getSuperclass());
+    }
+
+    public View[] getInterfaces()
+    {
+        Class<?>[] interfaces = cl.getInterfaces();
+
+        View[] interfaceViews = new View[interfaces.length];
+        for(int i = 0; i < interfaces.length; i++)
+            interfaceViews[i] =  getView(interfaces[i]);
+
+        return interfaceViews;
+    }
+
+    public final boolean isInterface()
+    {
+        return cl.isInterface();
+    }
+    
+    public final boolean isGeneric()
+    {
+        return getTypeParams().length>0;
+    }
+    
+    /**
+     * Returns all the formal type parameters.
+     * 
+     * @return Type parameters. Empty array if none exist.
+     */
+    public  TypeParamView[] getTypeParams() {
+        if(typeParams == null) {            
+            List<GenTypeDeclTpar> genTypeParams = JavaUtils.getJavaUtils().getTypeParams(this.cl);            
+            typeParams = new TypeParamView[genTypeParams.size()];
+                for (int i = 0; i < typeParams.length; i++) {
+                typeParams[i] = new TypeParamView(this, genTypeParams.get(i));                
+            }            
+        }
+        return typeParams;
+    }
+    
+
+    /**
+     * Return views of all methods of this class (including inherited ones).
+     * Walk superclasses + interfaces for methods. Method definitions higher
+     * up in the inheritance hierarchy are first in the array, with the latest 
+     * redefinition last.
+     */
+    public MethodView[] getAllMethods()
+    {
+        if(allMethods == null) {
+            HashMap<String,MemberElement> map = new HashMap<String,MemberElement>();
+            getAllMethods(map, 0);
+            
+            List<MemberElement> methods = new ArrayList<MemberElement>(map.values());
+            Collections.sort(methods, new ElementComparer());
+
+            int numMethods = methods.size();
+            allMethods = new MethodView[numMethods];
+            for(int i = 0; i < numMethods; i++) {
+                MemberElement elem = (MemberElement)methods.get(i);
+                allMethods[i] = (MethodView)elem.member;
+            }
+        }
+
+        return allMethods;
+    }
+
+    /**
+     ** Walk superclasses + interfaces for fields.
+     ** All fields are inherited (+ overridden) from everywhere.
+     **/
+    public FieldView[] getAllFields()
+    {
+        if(allFields == null) {
+            HashMap<String,MemberElement> map = new HashMap<String,MemberElement>();
+            getAllFields(map, 0);
+            
+            List<MemberElement> fields = new ArrayList<MemberElement>(map.values());
+            Collections.sort(fields, new ElementComparer());
+
+            int numFields = fields.size();
+            allFields = new FieldView[numFields];
+            for(int i = 0; i < numFields; i++) {
+                MemberElement elem = (MemberElement)fields.get(i);
+                allFields[i] = (FieldView)elem.member;
+            }
+        }
+
+        return allFields;
+    }
+
+    /**
+     ** (Attempt at an) efficient implementation of getAllMethods + getAllFields
+     ** The old version had shocking performance - this one uses a HashMap
+     ** to notice the conflicts
+     **/
+
+    class MemberElement
+    {
+        int index;
+        MemberView member;
+
+        MemberElement(int index, MemberView member)
+        {
+            this.index = index;
+            this.member = member;
+        }
+    }
+
+    class ElementComparer implements Comparator<MemberElement>
+    {
+        @Override
+      public Comparator<MemberElement> reversed() {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      public Comparator<MemberElement> thenComparing(
+          Comparator<? super MemberElement> other) {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      public <U> Comparator<MemberElement> thenComparing(
+          Function<? super MemberElement, ? extends U> keyExtractor,
+          Comparator<? super U> keyComparator) {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      public <U extends Comparable<? super U>> Comparator<MemberElement> thenComparing(
+          Function<? super MemberElement, ? extends U> keyExtractor) {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      public Comparator<MemberElement> thenComparingInt(
+          ToIntFunction<? super MemberElement> keyExtractor) {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      public Comparator<MemberElement> thenComparingLong(
+          ToLongFunction<? super MemberElement> keyExtractor) {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      public Comparator<MemberElement> thenComparingDouble(
+          ToDoubleFunction<? super MemberElement> keyExtractor) {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+        /** Return { -1, 0, 1 } to represent <a> { <, ==, > } <b> **/
+        public final int compare(MemberElement a, MemberElement b)
+        {
+            int cmp = a.index - b.index;
+
+            return (cmp < 0) ? -1 : ((cmp > 0) ? 1 : 0);
+        }
+    }
+
+    /**
+     * Helper method to get all methods from the class represented by this
+     * view and all its superclasses. If all methods have already been cached
+     * (in "allMethods"), simply returns the cached list.
+     * 
+     * @param h        The hashmap into which to put all the methods
+     * @param methnum  The number of methods presently in the map
+     * @return         The number of methods in the map at completion
+     */
+    protected int getAllMethods(HashMap<String,MemberElement> h, int methnum)
+    {
+        if(allMethods != null) {
+            // carefully copy from allMethods into h
+            methnum = addMembers(h, allMethods, methnum);
+            return methnum;
+        }
+
+        // otherwise, do the real work
+        // carefully copy local methods into v
+
+        View sView = getSuper();
+        if(sView != null)
+            methnum = sView.getAllMethods(h, methnum);
+
+        if(isInterface()) {
+            View[] ifaces = getInterfaces();
+            for(int i = 0; i < ifaces.length; i++)
+                methnum = ifaces[i].getAllMethods(h, methnum);
+        }
+
+        methnum = addMembers(h, getDeclaredMethods(), methnum);
+        return methnum;
+    }
+
+    protected int getAllFields(HashMap<String,MemberElement> h, int fieldnum)
+    {
+        if(allFields != null) {
+            // carefully copy from allFields into h
+            fieldnum = addMembers(h, allFields, fieldnum);
+            return fieldnum;
+        }
+
+        // otherwise, do the real work
+        // carefully copy local fields into v
+
+        View sView = getSuper();
+        if(sView != null)
+            fieldnum = sView.getAllFields(h, fieldnum);
+
+        View[] ifaces = getInterfaces();
+        for(int i = 0; i < ifaces.length; i++)
+            fieldnum = ifaces[i].getAllFields(h, fieldnum);
+
+        fieldnum = addMembers(h, getDeclaredFields(), fieldnum);
+        return fieldnum;
+    }
+
+    private int addMembers(HashMap<String,MemberElement> h, MemberView[] members, int num)
+    {
+        for(int i = members.length - 1; i >= 0; i--) {
+            h.put(members[i].toString(), new MemberElement(num++, members[i]));
+        }
+
+        return num;
+    }
+
+    public MethodView[] getDeclaredMethods()
+    {
+        if(methods == null) {
+            int count = 0;
+            try {
+                Method[] cl_methods = cl.getDeclaredMethods();
+                
+                for(int i = 0; i < cl_methods.length; i++) {
+                    if (!cl_methods[i].isSynthetic()) {
+                        count++;
+                    }
+                }
+                methods = new MethodView[count];
+                
+                count = 0;
+                for(int i = 0; i < cl_methods.length; i++) {
+                    if (!cl_methods[i].isSynthetic()) {
+                        try {
+                            methods[count] = new MethodView(this, cl_methods[i]);
+                        }
+                        catch (Throwable t) {
+                            t.printStackTrace();
+                            if (t instanceof ClassNotFoundException) {
+                                throw (ClassNotFoundException) t;
+                            }
+                        }
+                        count++;
+                    }
+                }
+            }
+            catch (LinkageError le) {
+                // getDeclaredMethods can cause attempts for other classes to be loaded.
+                // This in turn can cause a LinkageError variant to be thrown. (For
+                // instance, NoClassDefFoundError).
+                methods = new MethodView[0];
+            }
+            catch (ClassNotFoundException cnfe) {
+                methods = new MethodView[0];
+            }
+        }
+
+        return methods;
+    }
+
+    public FieldView[] getDeclaredFields()
+    {
+        if(fields == null)
+        {
+            try {
+                Field[] cl_fields= cl.getDeclaredFields();
+                fields = new FieldView[cl_fields.length];
+            
+                for(int i = 0; i < cl_fields.length; i++)
+                    fields[i] = new FieldView(this, cl_fields[i]);
+            }
+            catch (LinkageError le) {
+                // getDeclaredFields can cause attempts for other classes to be loaded.
+                // This in turn can cause a LinkageError variant to be thrown. (For
+                // instance, NoClassDefFoundError).
+                fields = new FieldView[0];
+            }
+        }
+
+        return fields;
+    }
+
+    public ConstructorView[] getConstructors()
+    {
+        if(constructors == null)
+        {
+            try {
+                Constructor<?>[] cl_constrs = cl.getDeclaredConstructors();
+                constructors = new ConstructorView[cl_constrs.length];
+                
+                for(int i = 0; i < constructors.length; i++)
+                    constructors[i] = new ConstructorView(this, cl_constrs[i]);
+            }
+            catch (LinkageError le) {
+                // Class.getDeclaredConstructors() can throw various linkage errors
+                return new ConstructorView[0];
+            }
+        }
+
+        return constructors;
+    }
+
+    public Comment getComment()
+    {
+        loadComments();
+        return comment;
+    }
+
+    public void setComment(Comment comment)
+    {
+        this.comment = comment;
+    }
+
+    boolean comments_loaded = false;
+    protected void loadComments()
+    {
+        if(comments_loaded)
+            return;     // already loaded - nothing to do
+
+        comments_loaded = true;
+
+        // match the comments against this view's members
+        // -> put all members into a hashmap indexed by
+        // <member>.getSignature() (== <comment>.getTarget())
+        Map<String,MemberView> table = new HashMap<String,MemberView>();
+        addMembers(table, getAllFields());
+        addMembers(table, getConstructors());
+        addMembers(table, getAllMethods());
+
+        loadClassComments(this, table);
+    }
+
+    protected void loadClassComments(View curview, Map<String,MemberView> table)
+    {
+        // move up to the superclass first, so that redefinied comments override
+        if(curview.getSuper() != null)
+            loadClassComments(curview.getSuper(), table);
+
+        CommentList comments = null;
+        String filename = curview.getQualifiedName().replace('.', '/') + ".ctxt";
+
+        try {
+            InputStream in = null;
+
+            if (curview.cl.getClassLoader() == null) {
+                in = ClassLoader.getSystemResourceAsStream(filename);
+            }
+            else {
+                in = curview.cl.getClassLoader().getResourceAsStream(filename);
+            }
+
+            if(in != null) {
+                comments = new CommentList();
+                comments.load(in);
+                in.close();
+            }
+            //else
+            //    Debug.message("Failed to load .ctxt file " + filename);
+
+        } catch(Exception e) {
+            e.printStackTrace();
+        }
+
+        if(comments != null) {
+            // match up the comments read from the file with the members of this view
+            for(Iterator<Comment> it = comments.getComments(); it.hasNext(); ) {
+                Comment c = it.next();
+                
+                if(c.getTarget().startsWith("class ") ||
+                   c.getTarget().startsWith("interface ")) {
+                    // we only want to set a class comment on our base class, not for
+                    // our supers
+                    if (curview == this)
+                        setComment(c);
+                    continue;
+                }
+
+                MemberView m = table.get(c.getTarget());
+
+                if(m == null) {
+                    //Debug.message("No member found for " + c.getTarget() + " in file " + filename);
+                    continue;
+                }
+                else {
+                    //Debug.message("Found member for " + c.getTarget() + " in file " + filename);
+                    m.setComment(c);
+                }
+            }
+        }
+    }
+
+    private void addMembers(Map<String,MemberView> table, MemberView[] members)
+    {
+        for(int i = 0; i < members.length; i++) {
+            //Debug.message("Adding member " + members[i].getSignature());
+            table.put(members[i].getSignature(), members[i]);
+        }
+    }
+
+    public String getTypeName()
+    {
+        return getTypeName(cl);
+    }
+
+    static String getTypeName(Class<?> type)
+    {
+        if(type.isArray())
+            {
+                try {
+                    Class<?> primtype = type;
+                    int dimensions = 0;
+                    while(primtype.isArray())
+                        {
+                            dimensions++;
+                            primtype = primtype.getComponentType();
+                        }
+                    StringBuffer sb = new StringBuffer();
+                    sb.append(JavaNames.stripPrefix(primtype.getName()));
+                    for (int i = 0; i < dimensions; i++)
+                        sb.append("[]");
+                    return sb.toString();
+                } catch (Throwable e) {
+                    // ignore it
+                }
+            }
+        return JavaNames.stripPrefix(type.getName());
+    }
+}
diff --git a/Sd1/P/Maven/bluej/src/main/java/bluej/views/ViewFilter.java b/Sd1/P/Maven/bluej/src/main/java/bluej/views/ViewFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..3eb7373e6f1f9b9cefa34a6eac91ce53c0f0a3ad
--- /dev/null
+++ b/Sd1/P/Maven/bluej/src/main/java/bluej/views/ViewFilter.java
@@ -0,0 +1,80 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package bluej.views;
+
+import java.lang.reflect.*;
+
+/**
+ ** @version $Id: ViewFilter.java 6215 2009-03-30 13:28:25Z polle $
+ ** @author Michael Cahill
+ **
+ ** A filter for views - allows only certain parts of a view to be seen.
+ ** Used to implement BlueJ's "public", "package" and "inherited" views.
+ **/
+public final class ViewFilter
+{
+	public static final int PUBLIC = Modifier.PUBLIC;
+    public static final int PROTECTED = PUBLIC | Modifier.PROTECTED;
+	public static final int PACKAGE = PROTECTED | 0x10000;
+	public static final int PRIVATE = PACKAGE | Modifier.PRIVATE;
+	
+	public static final int STATIC = Modifier.STATIC;
+	public static final int INSTANCE = 0x20000;
+	
+	public static final int ABSTRACT = Modifier.ABSTRACT;
+	public static final int CONCRETE = 0x40000;
+	
+	static final int allbits = PRIVATE | STATIC | INSTANCE | ABSTRACT | CONCRETE;
+	
+	int modifiers;
+	
+	public ViewFilter(int modifiers)
+	{
+		if(((modifiers & STATIC) == 0) && ((modifiers & INSTANCE) == 0))
+			modifiers |= STATIC | INSTANCE;
+			
+		if(((modifiers & ABSTRACT) == 0) && ((modifiers & CONCRETE) == 0))
+			modifiers |= ABSTRACT | CONCRETE;
+			
+		this.modifiers = modifiers;
+	}
+	
+	public boolean accept(int othermods)
+	{
+		if((othermods & 7) == 0)
+			othermods |= 0x10000;
+		if((othermods & STATIC ) == 0)
+			othermods |= INSTANCE;
+			
+		return ((allbits & othermods & ~modifiers) == 0);
+	}
+	
+	public boolean accept(Member member)
+	{
+		return accept(member.getModifiers());
+	}
+	
+	public boolean accept(MemberView member)
+	{
+		return accept(member.getModifiers());
+	}
+}
diff --git a/Sd1/P/Maven/greenfoot/.gitignore b/Sd1/P/Maven/greenfoot/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..a1c3ab4d08c0f9f91918f21c730272a4711885e8
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/.gitignore
@@ -0,0 +1,4 @@
+/target/
+/.settings/
+.classpath
+.project
diff --git a/Sd1/P/Maven/greenfoot/pom.xml b/Sd1/P/Maven/greenfoot/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b950d32e9c0f41de0740f8b474bcf6dd73611966
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/pom.xml
@@ -0,0 +1,100 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>de.hdm-stuttgart.mi</groupId>
+	<artifactId>greenfoot</artifactId>
+	<version>2.3.0</version>
+	<packaging>jar</packaging>
+
+	<name>greenfoot</name>
+
+	<!--Fixme: Add a sensible project related domain here -->
+	<url>http://somedomain.org</url>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>de.hdm-stuttgart.mi</groupId>
+			<artifactId>bluej</artifactId>
+			<version>3.0.9</version>
+		</dependency>
+
+		<dependency>
+			<groupId>commons-logging</groupId>
+			<artifactId>commons-logging</artifactId>
+			<version>1.1.3</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-httpclient</groupId>
+			<artifactId>commons-httpclient</artifactId>
+			<version>3.1</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.opencsv</groupId>
+			<artifactId>opencsv</artifactId>
+			<version>2.3</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-codec</groupId>
+			<artifactId>commons-codec</artifactId>
+			<version>1.4</version>
+		</dependency>
+		<dependency>
+			<groupId>com.googlecode.soundlibs</groupId>
+			<artifactId>jlayer</artifactId>
+			<version>1.0.1-1</version>
+		</dependency>
+
+	</dependencies>
+
+	<build>
+		<plugins>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.1</version>
+				<configuration>
+					<source>1.8</source>
+					<target>1.8</target>
+				</configuration>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-javadoc-plugin</artifactId>
+				<version>2.10.1</version>
+				<configuration />
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-shade-plugin</artifactId>
+				<version>2.3</version>
+				<configuration>
+					<transformers>
+						<transformer
+							implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+							<manifestEntries>
+								<Main-Class>de.hdm_stuttgart.mi.greenfoot.App</Main-Class>
+							</manifestEntries>
+						</transformer>
+					</transformers>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>shade</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+
+		</plugins>
+	</build>
+</project>
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/Actor.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/Actor.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fa20c3f2e8724a99b1eb1ada9187f906113f943
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/Actor.java
@@ -0,0 +1,1070 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2013  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import greenfoot.collision.ibsp.Rect;
+import greenfoot.core.WorldHandler;
+import greenfoot.platforms.ActorDelegate;
+import greenfoot.util.GreenfootUtil;
+
+import java.util.List;
+
+/**
+ * An Actor is an object that exists in the Greenfoot world. 
+ * Every Actor has a location in the world, and an appearance (that is:
+ * an icon).
+ * 
+ * <p>An Actor is not normally instantiated, but instead used as a superclass
+ * to more specific objects in the world. Every object that is intended to appear
+ * in the world must extend Actor. Subclasses can then define their own
+ * appearance and behaviour.
+ * 
+ * <p>One of the most important aspects of this class is the 'act' method. This method
+ * is called when the 'Act' or 'Run' buttons are activated in the Greenfoot interface.
+ * The method here is empty, and subclasses normally provide their own implementations.
+ * 
+ * @author Poul Henriksen
+ * @version 2.5
+ */
+public abstract class Actor
+{
+    /** Error message to display when trying to use methods that requires a world. */
+    private static final String NO_WORLD = "An actor is trying to access the world, when no world has been instantiated.";
+
+    /** Error message to display when trying to use methods that requires the actor be in a world. */
+    private static final String ACTOR_NOT_IN_WORLD = "Actor not in world. An attempt was made to use the actor's location while it is not in the world. Either it has not yet been inserted, or it has been removed.";
+
+    /** Counter of number of actors constructed, used as a hash value */
+    private static int sequenceNumber = 0;
+
+    /**
+     * x-coordinate of the object's location in the world. The object is
+     * centered around this location.
+     */
+    int x;
+
+    /**
+     * y-coordinate of the object's location in the world. The object is
+     * centered around this location.
+     */
+    int y;
+
+    /**
+     * Sequence number of this actor
+     */
+    private int mySequenceNumber;
+
+    /**
+     * The last time objects in the world were painted, where was this object
+     * in the sequence?
+     */
+    private int lastPaintSequenceNumber;
+
+    /** Rotation in degrees (0-359) */
+    int rotation = 0;
+
+    /** Reference to the world that this actor is a part of. */
+    World world;
+
+    /** The image for this actor. */
+    private GreenfootImage image;
+
+    /** Field used to store some extra data in an object. Used by collision checkers. */
+    private Object data;
+
+    static GreenfootImage greenfootImage;
+
+    /** Axis-aligned bounding rectangle of the object, in pixels. */
+    private Rect boundingRect;
+    /** X-coordinates of the rotated bounding rectangle's corners */
+    private int[] boundingXs = new int[4];
+    /** Y-coordinates of the rotated bounding rectangle's corners */
+    private int[] boundingYs = new int[4];
+
+    static {
+        //Do this in a 'try' since a failure at this point will crash Greenfoot.
+        try {
+            greenfootImage = new GreenfootImage(GreenfootUtil.getGreenfootLogoPath());
+        }
+        catch (Exception e) {
+            // Should not happen unless the Greenfoot installation is seriously broken.
+            e.printStackTrace();
+            System.err.println("Greenfoot installation is broken - reinstalling Greenfoot might help.");
+        }
+    }
+
+    /**
+     * Construct an Actor.
+     * The object will have a default image.
+     */
+    public Actor()
+    {
+        // Use the class image, if one is defined, as the default image, or the
+        // Greenfoot logo image otherwise
+        mySequenceNumber = sequenceNumber++;
+        GreenfootImage image = getClassImage();
+        if (image == null) {
+            image = greenfootImage;
+        }
+
+        // Make the image a copy of the original to avoid modifications to the
+        // original.
+        image = image.getCopyOnWriteClone();
+
+        setImage(image);
+    }
+
+    /**
+     * The act method is called by the greenfoot framework to give actors a
+     * chance to perform some action. At each action step in the environment,
+     * each object's act method is invoked, in unspecified order.
+     * 
+     * <p>The default implementation does nothing. This method should be overridden in
+     * subclasses to implement an actor's action.
+     */
+    public void act()
+    {
+    }
+
+    /**
+     * Return the x-coordinate of the actor's current location. The
+     * value returned is the horizontal index of the actor's cell in the world.
+     * 
+     * @return The x-coordinate of the object's current location.
+     * @throws IllegalStateException If the actor has not been added into a world.
+     */
+    public int getX() throws IllegalStateException
+    {
+        failIfNotInWorld();
+        return x;
+    }
+
+    /**
+     * Return the y-coordinate of the object's current location. The
+     * value returned is the vertical index of the actor's cell in the world.
+     * 
+     * @return The y-coordinate of the actor's current location
+     * @throws IllegalStateException If the actor has not been added into a world.
+     */
+    public int getY()
+    {
+        failIfNotInWorld();
+        return y;
+    }
+
+    /**
+     * Return the current rotation of this actor. Rotation is expressed as a degree
+     * value, range (0..359). Zero degrees is towards the east (right-hand side of
+     * the world), and the angle increases clockwise.
+     * 
+     * @see #setRotation(int)
+     * 
+     * @return The rotation in degrees.
+     */
+    public int getRotation()
+    {
+        return rotation;
+    }
+
+    /**
+     * Set the rotation of this actor. Rotation is expressed as a degree
+     * value, range (0..359). Zero degrees is to the east (right-hand side of the
+     * world), and the angle increases clockwise.
+     * 
+     * @param rotation The rotation in degrees.
+     * 
+     * @see #turn(int)
+     */
+    public void setRotation(int rotation)
+    {
+        // First normalize
+        if (rotation >= 360) {
+            // Optimize the usual case: rotation has adjusted to a value greater than
+            // 360, but is still within the 360 - 720 bound.
+            if (rotation < 720) {
+                rotation -= 360;
+            }
+            else {
+                rotation = rotation % 360;
+            }
+        }
+        else if (rotation < 0) {
+            // Likwise, if less than 0, it's likely that the rotation was reduced by
+            // a small amount and so will be >= -360.
+            if (rotation >= -360) {
+                rotation += 360;
+            }
+            else {
+                rotation = 360 + (rotation % 360);
+            }
+        }
+        
+        if (this.rotation != rotation) {
+            this.rotation = rotation;
+            // Recalculate the bounding rect.
+            boundingRect = null;
+            // since the rotation have changed, the size probably has too.
+            sizeChanged();
+        }
+    }
+    
+    /**
+     * Turn this actor to face towards a certain location.
+     * 
+     * @param x  The x-coordinate of the cell to turn towards
+     * @param y  The y-coordinate of the cell to turn towards
+     */
+    public void turnTowards(int x, int y)
+    {
+        double a = Math.atan2(y - this.y, x - this.x);
+        setRotation((int) Math.toDegrees(a));
+    }
+
+    /**
+     * Assign a new location for this actor. This moves the actor to the specified
+     * location. The location is specified as the coordinates of a cell in the world.
+     * 
+     * <p>If this method is overridden it is important to call this method as
+     * "super.setLocation(x,y)" from the overriding method, to avoid infinite recursion.
+     * 
+     * @param x Location index on the x-axis
+     * @param y Location index on the y-axis
+     * 
+     * @see #move(int)
+     */
+    public void setLocation(int x, int y)
+    {
+        setLocationDrag(x, y);
+    }
+    
+    /**
+     * Move this actor the specified distance in the direction it is
+     * currently facing.
+     * 
+     * <p>The direction can be set using the {@link #setRotation(int)} method.
+     * 
+     * @param distance  The distance to move (in cell-size units); a negative value
+     *                  will move backwards
+     * 
+     * @see #setLocation(int, int)
+     */
+    public void move(int distance)
+    {
+        double radians = Math.toRadians(rotation);
+
+        // We round to the nearest integer, to allow moving one unit at an angle
+        // to actually move.
+        int dx = (int) Math.round(Math.cos(radians) * distance);
+        int dy = (int) Math.round(Math.sin(radians) * distance);
+        setLocation(x + dx, y + dy);
+    }
+    
+    /**
+     * Turn this actor by the specified amount (in degrees).
+     * 
+     * @param amount  the number of degrees to turn; positive values turn clockwise
+     * 
+     * @see #setRotation(int)
+     */
+    public void turn(int amount)
+    {
+        setRotation(rotation + amount);
+    }
+    
+    /**
+     * The implementation of setLocation.  The main reason for the existence of this method
+     * (rather than inlining it into setLocation) is that setLocation can
+     * be overridden.  We make sure that setLocationInPixels (used during dragging)
+     * always calls this method (setLocationDrag) so that it never calls the 
+     * potentially-overridden setLocation method.
+     * 
+     * <p>setLocation is then called once after the drag, by WorldHandler, so that actors
+     * that do override setLocation only see the method called once at the end of the drag
+     * (even though the stored location is changing during the drag). 
+     */
+    private void setLocationDrag(int x, int y)
+    {
+        // Note this should not call user code - because it is called off the
+        // simulation thread. We must access world fields (width, height, cellSize) directly.
+        
+        if (world != null) {
+            int oldX = this.x;
+            int oldY = this.y;
+
+            if (world.isBounded()) {
+                this.x = limitValue(x, world.width);
+                this.y = limitValue(y, world.height);
+            }
+            else {
+                this.x = x;
+                this.y = y;
+            }
+
+            if (this.x != oldX || this.y != oldY) {
+                if (boundingRect != null) {
+                    int dx = (this.x - oldX) * world.cellSize;
+                    int dy = (this.y - oldY) * world.cellSize;
+
+                    boundingRect.setX(boundingRect.getX() + dx);
+                    boundingRect.setY(boundingRect.getY() + dy);
+
+                    for (int i = 0; i < 4; i++) {
+                        boundingXs[i] += dx;
+                        boundingYs[i] += dy;
+                    }
+                }
+                locationChanged(oldX, oldY);
+            }
+        }
+    }
+
+    /**
+     * Limits the value v to be less than limit and large or equal to zero.
+     */
+    private int limitValue(int v, int limit)
+    {
+        if (v < 0) {
+            v = 0;
+        }
+        if (limit <= v) {
+            v = limit - 1;
+        }
+        return v;
+    }
+
+    /**
+     * Return the world that this actor lives in.
+     * 
+     * @return The world.
+     */
+    public World getWorld()
+    {
+        return world;
+    }
+
+    /**
+     * This method is called by the Greenfoot system when this actor has
+     * been inserted into the world. This method can be overridden to implement
+     * custom behaviour when the actor is inserted into the world.
+     * <p>
+     * The default implementation does nothing.
+     * 
+     * @param world The world the object was added to.
+     */
+    protected void addedToWorld(World world)
+    {}
+
+    /**
+     * Returns the image used to represent this actor. This image can be
+     * modified to change the actor's appearance.
+     * 
+     * @return The object's image.
+     */
+    public GreenfootImage getImage()
+    {
+        return image;
+    }
+
+    /**
+     * Set an image for this actor from an image file. The file may be in
+     * jpeg, gif or png format. The file should be located in the project
+     * directory.
+     * 
+     * @param filename The name of the image file.
+     * @throws IllegalArgumentException If the image can not be loaded.
+     */
+    public void setImage(String filename) throws IllegalArgumentException
+    {
+        setImage(new GreenfootImage(filename));
+    }
+
+    /**
+     * Set the image for this actor to the specified image.
+     * 
+     * @see #setImage(String)
+     * @param image The image.
+     */
+    public void setImage(GreenfootImage image)
+    {
+        if (image == null && this.image == null) {
+            return;
+        }
+
+        boolean sizeChanged = true;
+
+        if (image != null && this.image != null) {
+            if (image.getWidth() == this.image.getWidth() && image.getHeight() == this.image.getHeight()) {
+                sizeChanged = false;
+            }
+        }
+
+        this.image = image;
+
+        if (sizeChanged) {
+            boundingRect = null;
+            sizeChanged();
+        }
+    }
+
+    // ==================================
+    //
+    // PACKAGE PROTECTED METHODS
+    //
+    // ==================================
+    
+    /**
+     * 
+     * Translates the given location into cell-coordinates before setting the
+     * location.
+     * 
+     * Used by the WorldHandler to drag objects.
+     * 
+     * @param x x-coordinate in pixels
+     * @param y y-coordinate in pixels
+     */
+    void setLocationInPixels(int x, int y)
+    {
+        int xCell = world.toCellFloor(x);
+        int yCell = world.toCellFloor(y);
+
+        if (xCell == this.x && yCell == this.y) {
+            return;
+        }
+
+        setLocationDrag(xCell, yCell);
+    }
+
+    /**
+     * Sets the world of this actor.
+     * 
+     * @param world
+     */
+    void setWorld(World world)
+    {
+        this.world = world;
+    }
+
+    /**
+     * Sets the world, and the initial location. The location is adjusted according to the world's bounding
+     * rules. The cached collision checking bounds, if any, are cleared.
+     */
+    void addToWorld(int x, int y, World world)
+    {
+        if (world.isBounded()) {
+            x = limitValue(x, world.getWidth());
+            y = limitValue(y, world.getHeight());
+        }
+        
+        this.x = x;
+        this.y = y;
+        boundingRect = null;
+
+        this.setWorld(world);
+        
+        // This call is not necessary, however setLocation may be overridden
+        // so it must still be called. (Asteroids scenario relies on setLocation
+        // being called when the object is added to the world...)
+        this.setLocation(x, y);
+    }
+
+    /**
+     * Get the axis-aligned bounding rectangle of the object, taking rotation into account.
+     * This returns a rectangle which completely covers the rotated actor's area.
+     * 
+     * @return A rect specified in pixels!
+     */
+    Rect getBoundingRect() 
+    {
+        if (boundingRect == null) {
+            calcBounds();
+        }
+        return boundingRect;
+    }
+
+    /**
+     * Calculates the bounds.
+     */
+    private void calcBounds()
+    {        
+        World w = getActiveWorld();
+        if(w == null) {
+            return;
+        }
+        int cellSize = w.getCellSize();
+        
+        if (image == null) {
+            int wx = x * cellSize + cellSize / 2;
+            int wy = y * cellSize + cellSize / 2;
+            boundingRect = new Rect(wx, wy, 0, 0);
+            for (int i = 0; i < 4; i++) {
+                boundingXs[i] = wx;
+                boundingYs[i] = wy;
+            }
+            return;
+        }
+        
+        if (rotation % 90 == 0) {
+            // Special fast calculation when rotated a multiple of 90
+            int width = 0;
+            int height = 0;
+            
+            if(rotation % 180 == 0) {
+                // Rotated by 180 multiple
+                width = image.getWidth();
+                height = image.getHeight();
+            } else {
+                // Swaps width and height since image is rotated by 90 (+/- multiple of 180)
+                width = image.getHeight();
+                height = image.getWidth();                
+            }
+            
+            int x = cellSize * this.x + (cellSize - width - 1) / 2;
+            int y = cellSize * this.y + (cellSize - height - 1) / 2;
+            boundingRect = new Rect(x, y, width, height);
+            boundingXs[0] = x; boundingYs[0] = y;
+            boundingXs[1] = x + width - 1; boundingYs[1] = y;
+            boundingXs[2] = boundingXs[1]; boundingYs[2] = y + height - 1;
+            boundingXs[3] = x; boundingYs[3] = boundingYs[2];
+        }
+        else {
+            getRotatedCorners(boundingXs, boundingYs, cellSize);
+            
+            int minX = Integer.MAX_VALUE;
+            int maxX = Integer.MIN_VALUE;
+            int minY = Integer.MAX_VALUE;
+            int maxY = Integer.MIN_VALUE;
+            
+            for (int i = 0; i < 4; i++) {
+                minX = Math.min(boundingXs[i] - 1, minX);
+                maxX = Math.max(boundingXs[i] + 1, maxX);
+                minY = Math.min(boundingYs[i] - 1, minY);
+                maxY = Math.max(boundingYs[i] + 1, maxY);
+            }
+            
+            // This rect will be bit big to include all pixels that are covered.
+            // We lose a bit of precision by using integers and might get
+            // collisions that wouldn't be there if using floating point. But
+            // making it a big bigger, we will get all the collision that we
+            // would get with floating point.
+            // For instance, if something has the width 28.2, it might cover 30
+            // pixels.
+            boundingRect = new Rect(minX, minY, maxX - minX + 1, maxY - minY + 1);
+        }
+    }
+
+    /**
+     * Set collision-checker-private data for this actor.
+     */
+    void setData(Object o)
+    {
+        this.data = o;
+    }
+    
+    /**
+     * Get the collision-checker-private data for this actor.
+     * @return
+     */
+    Object getData()
+    {
+        return data;
+    }
+    
+    /**
+     * Translate a cell coordinate into a pixel. This will return the coordinate of the centre of he cell.
+     */
+    int toPixel(int x)
+    {        
+        World aWorld = getActiveWorld();
+        if(aWorld == null) {
+            // Should never happen
+            throw new IllegalStateException(NO_WORLD);
+        }
+        return x * aWorld.getCellSize() +  aWorld.getCellSize()/2;
+    }
+
+    
+    // ============================
+    //
+    // Private methods
+    //
+    // ============================
+    
+    /**
+     * Get the default image for objects of this class. May return null.
+     */
+    private GreenfootImage getClassImage()
+    {
+        Class<?> clazz = getClass();
+        while (clazz != null) {
+            GreenfootImage image = null;
+            try {
+                image = getImage(clazz);
+            }
+            catch (Throwable e) {
+                // Ignore exception and continue looking for images
+            }
+            if (image != null) {
+                return image;
+            }
+            clazz = clazz.getSuperclass();
+        }
+
+        return greenfootImage;
+    }
+    
+
+    /**
+     * Notify the world that this object's size has changed, if it in fact has changed.
+     */
+    private void sizeChanged()
+    {
+        if(world != null) {
+            world.updateObjectSize(this);
+        }
+    }   
+
+    /**
+     * Notify the world that this object's location has changed.
+     */
+    private void locationChanged(int oldX, int oldY)
+    {
+        if(world != null) {
+            world.updateObjectLocation(this, oldX, oldY);
+        }
+    }
+    
+    /**
+     * Throws an exception if the actor is not in a world.
+     * 
+     * @throws IllegalStateException If not in world.
+     */
+    private void failIfNotInWorld()
+    {
+        if(world == null) {
+            throw new IllegalStateException(ACTOR_NOT_IN_WORLD);
+        }
+    }
+    
+    /**
+     * Calculated the co-ordinates of the bounding rectangle after it is rotated
+     * and translated for the actor position, in pixels.
+     * 
+     * @param xs  The array to hold the four X coordinates
+     * @param ys  The array to hold the four Y coordinates
+     * @param cellSize  The world cell size
+     */
+    private void getRotatedCorners(int [] xs, int [] ys, int cellSize)
+    {
+        int width = image.getWidth();
+        int height = image.getHeight();
+        
+        xs[0] = -width / 2;
+        xs[1] = xs[0] + width - 1;
+        xs[2] = xs[1];
+        xs[3] = xs[0];
+        
+        ys[0] = -height / 2;
+        ys[1] = ys[0];
+        ys[2] = ys[1] + height - 1;
+        ys[3] = ys[2];
+        
+        double rotR = Math.toRadians(rotation);
+        double sinR = Math.sin(rotR);
+        double cosR = Math.cos(rotR);
+        
+        double xc = cellSize * x + cellSize / 2.;
+        double yc = cellSize * y + cellSize / 2.;
+        
+        // Do the actual rotation
+        for (int i = 0; i < 4; i++) {
+            int nx = (int)(xs[i] * cosR - ys[i] * sinR + xc);
+            int ny = (int)(ys[i] * cosR + xs[i] * sinR + yc);
+            xs[i] = nx;
+            ys[i] = ny;
+        }
+    }
+
+    /**
+     * Check whether all of the vertexes in the "other" rotated rectangle are on the
+     * outside of any one of the edges in "my" rotated rectangle.
+     *  
+     * @param myX   The x-coordinates of the corners of "my" rotated rectangle
+     * @param myY    The y-coordinates of the corners "my" rotated rectangle
+     * @param otherX  The x-coordinates of the corners of the "other" rotated rectangle
+     * @param otherY  The y-coordinates of the corners of the "other" rotated rectangle
+     * 
+     * @return  true if all corners of the "other" rectangle are on the outside of any of
+     *          the edges of "my" rectangle.
+     */
+    private static boolean checkOutside(int [] myX, int [] myY, int [] otherX, int [] otherY)
+    {
+        vloop:
+        for (int v = 0; v < 4; v++) {
+            int v1 = (v + 1) & 3; // wrap at 4 back to 0
+            int edgeX = myX[v] - myX[v1];
+            int edgeY = myY[v] - myY[v1];
+            int reX = -edgeY;
+            int reY = edgeX;
+            
+            if (reX == 0 && reY == 0) {
+                continue vloop;
+            }
+
+            for (int e = 0; e < 4; e++) {
+                int scalar = reX * (otherX[e] - myX[v1]) + reY * (otherY[e] - myY[v1]);
+                if (scalar < 0) {
+                    continue vloop;
+                }
+            }
+
+            // If we got here, we have an edge with all vertexes from the other rect
+            // on the outside:
+            return true;
+        }
+
+        return false;
+    }
+    
+    // ============================
+    //
+    // Collision stuff
+    //
+    // ============================
+
+    /**
+     * Check whether this object intersects with another given object.
+     * 
+     * @return True if the object's intersect, false otherwise.
+     */
+    protected boolean intersects(Actor other)
+    {
+        if (image == null) {
+            if (other.image == null) {
+                // No images; the actors can be considered to represent points,
+                // and we'll say they intersect if they match exactly.
+                return x == other.x && y == other.y;
+            }
+            
+            int cellSize = world.getCellSize();
+            
+            // We are a point, the other actor is a rect. Rotate our relative
+            return other.containsPoint(x * cellSize + cellSize / 2, y * cellSize + cellSize / 2);
+        }
+        else if (other.image == null) {
+            // We are a rectangle, the other is a point
+            int cellSize = world.getCellSize();
+            return containsPoint(other.x * cellSize + cellSize / 2, other.y * cellSize + cellSize / 2);
+        }
+        else {
+            Rect thisBounds = getBoundingRect();
+            Rect otherBounds = other.getBoundingRect();
+            if (rotation == 0 && other.rotation == 0) {
+                return thisBounds.intersects(otherBounds);
+            }
+            else {
+                // First do a check based only on axis-aligned bounding boxes.
+                if (! thisBounds.intersects(otherBounds)) {
+                    return false;
+                }
+                
+                int [] myX = boundingXs;
+                int [] myY = boundingYs;
+                int [] otherX = other.boundingXs;
+                int [] otherY = other.boundingYs;
+                
+                if (checkOutside(myX, myY, otherX, otherY)) {
+                    return false;
+                }
+                if (checkOutside(otherX, otherY, myX, myY)) {
+                    return false;
+                }
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * Return the neighbours to this object within a given distance. This
+     * method considers only logical location, ignoring extent of the image.
+     * Thus, it is most useful in scenarios where objects are contained in a
+     * single cell.
+     * <p>
+     * 
+     * All cells that can be reached in the number of steps given in 'distance'
+     * from this object are considered. Steps may be only in the four main
+     * directions, or may include diagonal steps, depending on the 'diagonal'
+     * parameter. Thus, a distance/diagonal specification of (1,false) will
+     * inspect four cells, (1,true) will inspect eight cells.
+     * <p>
+     * 
+     * @param distance Distance (in cells) in which to look for other objects.
+     * @param diagonal If true, include diagonal steps.
+     * @param cls Class of objects to look for (passing 'null' will find all
+     *            objects).
+     * @return A list of all neighbours found.
+     */
+    @SuppressWarnings("rawtypes")
+    protected List getNeighbours(int distance, boolean diagonal, Class cls)
+    {
+        failIfNotInWorld();
+        // Don't use getWorld() here, as it is overridable
+        return world.getNeighbours(this, distance, diagonal, cls);
+    }
+    
+    /**
+     * Return all objects that intersect the center of the given location (relative to
+     * this object's location). <br>
+     * 
+     * @return List of objects at the given offset. The list will include this
+     *         object, if the offset is zero.
+     * @param dx X-coordinate relative to this objects location.
+     * @param dy y-coordinate relative to this objects location.
+     * @param cls Class of objects to look for (passing 'null' will find all
+     *            objects).
+     */
+    @SuppressWarnings("rawtypes")
+    protected List getObjectsAtOffset(int dx, int dy, Class cls)
+    {
+        failIfNotInWorld();
+        return world.getObjectsAt(x + dx, y + dy, cls);
+    }
+
+    /**
+     * Return one object that is located at the specified cell (relative to this
+     * objects location). Objects found can be restricted to a specific class
+     * (and its subclasses) by supplying the 'cls' parameter. If more than one
+     * object of the specified class resides at that location, one of them will
+     * be chosen and returned.
+     * 
+     * @param dx X-coordinate relative to this objects location.
+     * @param dy y-coordinate relative to this objects location.
+     * @param cls Class of objects to look for (passing 'null' will find all objects).
+     * @return An object at the given location, or null if none found.
+     */
+    @SuppressWarnings("rawtypes")
+    protected Actor getOneObjectAtOffset(int dx, int dy, Class cls)
+    {
+        failIfNotInWorld();
+        return world.getOneObjectAt(this, x + dx, y + dy, cls);        
+    }
+    
+    /**
+     * Return all objects within range 'radius' around this object. 
+     * An object is within range if the distance between its centre and this
+     * object's centre is less than or equal to 'radius'.
+     * 
+     * @param radius Radius of the circle (in cells)
+     * @param cls Class of objects to look for (passing 'null' will find all objects).
+     */
+    @SuppressWarnings("rawtypes")
+    protected List getObjectsInRange(int radius, Class cls)
+    {
+        failIfNotInWorld();
+        List inRange = world.getObjectsInRange(x, y, radius, cls);
+        inRange.remove(this);
+        return inRange;
+    }
+
+    /**
+     * Return all the objects that intersect this object. This takes the
+     * graphical extent of objects into consideration. <br>
+     * 
+     * @param cls Class of objects to look for (passing 'null' will find all objects).
+     */
+    @SuppressWarnings("rawtypes")
+    protected List getIntersectingObjects(Class cls)
+    {
+        failIfNotInWorld();
+        List l = world.getIntersectingObjects(this, cls);
+        l.remove(this);
+        return l;
+    }
+    
+    /**
+     * Return an object that intersects this object. This takes the
+     * graphical extent of objects into consideration. <br>
+     * 
+     * @param cls Class of objects to look for (passing 'null' will find all objects).
+     */
+    @SuppressWarnings("rawtypes")
+    protected Actor getOneIntersectingObject(Class cls)
+    {
+        failIfNotInWorld();
+        return world.getOneIntersectingObject(this, cls);
+    }
+    
+    /**
+     * Checks whether this actor is touching any other objects
+     * of the given class.
+     * 
+     * @param cls Class of objects to look for (passing 'null' will check for all actors).
+     */
+    @SuppressWarnings("rawtypes")
+    protected boolean isTouching(Class cls)
+    {
+        failIfNotInWorld();
+        return getOneIntersectingObject(cls) != null;
+    }
+    
+    /**
+     * Removes one object of the given class that this actor is
+     * currently touching (if any exist). 
+     * 
+     * @param cls Class of objects to remove (passing 'null' will remove any actor).
+     */
+    @SuppressWarnings("rawtypes")
+    protected void removeTouching(Class cls)
+    {
+        failIfNotInWorld();
+        Actor a = getOneIntersectingObject(cls);
+        if (a != null)
+        {
+            world.removeObject(a);
+        }
+    }
+    
+    /**
+     * Checks whether the specified point (specified in pixel co-ordinates) is within the area
+     * covered by the (rotated) graphical representation of this actor.
+     * 
+     * @param px  The (world relative) x pixel co-ordinate
+     * @param py  The (world relative) y pixel co-ordinate
+     * @return  true if the pixel is within the actor's bounds; false otherwise
+     */
+    boolean containsPoint(int px, int py)
+    {
+        failIfNotInWorld();
+        if (image == null) {
+            return false;
+        }
+
+        if (boundingRect == null) {
+            calcBounds(); // Make sure bounds are up-to-date
+        }
+        
+        if (rotation == 0 || rotation == 90 || rotation == 270) {
+            // We can just check the bounding rectangle
+            return (px >= boundingRect.getX() && px < boundingRect.getRight()
+                    && py >= boundingRect.getY() && py < boundingRect.getTop());
+        }
+        
+        vloop: for (int v = 0; v < 4; v++) {
+            int v1 = (v + 1) & 3; // wrap at 4 back to 0
+            int edgeX = boundingXs[v] - boundingXs[v1];
+            int edgeY = boundingYs[v] - boundingYs[v1];
+            int reX = -edgeY;
+            int reY = edgeX;
+
+            if (reX == 0 && reY == 0) {
+                continue vloop;
+            }
+
+            int scalar = reX * (px - boundingXs[v1]) + reY * (py - boundingYs[v1]);
+            if (scalar < 0) {
+                continue vloop;
+            }
+
+            // If we got here, we have an edge with all vertexes from the other rect
+            // on the outside:
+            return false;
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Get the sequence number of this actor. This can be used as a
+     * hash value, which is not overridable by the user.
+     */
+    final int getSequenceNumber()
+    {
+        return mySequenceNumber;
+    }
+
+    /**
+     * Get the sequence number of this actor from the last paint operation.
+     * (Returns whatever was set using the setLastPaintSeqNum method).
+     */
+    final int getLastPaintSeqNum()
+    {
+        return lastPaintSequenceNumber;
+    }
+    
+    /**
+     * Set the sequence number of this actor from the last paint operation.
+     */
+    final void setLastPaintSeqNum(int num)
+    {
+        lastPaintSequenceNumber = num;
+    }
+    
+    // ============================================================================
+    //  
+    // Methods below here are delegated to different objects depending on how
+    // the project is run.
+    // (From Greenfoot IDE or StandAlone)
+    //  
+    // ============================================================================
+
+    private static ActorDelegate delegate;
+    
+    /**
+     * Set the object that this actor should delegate method calls to.
+     *
+     */
+    static void setDelegate(ActorDelegate d)
+    {
+        delegate = d;
+    }
+    
+    static ActorDelegate getDelegate()
+    {
+        return delegate;
+    }
+    
+    /**
+     * Get the default image for objects of this class. May return null.
+     */
+    GreenfootImage getImage(Class<?> clazz)
+    {
+        return delegate.getImage(clazz.getName());
+    }
+
+    /**
+     * Get the active world. This method will return the instantiated world,
+     * even if the object is not yet added to a world.
+     */
+    World getActiveWorld()
+    {
+        if(world != null) {
+            return world;
+        }
+        WorldHandler handler = WorldHandler.getInstance();
+        if (handler != null) {
+            return handler.getWorld();
+        }
+        else {
+            return null;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ActorSet.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ActorSet.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f2171d7996cb1e36efbd017fa8154b954207764
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ActorSet.java
@@ -0,0 +1,304 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import java.util.AbstractSet;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * This is an ordered set. 
+ * 
+ * @author Davin McCall
+ */
+public class ActorSet extends AbstractSet<Actor>
+{
+    @Override
+  public Spliterator<Actor> spliterator() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public boolean removeIf(Predicate<? super Actor> filter) {
+    // TODO Auto-generated method stub
+    return false;
+  }
+
+  @Override
+  public Stream<Actor> stream() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Stream<Actor> parallelStream() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void forEach(Consumer<? super Actor> action) {
+    // TODO Auto-generated method stub
+    
+  }
+
+    private ListNode listHeadTail = new ListNode();
+    
+    private ListNode [] hashMap = new ListNode[0];
+    
+    private int numActors = 0;
+    
+    /** Sum of sequence numbers of contained actors */
+    private int myHashCode = 0;
+    
+    
+    @Override
+    public int hashCode()
+    {
+        return myHashCode;
+    }
+    
+    public boolean add(Actor actor)
+    {
+        if (contains(actor)) {
+            return false;
+        }
+        
+        numActors++;
+        ListNode newNode = new ListNode(actor, listHeadTail.prev);
+        
+        int seq = ActorVisitor.getSequenceNumber(actor);
+        if (numActors >= 2 * hashMap.length) {
+            // grow the hashmap
+            resizeHashmap();
+        }
+        else {
+            int hash = seq % hashMap.length;
+            ListNode hashHead = hashMap[hash];
+            hashMap[hash] = newNode;
+            newNode.setHashListHead(hashHead);
+        }
+        
+        myHashCode += seq;
+        return true;
+    }
+
+    private void resizeHashmap()
+    {
+        hashMap = new ListNode[numActors];
+        ListNode currentActor = listHeadTail.next;
+        while (currentActor != listHeadTail) {
+            int seq = ActorVisitor.getSequenceNumber(currentActor.actor);
+            int hash = seq % numActors;
+            ListNode hashHead = hashMap[hash];
+            hashMap[hash] = currentActor;
+            currentActor.setHashListHead(hashHead);
+            
+            currentActor = currentActor.next;
+        }
+    }
+    
+    public boolean contains(Actor actor)
+    {
+        return getActorNode(actor) != null; 
+    }
+    
+    @Override
+    public boolean contains(Object o)
+    {
+        if (o instanceof Actor) {
+            Actor a = (Actor) o;
+            return contains(a);
+        }
+        return false;
+    }
+    
+    /**
+     * Get the list node for an actor (null if the actor is not in the set).
+     */
+    private ListNode getActorNode(Actor actor)
+    {
+        if (hashMap.length == 0) {
+            return null;
+        }
+        
+        int seq = ActorVisitor.getSequenceNumber(actor);
+        int hash = seq % hashMap.length;
+        ListNode hashHead = hashMap[hash];
+        
+        if (hashHead == null) {
+            return null;
+        }
+        else if (hashHead.actor == actor) {
+            return hashHead;
+        }
+        
+        ListNode curNode = hashHead.nextHash;
+        while (curNode != hashHead) {
+            if (curNode.actor == actor) {
+                return curNode;
+            }
+            curNode = curNode.nextHash;
+        }
+        
+        return null;
+    }
+    
+    public boolean remove(Actor actor)
+    {
+        ListNode actorNode = getActorNode(actor);
+        
+        if (actorNode != null) {
+            remove(actorNode);
+            myHashCode -= ActorVisitor.getSequenceNumber(actor);
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+    
+    private void remove(ListNode actorNode)
+    {
+        int seq = ActorVisitor.getSequenceNumber(actorNode.actor);
+        int hash = seq % hashMap.length;
+        if (hashMap[hash] == actorNode) {
+            hashMap[hash] = actorNode.nextHash;
+            if (hashMap[hash] == actorNode) {
+                // The circular list had only one element
+                hashMap[hash] = null;
+            }
+        }
+        
+        actorNode.remove();
+        numActors--;
+        if (numActors <= hashMap.length / 2) {
+            // shrink the hashMap
+            resizeHashmap();
+        }
+    }
+    
+    public int size()
+    {
+        return numActors;
+    }
+    
+    @Override
+    public Iterator<Actor> iterator()
+    {
+        return new ActorSetIterator();
+    }
+    
+    private class ListNode
+    {
+        Actor actor;
+        ListNode next;
+        ListNode prev;
+        
+        // The node also appears in a linked list representing the hash bucket 
+        ListNode nextHash;
+        ListNode prevHash;
+        
+        public ListNode()
+        {
+            // actor, next, prev = null: this is the head/tail node
+            next = this;
+            prev = this;
+        }
+        
+        /**
+         * Create a new list node and insert it at the tail of the list.
+         * @param actor
+         * @param listTail
+         */
+        public ListNode(Actor actor, ListNode listTail)
+        {
+            this.actor = actor;
+            next = listTail.next;
+            prev = listTail;
+            listTail.next = this;
+            next.prev = this;
+        }
+        
+        /**
+         * Set this node as the new head node in a hash bucket list.
+         * @param oldHead  The original head node in the bucket
+         */
+        public void setHashListHead(ListNode oldHead)
+        {
+            if (oldHead == null) {
+                nextHash = this;
+                prevHash = this;
+            }
+            else {
+                nextHash = oldHead;
+                prevHash = oldHead.prevHash;
+                oldHead.prevHash = this;
+                prevHash.nextHash = this;
+            }
+        }
+        
+        public void remove()
+        {
+            next.prev = prev;
+            prev.next = next;
+            nextHash.prevHash = prevHash;
+            prevHash.nextHash = nextHash;
+        }
+    }
+    
+    private class ActorSetIterator implements Iterator<Actor>
+    {
+        @Override
+      public void forEachRemaining(Consumer<? super Actor> action) {
+        // TODO Auto-generated method stub
+        
+      }
+
+        ListNode currentNode;
+        
+        public ActorSetIterator()
+        {
+            currentNode = listHeadTail;
+        }
+        
+        public boolean hasNext()
+        {
+            return currentNode.next != listHeadTail;
+        }
+        
+        public Actor next()
+        {
+            currentNode = currentNode.next;
+            return currentNode.actor;
+        }
+        
+        public void remove()
+        {
+            ActorSet.this.remove(currentNode);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ActorVisitor.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ActorVisitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..274c38d1ada3dfd3b5d5ca2ea32db76a5d8cf286
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ActorVisitor.java
@@ -0,0 +1,166 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import greenfoot.collision.ibsp.Rect;
+import greenfoot.platforms.ActorDelegate;
+
+/**
+ * Class that makes it possible for classes outside the greenfoot package to get
+ * access to Actor methods that are package protected. We need some
+ * package-protected methods, because we don't want them to show up
+ * in the public interface visible to users.
+ * 
+ * @author Poul Henriksen 
+ */
+public class ActorVisitor
+{
+    public static void setLocationInPixels(Actor actor, int dragBeginX, int dragBeginY)
+    {
+        actor.setLocationInPixels(dragBeginX, dragBeginY);
+    }
+    
+    /**
+     * Get the X co-ordinate of an actor's position, in cells
+     */
+    public static int getX(Actor actor)
+    {
+        return actor.x;
+    }
+    
+    /**
+     * Get the Y co-ordinate of an actor's position, in cells
+     */
+    public static int getY(Actor actor)
+    {
+        return actor.y;
+    }
+    
+    /**
+     * Get the rotation of an actor, in degrees, from 0-359
+     */
+    public static int getRotation(Actor actor)
+    {
+        return actor.rotation;
+    }
+    
+    /**
+     * Get the world that an actor resides in (null if none).
+     */
+    public static World getWorld(Actor actor)
+    {
+        return actor.world;
+    }
+   
+    /**
+     * Checks whether the specified point (specified in pixel co-ordinates) is within the area
+     * covered by the (rotated) graphical representation of the given actor.
+     * 
+     * @param actor  The relevant actor
+     * @param px  The (world relative) x pixel co-ordinate
+     * @param py  The (world relative) y pixel co-ordinate
+     * @return  true if the pixel is within the actor's bounds; false otherwise
+     */
+    public static boolean containsPoint(Actor actor, int px, int py)
+    {
+        return actor.containsPoint(px, py);
+    }
+
+    public static boolean intersects(Actor actor, Actor other)
+    {
+        return actor.intersects(other);
+    }
+    
+    public static int toPixel(Actor actor, int x) 
+    {
+        return actor.toPixel(x);
+    }
+    
+    public static Rect getBoundingRect(Actor actor) 
+    {
+        return actor.getBoundingRect();
+    }
+    
+    public static void setData(Actor actor, Object n)
+    {
+        actor.setData(n);
+    }
+    
+    public static Object getData(Actor actor)
+    {
+        return actor.getData();
+    }
+    
+    /**
+     * Get the display image for an actor. This is the last image that was
+     * set using setImage(). The returned image should not be modified.
+     * 
+     * @param actor  The actor whose display image to retrieve
+     */
+    public static GreenfootImage getDisplayImage(Actor actor)
+    {
+        return actor.getImage();
+    }
+
+    /**
+     * Get a drag image for the actor. Normally this delegates to
+     * Actor.getImage(), but it will return the greenfoot logo image
+     * if that returns null.
+     */
+    public static GreenfootImage getDragImage(Actor actor)
+    {
+        GreenfootImage image = actor.getImage();
+        if (image == null) {
+            image = Actor.greenfootImage;
+        }
+        return image;
+    }
+    
+    public static void setDelegate(ActorDelegate instance)
+    {
+        Actor.setDelegate(instance);
+    }
+    
+    public static int getSequenceNumber(Actor actor)
+    {
+        return actor.getSequenceNumber();
+    }
+    
+    /**
+     * Get the sequence number of the given actor from the last paint
+     * operation on the world. (Returns whatever was set using the
+     * setLastPaintSeqNum method).
+     */
+    public static int getLastPaintSeqNum(Actor actor)
+    {
+        return actor.getLastPaintSeqNum();
+    }
+    
+    /**
+     * Set the sequence number of the given actor from the last paint
+     * operation on the world.
+     */
+    public static void setLastPaintSeqNum(Actor actor, int num)
+    {
+        actor.setLastPaintSeqNum(num);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/Greenfoot.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/Greenfoot.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c7afb6c9785fff665acb7e4912a3e94be68b261
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/Greenfoot.java
@@ -0,0 +1,292 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import java.util.Random;
+
+import greenfoot.core.Simulation;
+import greenfoot.core.WorldHandler;
+import greenfoot.sound.MicLevelGrabber;
+import greenfoot.sound.Sound;
+import greenfoot.sound.SoundFactory;
+
+
+/**
+ * This utility class provides methods to control the simulation
+ * and interact with the system.
+ * 
+ * <h3>Key names</h3>
+ * 
+ * <p>Part of the functionality provided by this class is the ability to
+ * retrieve keyboard input. The methods getKey() and isKeyDown() are used
+ * for this and they return/understand the following key names:
+ * 
+ * <ul>
+ * <li>"a", "b", .., "z" (alphabetical keys), "0".."9" (digits), most
+ *     punctuation marks. getKey() also returns uppercase characters when
+ *     appropriate.
+ * <li>"up", "down", "left", "right" (the cursor keys)
+ * <li>"enter", "space", "tab", "escape", "backspace", "shift", "control"
+ * <li>"F1", "F2", .., "F12" (the function keys)
+ * </ul>
+ * 
+ * @author Davin McCall
+ * @version 2.4
+ */
+public class Greenfoot
+{
+
+    private static Random randomGenerator = new Random();
+
+    /**
+     * Sets the World to run to the one given.
+     * This World will now be the main World that Greenfoot runs with on the
+     * next act.
+     *
+     * @param world The World to switch running to, cannot be null.
+     */
+    public static void setWorld(World world)
+    {
+        if ( world == null ) {
+            throw new NullPointerException("The given world cannot be null.");
+        }
+
+        WorldHandler.getInstance().setWorld( world );
+    }
+
+    /**
+     * Get the most recently pressed key, since the last time this method was
+     * called. If no key was pressed since this method was last called, it
+     * will return null. If more than one key was pressed, this returns only
+     * the most recently pressed key.
+     * 
+     * @return  The name of the most recently pressed key
+     */
+    public static String getKey()
+    {
+        return WorldHandler.getInstance().getKeyboardManager().getKey();
+    }
+    
+    /**
+     * Check whether a given key is currently pressed down.
+     * 
+     * @param keyName  The name of the key to check
+     * @return         True if the key is down
+     */
+    public static boolean isKeyDown(String keyName)
+    {
+        return WorldHandler.getInstance().getKeyboardManager().isKeyDown(keyName);
+    }
+    
+    /**
+     * Delay the current execution by a number of time steps. 
+     * The size of one time step is defined by the Greenfoot environment (the speed slider).
+     * 
+     * @see #setSpeed(int)
+     */
+    public static void delay(int time)
+    {
+        for(int i=0; i < time; i++) {
+            WorldHandler.getInstance().repaint();
+            Simulation.getInstance().sleep();
+        }
+    }
+    
+    /**
+     * Set the speed of the execution.
+     *  
+     * @param speed  The new speed. the value must be in the range (1..100)
+     */
+    public static void setSpeed(int speed)
+    {
+        Simulation.getInstance().setSpeed(speed);
+    }
+    
+    /**
+     * Pause the execution.
+     */
+    public static void stop()
+    {
+        Simulation.getInstance().setPaused(true);
+    }
+    
+    /**
+     * Run (or resume) the execution.
+     */
+    public static void start()
+    {
+        Simulation.getInstance().setPaused(false);
+    }
+    
+    /**
+     * Return a random number between 0 (inclusive) and limit (exclusive).
+     */
+    public static int getRandomNumber(int limit)
+    {
+        return randomGenerator.nextInt(limit);
+    }
+
+    /**
+     * Play sound from a file. The following formats are supported: AIFF, AU and
+     * WAV.
+     * <p>
+     * The file name may be an absolute path, a base name for a file located in
+     * the project directory or in the sounds directory of the project
+     * directory.
+     * 
+     * @param soundFile Typically the name of a file in the sounds directory in
+     *            the project directory.
+     * @throws IllegalArgumentException If the sound can not be loaded.
+     */
+    public static void playSound(final String soundFile)
+    {
+        Sound sound = SoundFactory.getInstance().createSound(soundFile, false);
+
+        if( sound != null) {
+            sound.play();
+        }
+    }
+
+
+    /**
+     * True if the mouse has been pressed (changed from a non-pressed state to
+     * being pressed) on the given object. If the parameter is an Actor the
+     * method will only return true if the mouse has been pressed on the given
+     * actor. If there are several actors at the same place, only the top most
+     * actor will receive the press. 
+     * If the parameter is a World then true will be returned if the mouse was
+     * pressed on the world background. If the parameter is null,
+     * then true will be returned for any mouse press, independent of the target 
+     * pressed on.
+     * 
+     * @param obj Typically one of Actor, World or null
+     * @return True if the mouse has been pressed as explained above
+     */
+    public static boolean mousePressed(Object obj)
+    {
+        return WorldHandler.getInstance().getMouseManager().isMousePressed(obj);
+    }
+
+    /**
+     * True if the mouse has been clicked (pressed and released) on the given
+     * object. If the parameter is an Actor the method will only return true if
+     * the mouse has been clicked on the given actor. If there are several
+     * actors at the same place, only the top most actor will receive the click.
+     * If the parameter is a World then true will be returned if the mouse was
+     * clicked on the world background. If the parameter is null,
+     * then true will be returned for any click, independent of the target 
+     * clicked on.
+     * 
+     * @param obj Typically one of Actor, World or null
+     * @return True if the mouse has been clicked as explained above
+     */
+    public static boolean mouseClicked(Object obj)
+    {
+        return WorldHandler.getInstance().getMouseManager().isMouseClicked(obj);
+    }
+
+    /**
+     * True if the mouse is currently being dragged on the given object. The mouse is
+     * considered to be dragged on an object if the drag started on that
+     * object - even if the mouse has since been moved outside of that object.
+     * <p>
+     * If the parameter is an Actor the method will only return true if the drag
+     * started on the given actor. If there are several actors at the same
+     * place, only the top most actor will receive the drag. 
+     * If the parameter is a World then true will be returned if the drag action
+     * was started on the world background. If the parameter is null,
+     * then true will be returned for any drag action, independent of the target 
+     * clicked on.
+     * 
+     * @param obj Typically one of Actor, World or null
+     * @return True if the mouse has been dragged as explained above
+     */
+    public static boolean mouseDragged(Object obj)
+    {
+        return WorldHandler.getInstance().getMouseManager().isMouseDragged(obj);
+    }
+
+    /**
+     * True if a mouse drag has ended. This happens when the mouse has been
+     * dragged and the mouse button released.
+     * <p>
+     * If the parameter is an Actor the method will only return true if the drag
+     * started on the given actor. If there are several actors at the same
+     * place, only the top most actor will receive the drag. 
+     * If the parameter is a World then true will be returned if the drag action
+     * was started on the world background. If the parameter is null,
+     * then true will be returned for any drag action, independent of the target 
+     * clicked on.
+     * 
+     * @param obj
+     *            Typically one of Actor, World or null
+     * @return True if the mouse has been dragged as explained above
+     */
+    public static boolean mouseDragEnded(Object obj)
+    {
+        return WorldHandler.getInstance().getMouseManager().isMouseDragEnded(obj);
+    }
+
+    /**
+     * True if the mouse has been moved on the given object. The mouse is
+     * considered to be moved on an object if the mouse pointer is above
+     * that object.
+     * <p>
+     * If the parameter is an Actor the method will only return true if the move
+     * is on the given actor. If there are several actors at the same
+     * place, only the top most actor will receive the move. 
+     * If the parameter is a World then true will be returned if the move
+     * was on the world background. If the parameter is null,
+     * then true will be returned for any move, independent of the target 
+     * under the move location.
+     * 
+     * @param obj Typically one of Actor, World or null
+     * @return True if the mouse has been moved as explained above
+     */
+    public static boolean mouseMoved(Object obj)
+    {
+        return WorldHandler.getInstance().getMouseManager().isMouseMoved(obj);
+    }
+
+    /**
+     * Return a mouse info object with information about the state of the
+     * mouse.
+     * 
+     * @return The info about the current state of the mouse, or null if the mouse
+     *         cursor is outside the world boundary (unless being dragged).
+     */
+    public static MouseInfo getMouseInfo()
+    {
+        return WorldHandler.getInstance().getMouseManager().getMouseInfo();
+    }
+    
+    /**
+     * Get the microphone input level. This level is an approximation of the loudness
+     * any noise that is currently being received by the microphone.
+     * 
+     * @return The microphone input level (between 0 and 100, inclusive).
+     */
+    public static int getMicLevel()
+    {
+        return MicLevelGrabber.getInstance().getLevel();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/GreenfootImage.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/GreenfootImage.java
new file mode 100644
index 0000000000000000000000000000000000000000..473d9564320860ea403a5d2091b3820e7e14cc7b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/GreenfootImage.java
@@ -0,0 +1,898 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import greenfoot.util.GraphicsUtilities;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.MediaTracker;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
+import java.awt.image.VolatileImage;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+
+
+/**
+ * An image to be shown on screen. The image may be loaded from an image file
+ * and/or drawn by using various drawing methods.
+ * 
+ * @author Poul Henriksen
+ * @version 2.4
+ */
+public class GreenfootImage
+{
+    private static final Color DEFAULT_BACKGROUND = new Color(255,255,255,0);
+    private static final Color DEFAULT_FOREGROUND = Color.BLACK;
+    
+    /** The image name and url are primarily used for debugging. */
+    private String imageFileName;
+    private URL imageUrl;
+    
+    private BufferedImage image;
+    private static MediaTracker tracker;
+    
+    private Color currentColor = DEFAULT_FOREGROUND;
+    private Font currentFont;
+    
+    /**
+     * Copy on write is used for performance reasons. If an image is
+     * copyOnWrite, it means that the actual image data might be shared between
+     * several GreenfootImage instances. As soon as a copy-on-write GreenfootImage is
+     * modified, it is necessary to create a copy of the image, in order not to
+     * change the image for the rest of the GreenfootImages sharing this image.
+     * This flag is used to keep track of whether it is a shared image that
+     * needs to be copied upon write (changes) to the image.
+     */
+    private boolean copyOnWrite = false;
+    
+    /**
+     * Value from 0 to 255, with 0 being completely transparent and 255 being opaque.
+     */
+    private int transparency = 255;
+
+    /**
+     * Create an image from an image file. Supported file formats are JPEG, GIF
+     * and PNG.
+     * 
+     * <p>The file name may be an absolute path, or a base name for a file located in
+     * the project directory.
+     * 
+     * @param filename Typically the name of a file in the images directory within
+     *            the project directory.
+     * @throws IllegalArgumentException If the image can not be loaded.
+     */
+    public GreenfootImage(String filename)
+        throws IllegalArgumentException
+    {
+        GreenfootImage gImage = GreenfootUtil.getCachedImage(filename);
+        if (gImage != null)
+        {
+            createClone(gImage);
+        }
+        else 
+        {
+            try{
+                loadFile(filename);
+            }
+            catch(IllegalArgumentException ile){
+                GreenfootUtil.addCachedImage(filename, null);
+                throw ile;
+            }
+        }
+        //if the image was successfully cached, ensure that the image is copyOnWrite
+        boolean success = GreenfootUtil.addCachedImage(filename, new GreenfootImage(this));
+        if (success){
+            copyOnWrite = true;
+        }
+    }
+       
+    /**
+     * Create an empty (transparent) image with the specified size.
+     * 
+     * @param width The width of the image in pixels.
+     * @param height The height of the image in pixels.
+     */
+    public GreenfootImage(int width, int height)
+    {
+        setImage(GraphicsUtilities.createCompatibleTranslucentImage(width, height));
+    }
+
+    /**
+     * Create a GreenfootImage from another GreenfootImage.
+     */
+    public GreenfootImage(GreenfootImage image)
+        throws IllegalArgumentException
+    {
+        if (! image.copyOnWrite) {
+            setImage(GraphicsUtilities.createCompatibleTranslucentImage(image.getWidth(), image.getHeight()));
+            Graphics2D g = getGraphics();
+            g.setComposite(AlphaComposite.Src);
+            g.drawImage(image.getAwtImage(), 0, 0, null);
+            g.dispose();
+        }
+        else {
+            // If the source image is a copy-on-write image, we can easily
+            // make this a copy-on-write image as well.
+            this.image = image.image;
+            copyOnWrite = true;
+        }
+        copyStates(image, this);
+    }
+    
+    /**
+     * Creates an image with the given string drawn as text using the given font size, with the given foreground
+     * color on the given background color.  If the string has newline characters, it
+     * is split into multiple lines which are drawn horizontally-centred.
+     * 
+     * @param string the string to be drawn
+     * @param size the requested height in pixels of each line of text (the actual height may be different by a pixel or so)
+     * @param foreground the color of the text.  Since Greenfoot 2.2.0, passing null will use black.
+     * @param background the color of the image behind the text.  Since Greenfoot 2.2.0, passing null with leave the background transparent.
+     * @since 2.0.1
+     */
+    public GreenfootImage(String string, int size, Color foreground, Color background)
+    {
+        String[] lines = string.replaceAll("\r", "").split("\n");
+        image = GraphicsUtilities.createCompatibleTranslucentImage(1, 1);
+        Graphics2D g = (Graphics2D)image.getGraphics();
+        Font font = g.getFont().deriveFont((float)size);
+        g.setFont(font);
+        
+        // If you ask for a height of size 40, you may well get a font of size 48
+        // (I did on my Ubuntu system).  So we compensate if that happens by
+        // scaling down our request to one that we expect should get the right size.
+        // We don't loop because it may not converge.
+        if (g.getFontMetrics().getHeight() != size) {
+            font = g.getFont().deriveFont((float)size * (float)size / (float)g.getFontMetrics().getHeight());
+            g.setFont(font);
+        }
+        
+        Rectangle2D[] bounds = new Rectangle2D[lines.length];
+        int maxX = 1; int y = 0;
+        for (int i = 0; i < lines.length;i++) {
+            bounds[i] = g.getFontMetrics().getStringBounds(lines[i], g);
+            maxX = Math.max(maxX, (int)Math.ceil(bounds[i].getWidth()));
+            y += Math.ceil(bounds[i].getHeight());
+        }
+        y = Math.max(y, 1);
+        g.dispose();
+        image = GraphicsUtilities.createCompatibleTranslucentImage(maxX, y);
+        g = (Graphics2D)image.getGraphics();
+        g.setFont(font);
+        g.setColor(background == null ? new Color(0, 0, 0, 0) : background);
+        g.fillRect(0, 0, image.getWidth(), image.getHeight());
+        g.setColor(foreground == null ? Color.BLACK : foreground);
+        y = 0;
+        for (int i = 0; i < lines.length;i++) {
+            g.drawString(lines[i], ((maxX - (int)bounds[i].getWidth()) / 2) - (int)bounds[i].getX(), y - (int)bounds[i].getY());
+            y += Math.ceil(bounds[i].getHeight());
+        }
+        g.dispose();
+    }
+    
+    //Package-visible:
+    GreenfootImage(byte[] imageData)
+    {
+        try {
+            image = GraphicsUtilities.loadCompatibleTranslucentImage(imageData);
+        } catch (IOException ex) {
+            throw new IllegalArgumentException("Could not load image from: " + imageFileName);
+        }
+    }  
+
+    private GreenfootImage() {        
+    } 
+    
+    /**
+     * Create a copy-on-write image based on this image. If the new image is
+     * modified, the original image will not be affected.
+     * <p>
+     * Only use this method if you are sure that the original image will never
+     * be modified.
+     */
+    GreenfootImage getCopyOnWriteClone()
+    {
+        GreenfootImage clone = new GreenfootImage();
+        clone.copyOnWrite = true;
+        clone.image = image;
+        copyStates(this, clone);
+        
+        return clone;
+    }
+    
+    /**
+     * Creates a copy of the cached image
+     * @param cachedImage image to copy
+     */
+    void createClone(GreenfootImage cachedImage)
+    {
+        this.copyOnWrite = true;
+        this.image = cachedImage.image;
+        copyStates(cachedImage, this);
+
+    }
+    
+    /**
+     * Copies the states from the src image to dst image.
+     */
+    private static void copyStates(GreenfootImage src, GreenfootImage dst)
+    {
+        dst.imageFileName = src.imageFileName;
+        dst.imageUrl = src.imageUrl;
+        dst.currentColor = src.currentColor;
+        dst.currentFont = src.currentFont;
+        dst.transparency = src.transparency;
+    }    
+    
+    private void loadURL(URL imageURL)
+        throws IllegalArgumentException
+    {
+        if (imageURL == null) {
+            throw new NullPointerException("Image URL must not be null.");
+        }
+        try {
+            image = GraphicsUtilities.loadCompatibleTranslucentImage(imageURL);
+        } catch (IOException ex) {
+            throw new IllegalArgumentException("Could not load image from: " + imageFileName);
+        }
+    }
+
+    /**
+     * Tries to find the filename using the classloader. It first searches in
+     * 'projectdir/images/', then in the 'projectdir' and last as an absolute
+     * filename or URL
+     * 
+     * @param filename Name of the image file
+     * @throws IllegalArgumentException If it could not read the image.
+     */
+    private void loadFile(String filename)
+        throws IllegalArgumentException
+    {
+        if (filename == null) {
+            throw new NullPointerException("Filename must not be null.");
+        }
+        imageFileName = filename;
+        try {
+            imageUrl = GreenfootUtil.getURL(filename, "images");
+        }
+        catch (FileNotFoundException e) {
+            throw new IllegalArgumentException(e);           
+        }
+        loadURL(imageUrl);
+    }
+
+    /**
+     * Sets the image to the specified AWT image
+     * 
+     * @param image
+     */
+    private void setImage(Image image)
+        throws IllegalArgumentException
+    {
+        if (image == null) {
+            throw new IllegalArgumentException("Image must not be null.");
+        }
+        this.image = getBufferedImage(image);
+        copyOnWrite = false;
+    }
+
+
+    /**
+     * Returns the java.awt.image.BufferedImage that backs this GreenfootImage. Any changes to
+     * the returned image will be reflected in the GreenfootImage.
+     * 
+     * @return The java.awt.image.BufferedImage backing this GreenfootImage
+     * @since Greenfoot version 1.0.2
+     */
+    public BufferedImage getAwtImage()
+    {
+        ensureWritableImage();
+        return image;
+    }
+    
+    /**
+     * Remember to call dispose() when no longer using the graphics object.
+     * 
+     */
+    private Graphics2D getGraphics()
+    {
+        if (copyOnWrite) {
+        ensureWritableImage();
+        }
+        Graphics2D graphics = image.createGraphics();
+        initGraphics(graphics);
+        return graphics;
+    }
+
+    /**
+     * Initialises the graphics. Should be called whenever we have created a
+     * graphics for this image.
+     */
+    private void initGraphics(Graphics2D graphics)
+    {
+        if(graphics != null) {
+            graphics.setBackground(DEFAULT_BACKGROUND);
+            graphics.setColor(currentColor);
+            if(currentFont != null) {
+                graphics.setFont(currentFont);
+            }
+        }
+    }
+
+    /**
+     * Return the width of the image.
+     * 
+     * @return Width of the image.
+     */
+    public int getWidth()
+    {
+        return image.getWidth(null);
+    }
+
+    /**
+     * Return the height of the image.
+     * 
+     * @return Height of the image.
+     */
+    public int getHeight()
+    {
+        return image.getHeight(null);
+    }
+    
+
+    /**
+     * Rotates this image around the center.
+     * 
+     * @param degrees
+     */
+    public void rotate(int degrees)
+    {
+        AffineTransform tx = AffineTransform.getRotateInstance(Math.toRadians(degrees), getWidth()/2., getHeight()/2.);
+        AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
+        BufferedImage newImage = GraphicsUtilities.createCompatibleTranslucentImage(getWidth(), getHeight());
+        setImage(op.filter(image, newImage));
+    }
+
+    /**
+     * Scales this image to a new size.
+     * 
+     * @param width Width of new image
+     * @param height Height of new image
+     */
+    public void scale(int width, int height)
+    {
+        if (width == image.getWidth() && height == image.getHeight())
+            return;
+        
+        // getScaledInstance is too slow, see: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196792
+        // This is adapted from: http://java.sun.com/products/java-media/2D/reference/faqs/index.html#Q_How_do_I_create_a_resized_copy
+        BufferedImage scaled = GraphicsUtilities.createCompatibleTranslucentImage(width, height);
+        Graphics2D g = scaled.createGraphics();
+        g.setComposite(AlphaComposite.Src);
+        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+        g.drawImage(image, 0, 0, width, height, null);
+        g.dispose();
+        setImage(scaled);
+    }
+
+    /**
+     * Mirrors the image vertically (the top of the image becomes the bottom, and vice versa).
+     * 
+     */
+    public void mirrorVertically()
+    {
+        AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
+        tx.translate(0, -image.getHeight(null));
+        AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
+        setImage(op.filter(image, null));
+    }
+
+    /**
+     * Mirrors the image horizontally (the left of the image becomes the right, and vice versa).
+     * 
+     */
+    public void mirrorHorizontally()
+    {
+        AffineTransform tx = AffineTransform.getScaleInstance(-1, 1);
+        tx.translate(-image.getWidth(null), 0);
+        AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
+        setImage(op.filter(image, null));
+    }
+
+    /**
+     * Fill the entire image with the current drawing dcolor.
+     * 
+     */
+    public void fill()
+    {
+        Graphics g = getGraphics();
+        g.fillRect(0, 0, getWidth(), getHeight());
+        g.dispose();
+    }
+
+    /**
+     * Draws the given Image onto this image
+     * 
+     * @param image The image to draw onto this one.
+     * @param x x-coordinate for drawing the image.
+     * @param y y-coordinate for drawing the image.
+     */
+    public void drawImage(GreenfootImage image, int x, int y)
+    {
+        Graphics2D g = getGraphics();
+        image.drawImage(g, x, y, null, true);
+        g.dispose();
+    }
+
+    /**
+     * Draws this image onto the given Graphics object.
+     * 
+     * @param useTransparency Whether the transparency value should be used when
+     *            drawing the image.
+     */
+    void drawImage(Graphics2D g, int x, int y, ImageObserver observer, boolean useTransparency)
+    {
+        Composite oldComposite = null;
+        if(useTransparency) {
+            float opacity = getTransparency() / 255f;
+            if(opacity < 1) {
+                // Don't bother with the composite if completely opaque.
+                if(opacity < 0) opacity = 0;
+                oldComposite = g.getComposite();
+                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
+            }
+        }
+        
+        g.drawImage(image, x, y, observer);
+
+        if(oldComposite != null) {
+            g.setComposite(oldComposite);
+        }
+    }
+    
+    /**
+     * Set the current font. This font will be used for subsequent text
+     * operations.
+     */
+    public void setFont(Font f)
+    {
+        currentFont = f;
+    }
+    
+    /**
+     * Get the current font.
+     */
+    public Font getFont()
+    {        
+        if(currentFont == null) {
+            currentFont = getGraphics().getFont();
+        }
+        return currentFont;
+    }
+
+    /**
+     * Set the current drawing color. This color will be used for subsequent
+     * drawing operations.
+     * 
+     * @param color The color to be used.
+     */
+    public void setColor(Color color)
+    {
+        currentColor = color;
+    }
+
+    /**
+     * Return the current drawing color.
+     * 
+     * @return The current color.
+     */
+    public Color getColor()
+    {
+        return currentColor;
+    }
+
+    /**
+     * Return the color at the given pixel.
+     * 
+     * @throws IndexOutOfBoundsException If the pixel location is not within the
+     *             image bounds.
+     */
+    public Color getColorAt(int x, int y)
+    {
+        return new Color(getRGBAt(x, y), true); 
+    }
+    
+    /**
+     * Sets the color at the given pixel to the given color.
+     */
+    public void setColorAt(int x, int y, Color color) {
+        setRGBAt(x, y, color.getRGB());
+    }
+
+    /**
+     * Set the transparency of the image.
+     * 
+     * @param t A value in the range 0 to 255. 0 is completely transparent
+     *            (invisible) and 255 is completely opaque (the default).
+     */
+    public void setTransparency(int t)
+    {
+        if (t < 0 || t > 255) {
+            throw new IllegalArgumentException("The transparency value has to be in the range 0 to 255. It was: " + t);
+        }
+
+        this.transparency = t;
+    }
+
+    /**
+     * Return the current transparency of the image.
+     * 
+     * @return A value in the range 0 to 255. 0 is completely transparent
+     *         (invisible) and 255 is completely opaque (the default).
+     */
+    public int getTransparency()
+    {
+        return transparency;
+    }    
+    
+    private int getRGBAt(int x, int y)
+    {
+        if (x >= getWidth()) {
+            throw new IndexOutOfBoundsException("X is out of bounds. It was: " + x
+                    + " and it should have been smaller than: " + getWidth());
+        }
+        if (y >= getHeight()) {
+            throw new IndexOutOfBoundsException("Y is out of bounds. It was: " + y
+                    + " and it should have been smaller than: " + getHeight());
+        }
+        if (x < 0) {
+            throw new IndexOutOfBoundsException("X is out of bounds. It was: " + x
+                    + " and it should have been at least: 0");
+        }
+        if (y < 0) {
+            throw new IndexOutOfBoundsException("Y is out of bounds. It was: " + y
+                    + " and it should have been at least: 0");
+        }
+
+        return image.getRGB(x,y);
+    }
+    
+    private void setRGBAt(int x, int y, int rgb)
+    {
+        if (x >= getWidth()) {
+            throw new IndexOutOfBoundsException("X is out of bounds. It was: " + x
+                    + " and it should have been smaller than: " + getWidth());
+        }
+        if (y >= getHeight()) {
+            throw new IndexOutOfBoundsException("Y is out of bounds. It was: " + y
+                    + " and it should have been smaller than: " + getHeight());
+        }
+        if (x < 0) {
+            throw new IndexOutOfBoundsException("X is out of bounds. It was: " + x
+                    + " and it should have been at least: 0");
+        }
+        if (y < 0) {
+            throw new IndexOutOfBoundsException("Y is out of bounds. It was: " + y
+                    + " and it should have been at least: 0");
+        }
+
+        ensureWritableImage();
+        image.setRGB(x,y,rgb);
+    }
+ 
+    /**
+     * Fill the specified rectangle. The left and right edges of the rectangle
+     * are at <code>x</code> and
+     * <code>x&nbsp;+&nbsp;width&nbsp;-&nbsp;1</code>. The top and bottom
+     * edges are at <code>y</code> and
+     * <code>y&nbsp;+&nbsp;height&nbsp;-&nbsp;1</code>. The resulting
+     * rectangle covers an area <code>width</code> pixels wide by
+     * <code>height</code> pixels tall. The rectangle is filled using the
+     * current color.
+     * 
+     * @param x the <i>x </i> coordinate of the rectangle to be filled.
+     * @param y the <i>y </i> coordinate of the rectangle to be filled.
+     * @param width the width of the rectangle to be filled.
+     * @param height the height of the rectangle to be filled.
+     */
+    public void fillRect(int x, int y, int width, int height)
+    {
+        Graphics2D g = getGraphics();
+        g.fillRect(x, y, width, height);
+        g.dispose();
+    }
+
+    /**
+     * Clears the image.
+     * 
+     */
+    public void clear()
+    {
+        Graphics2D g = getGraphics();
+        //TODO clearRect might be very slow on mac with Sun Rendere
+        g.clearRect(0, 0, getWidth(), getHeight());
+        g.dispose();
+    }
+
+    /**
+     * Draw the outline of the specified rectangle. The left and right edges of
+     * the rectangle are at <code>x</code> and
+     * <code>x&nbsp;+&nbsp;width</code>. The top and bottom edges are at
+     * <code>y</code> and <code>y&nbsp;+&nbsp;height</code>. The rectangle
+     * is drawn using the current color.
+     * 
+     * @param x the <i>x </i> coordinate of the rectangle to be drawn.
+     * @param y the <i>y </i> coordinate of the rectangle to be drawn.
+     * @param width the width of the rectangle to be drawn.
+     * @param height the height of the rectangle to be drawn.
+     */
+    public void drawRect(int x, int y, int width, int height)
+    {
+        Graphics2D g = getGraphics();
+        g.drawRect(x, y, width, height);
+        g.dispose();
+    }
+
+    /**
+     * Draw the text given by the specified string, using the current font and
+     * color. The baseline of the leftmost character is at position ( <i>x
+     * </i>,&nbsp; <i>y </i>).
+     * 
+     * @param string the string to be drawn.
+     * @param x the <i>x </i> coordinate.
+     * @param y the <i>y </i> coordinate.
+     */
+    public void drawString(String string, int x, int y)
+    {
+        Graphics2D g = getGraphics();
+        g.drawString(string, x, y);
+        g.dispose();
+    }
+
+    /**
+     * Draw a shape directly on the image. Shapes are specified by the <a href=
+     * "http://java.sun.com/javase/6/docs/api/java/awt/Shape.html">shape
+     * interface</a>.
+     * @param shape the shape to be drawn.
+     */
+    public void drawShape(Shape shape)
+    {
+        Graphics2D g = getGraphics();
+        g.draw(shape);
+        g.dispose();
+    }
+
+    /**
+     * Draw a filled shape directly on the image. Shapes are specified by the
+     * <a href="http://java.sun.com/javase/6/docs/api/java/awt/Shape.html">shape
+     * interface</a>.
+     * @param shape the shape to be drawn.
+     */
+    public void fillShape(Shape shape)
+    {
+        Graphics2D g = getGraphics();
+        g.fill(shape);
+        g.dispose();
+    }
+
+    /**
+     * Fill an oval bounded by the specified rectangle with the current drawing
+     * color.
+     * 
+     * @param x the <i>x </i> coordinate of the upper left corner of the oval to
+     *            be filled.
+     * @param y the <i>y </i> coordinate of the upper left corner of the oval to
+     *            be filled.
+     * @param width the width of the oval to be filled.
+     * @param height the height of the oval to be filled.
+     */
+    public void fillOval(int x, int y, int width, int height)
+    {
+        Graphics2D g = getGraphics();
+        g.fillOval(x, y, width, height);
+        g.dispose();
+    }
+
+    /**
+     * Draw an oval bounded by the specified rectangle with the current drawing
+     * color.
+     * 
+     * @param x the <i>x </i> coordinate of the upper left corner of the oval to
+     *            be filled.
+     * @param y the <i>y </i> coordinate of the upper left corner of the oval to
+     *            be filled.
+     * @param width the width of the oval to be filled.
+     * @param height the height of the oval to be filled.
+     */
+    public void drawOval(int x, int y, int width, int height)
+    {
+        Graphics2D g = getGraphics();
+        g.drawOval(x, y, width, height);
+        g.dispose();
+    }
+
+    /**
+     * Fill a closed polygon defined by arrays of <i>x </i> and <i>y </i>
+     * coordinates.
+     * <p>
+     * This method draws the polygon defined by <code>nPoint</code> line
+     * segments, where the first <code>nPoint&nbsp;-&nbsp;1</code> line
+     * segments are line segments from
+     * <code>(xPoints[i&nbsp;-&nbsp;1],&nbsp;yPoints[i&nbsp;-&nbsp;1])</code>
+     * to <code>(xPoints[i],&nbsp;yPoints[i])</code>, for 1&nbsp;&le;&nbsp;
+     * <i>i </i>&nbsp;&le;&nbsp; <code>nPoints</code>. The figure is
+     * automatically closed by drawing a line connecting the final point to the
+     * first point, if those points are different.
+     * <p>
+     * The area inside the polygon is defined using an even-odd fill rule, also
+     * known as the alternating rule.
+     * 
+     * @param xPoints a an array of <code>x</code> coordinates.
+     * @param yPoints a an array of <code>y</code> coordinates.
+     * @param nPoints a the total number of points.
+     */
+    public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
+    {
+        Graphics2D g = getGraphics();
+        g.fillPolygon(xPoints, yPoints, nPoints);
+        g.dispose();
+    }
+
+    /**
+     * Draws a closed polygon defined by arrays of <i>x</i> and <i>y</i>
+     * coordinates. Each pair of (<i>x</i>,&nbsp;<i>y</i>) coordinates
+     * defines a point.
+     * <p>
+     * This method draws the polygon defined by <code>nPoint</code> line
+     * segments, where the first <code>nPoint&nbsp;-&nbsp;1</code> line
+     * segments are line segments from
+     * <code>(xPoints[i&nbsp;-&nbsp;1],&nbsp;yPoints[i&nbsp;-&nbsp;1])</code>
+     * to <code>(xPoints[i],&nbsp;yPoints[i])</code>, for 1&nbsp;&le;&nbsp;<i>i</i>&nbsp;&le;&nbsp;<code>nPoints</code>.
+     * The figure is automatically closed by drawing a line connecting the final
+     * point to the first point, if those points are different.
+     * 
+     * @param xPoints an array of <code>x</code> coordinates.
+     * @param yPoints an array of <code>y</code> coordinates.
+     * @param nPoints the total number of points.
+     */
+    public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
+    {
+        Graphics2D g = getGraphics();
+        g.drawPolygon(xPoints, yPoints, nPoints);
+        g.dispose();
+    }
+
+    /**
+     * Draw a line, using the current drawing color, between the points
+     * <code>(x1,&nbsp;y1)</code> and <code>(x2,&nbsp;y2)</code>.
+     * 
+     * @param x1 the first point's <i>x </i> coordinate.
+     * @param y1 the first point's <i>y </i> coordinate.
+     * @param x2 the second point's <i>x </i> coordinate.
+     * @param y2 the second point's <i>y </i> coordinate.
+     */
+    public void drawLine(int x1, int y1, int x2, int y2)
+    {
+        Graphics2D g = getGraphics();
+        g.drawLine(x1, y1, x2, y2);
+        g.dispose();
+    }
+
+    /**
+     * Return a text representation of the image.
+     */
+    public String toString()
+    {
+        String superString = super.toString();
+        if (imageFileName == null) {
+            return superString;
+        }
+        else {
+            return "Image file name: " + imageFileName +   "   Image url: " + imageUrl + "  " + superString;
+        }
+    }
+    
+    static boolean equal(GreenfootImage image1, GreenfootImage image2)
+    {
+        if (image1 == null || image2 == null) {
+            return image1 == image2;
+        }
+        else {
+            return (image1.image == image2.image || image1.equals(image2));
+        }
+    }
+
+    /**
+     * Ensure we have an image which we are allowed to write to. If we are
+     * a copy-on-write image, create a copy of the image (and set up the
+     * graphics2d object) before returning.
+     */
+    private void ensureWritableImage()
+    {
+        if (copyOnWrite) {
+            BufferedImage bImage = GraphicsUtilities.createCompatibleTranslucentImage(image.getWidth(null), image.getHeight(null));
+            Graphics2D graphics = bImage.createGraphics();
+            initGraphics(graphics);
+            graphics.drawImage(image, 0, 0, null);
+            image = bImage;
+            copyOnWrite = false;
+            graphics.dispose();
+        }
+    }
+    
+    /**
+     * Gets a BufferedImage of the AWT Image that this GreenfootImage
+     * represents. We need this for some of the image manipulation methods.
+     */
+    private static BufferedImage getBufferedImage(Image image)
+    {
+        if (image instanceof BufferedImage) {}
+        else if (image instanceof VolatileImage) {
+            image = ((VolatileImage) image).getSnapshot();
+            waitForImageLoad(image);
+        }
+        else {
+            waitForImageLoad(image);
+            BufferedImage bImage = GraphicsUtilities.createCompatibleTranslucentImage(image.getWidth(null), image.getHeight(null));
+            Graphics g = bImage.getGraphics();
+            g.drawImage(image, 0, 0, null);
+            image = bImage;
+        }
+        return (BufferedImage) image;
+    }
+        
+    /**
+     * Wait until the image is fully loaded and then init the graphics.
+     * 
+     */
+    private static void waitForImageLoad(Image image)
+    {
+        if (tracker == null) {
+            tracker = new MediaTracker(new Component() {});
+        }
+        tracker.addImage(image, 0);
+        try {
+            tracker.waitForID(0);
+            tracker.removeImage(image);
+        }
+        catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+   
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/GreenfootSound.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/GreenfootSound.java
new file mode 100644
index 0000000000000000000000000000000000000000..ceb164bdc2ce916866de58cf18a8cf794f9ff639
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/GreenfootSound.java
@@ -0,0 +1,145 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import greenfoot.sound.Sound;
+import greenfoot.sound.SoundFactory;
+
+/**
+ * Represents audio that can be played in Greenfoot. A GreenfootSound loads the audio from a file.
+ * The sound cannot be played several times simultaneously, but can be played several times sequentially. 
+ * 
+ * <p>Most files of the following formats are supported: AIFF, AU, WAV, MP3 and MIDI.
+ * 
+ * @author Poul Henriksen
+ * @version 2.4
+ */
+public class GreenfootSound
+{
+
+    private Sound sound;
+    /**
+     * The name of the file where the sound is loaded from.
+     */
+    private String filename;
+
+    /**
+     * Creates a new sound from the given file. 
+     * 
+     * @param filename Typically the name of a file in the sounds directory in
+     *            the project directory. 
+     */
+    public GreenfootSound(String filename)
+    {
+        this.filename = filename;
+        sound = SoundFactory.getInstance().createSound(filename, false);
+    }
+
+    /**
+     * Start playing this sound. If it is playing already, it will do
+     * nothing. If the sound is currently looping, it will finish the current
+     * loop and stop. If the sound is currently paused, it will resume playback
+     * from the point where it was paused. The sound will be played once.
+     */
+    public void play()
+    {
+        sound.play();
+    }
+
+    /**
+     * Play this sound repeatedly in a loop. If called on an already looping
+     * sound, it will do nothing. If the sound is already playing once, it will
+     * start looping instead. If the sound is currently paused, it will resume
+     * playing from the point where it was paused.
+     */
+    public void playLoop()
+    {
+        sound.loop();
+    }
+
+    /**
+     * Stop playing this sound if it is currently playing. If the sound is
+     * played again later, it will start playing from the beginning. If the
+     * sound is currently paused it will now be stopped instead.
+     */
+    public void stop()
+    {
+        sound.stop();
+    }
+
+    /**
+     * Pauses the current sound if it is currently playing. If the sound is
+     * played again later, it will resume from the point where it was paused.
+     * <p>
+     * Make sure that this is really the method you want. If possible, you
+     * should always use {@link #stop()}, because the resources can be released
+     * after calling {@link #stop()}. The resources for the sound will not be
+     * released while it is paused.
+     * @see #stop()
+     */
+    public void pause()
+    {
+        sound.pause();
+    }
+
+    /**
+     * True if the sound is currently playing.
+     * 
+     */
+    public boolean isPlaying()
+    {
+        return sound.isPlaying();
+    }
+
+    /**
+     * Get the current volume of the sound, between 0 (off) and 100 (loudest.)
+     */
+    public int getVolume()
+    {
+        return sound.getVolume();
+    }
+
+    /**
+     * Set the current volume of the sound between 0 (off) and 100 (loudest.)
+     * @param level the level to set the sound volume to.
+     */
+    public void setVolume(int level)
+    {
+        sound.setVolume(level);
+    }
+
+    /**
+     * Returns a string representation of this sound containing the name of the
+     * file and whether it is currently playing or not.
+     */
+    public String toString()
+    {
+        String s = super.toString() + " file: " + filename + " ";
+        if (sound != null) {
+            s += ". Is playing: " + isPlaying();
+        }
+        else {
+            s += ". Not found.";
+        }
+        return s;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ImageVisitor.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ImageVisitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..129dcd232c43361bb203d83e217019c7311a1d69
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ImageVisitor.java
@@ -0,0 +1,48 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import java.awt.Graphics2D;
+import java.awt.image.ImageObserver;
+
+/**
+ * Class that makes it possible for classes outside the greenfoot package to get
+ * access to Image methods that are package protected. We need some
+ * package-protected methods in the Image, because we don't want them to show up
+ * in the public interface visible to users.
+ * 
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: ImageVisitor.java 6256 2009-04-16 11:55:51Z polle $
+ */
+public class ImageVisitor
+{
+    public static void drawImage(GreenfootImage image, Graphics2D g, int x, int y, ImageObserver observer, boolean useTranparency)
+    {
+        image.drawImage(g, x, y, observer, useTranparency);
+    }
+    
+    public static boolean equal(GreenfootImage image1, GreenfootImage image2)
+    {
+        return GreenfootImage.equal(image1, image2);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/MouseInfo.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/MouseInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..f97165976fc078f3071582b15bf1e48107d7049c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/MouseInfo.java
@@ -0,0 +1,126 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+/**
+ * This class contains information about the current status of the mouse. You
+ * can get a MouseInfo object via {@link Greenfoot#getMouseInfo()}.
+ * 
+ * @see Greenfoot#getMouseInfo()
+ * @author Poul Henriksen
+ * @version 2.4
+ */
+public class MouseInfo
+{    
+    private Actor actor;
+    private int button;
+    private int x;
+    private int y;
+    private int clickCount;;
+    
+    /**
+     * Do not create your own MouseInfo objects. Use
+     * {@link Greenfoot#getMouseInfo() getMouseInfo()}.
+     * 
+     * @see Greenfoot#getMouseInfo()
+     */
+    MouseInfo() {  }
+    
+    /**
+     * Return the current x position of the mouse cursor.
+     * 
+     * @return the x position in grid coordinates
+     */
+    public int getX() 
+    {
+        return x;
+    }
+
+    /**
+     * Return the current y position of the mouse cursor.
+     * 
+     * @return the y position in grid coordinates
+     */
+    public int getY() 
+    {
+        return y;
+    }
+    
+    /**
+     * Return the actor (if any) that the current mouse behaviour is related to.
+     * If the mouse was clicked or pressed the actor it was clicked on will be
+     * returned. If the mouse was dragged or a drag ended, the actor where the
+     * drag started will be returned. If the mouse was moved, it will return the
+     * actor that the mouse is currently over.
+     * 
+     * @return Actor that the current mouse behaviour relates to, or null if
+     *         there is no actor related to current behaviour. 
+     */
+    public Actor getActor()
+    {
+        return actor;
+    }
+    
+    /**
+     * The number of the pressed or clicked button (if any).
+     * 
+     * @return The button number. Usually 1 is the left button, 2 is the middle
+     *         button and 3 is the right button.
+     */
+    public int getButton() {
+        return button;
+    }
+
+    /**
+     * Return the number of mouse clicks associated with this mouse event.
+     * @return The number of times a button has been clicked.
+     */
+    public int getClickCount() {
+        return clickCount;
+    }
+    
+    void setButton(int button)
+    {
+        this.button = button;
+    }
+
+    void setLoc(int x, int y)
+    {
+        this.x = x;
+        this.y = y;
+    }
+
+    void setActor(Actor actor)
+    {
+        this.actor = actor;
+    }
+
+    void setClickCount(int clickCount)
+    {
+        this.clickCount = clickCount;
+    }    
+    
+    public String toString() 
+    {
+        return "MouseInfo. Actor: " + actor + "  Location: (" + x + "," + y + ")  Button: " + button + " Click Count: " + clickCount;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/MouseInfoVisitor.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/MouseInfoVisitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d3206cc451e4b7d7b60678d4441d59f4f68a1ed
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/MouseInfoVisitor.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+
+
+
+/**
+ * To get access to package private methods in MouseInfo.
+ * 
+ * @author Poul Henriksen
+ *
+ */
+public class MouseInfoVisitor
+{
+    public static void setActor(MouseInfo info, Actor actor) {
+        info.setActor(actor);
+    }    
+
+    public static void setLoc(MouseInfo info, int x, int y) {
+        info.setLoc(x, y);
+    }
+
+    public static void setButton(MouseInfo info, int button)
+    {
+        info.setButton(button);
+    }    
+    
+    public static MouseInfo newMouseInfo()
+    {
+        return new MouseInfo();
+    }
+
+    public static void setClickCount(MouseInfo mouseInfo, int clickCount)
+    {
+        mouseInfo.setClickCount(clickCount);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ObjectTracker.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ObjectTracker.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e6c1766b6d15aaaa73f02f6b0f15d8f322f5fa6
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/ObjectTracker.java
@@ -0,0 +1,169 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import greenfoot.core.GNamedValue;
+import greenfoot.core.GreenfootLauncherDebugVM;
+import greenfoot.core.GreenfootMain;
+
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.function.Consumer;
+
+import rmiextension.wrappers.RObject;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugmgr.NamedValue;
+import bluej.debugmgr.ValueCollection;
+import bluej.runtime.BJMap;
+import bluej.runtime.ExecServer;
+import bluej.utility.Debug;
+import bluej.utility.JavaUtils;
+
+/**
+ * Class that can be used to get the remote version of an object and vice versa.
+ * 
+ * @author Poul Henriksen
+ */
+public class ObjectTracker
+{
+    private static HashMap<Object,RObject> cachedObjects = new HashMap<Object,RObject>();
+
+    /**
+     * Gets the remote reference to an object. If there is currently no remote reference,
+     * one is created.
+     *  
+     * @throws RemoteException  if an exception occurred in the remote VM
+     */
+    public static RObject getRObject(Object obj) throws RemoteException
+    {
+        synchronized (cachedObjects) {
+            RObject rObject = cachedObjects.get(obj);
+            if (rObject != null) {
+                return rObject;
+            }
+            
+            GreenfootLauncherDebugVM.getInstance().setTransportField(obj);
+            RObject rObj = GreenfootMain.getInstance().getProject().getRProject().getRemoteObject();
+            
+            if (rObj != null) {
+                cachedObjects.put(obj,rObj);
+            }
+            
+            return rObj;
+        }
+    }    
+
+    /**
+     * Get the complete set of registered objects as a ValueCollection.
+     */
+    public static ValueCollection getObjects()
+    {
+        return new ValueCollection()
+        {
+            BJMap<String,Object> map;
+            String [] names;
+            
+            private void initNames()
+            {
+                if (names == null) {
+                    map = ExecServer.getObjectMap();
+                    synchronized (map) {
+                        Object [] keys = map.getKeys();
+                        names = new String[keys.length];
+                        System.arraycopy(keys, 0, names, 0, keys.length);
+                    }
+                }
+            }
+            
+            @Override
+            public GNamedValue getNamedValue(String name)
+            {
+                initNames();
+                synchronized (map) {
+                    Object o = map.get(name);
+                    if (o != null) {
+                        JavaType type = JavaUtils.genTypeFromClass(o.getClass());
+                        return new GNamedValue(name, type);
+                    }
+                    return new GNamedValue(name, JavaUtils.genTypeFromClass(Object.class));
+                }
+            }
+            
+            @Override
+            public Iterator<? extends NamedValue> getValueIterator()
+            {
+                initNames();
+                return new Iterator<GNamedValue>() {
+                    @Override
+                  public void forEachRemaining(
+                      Consumer<? super GNamedValue> action) {
+                    // TODO Auto-generated method stub
+                    
+                  }
+                    int index = 0;
+                    
+                    @Override
+                    public boolean hasNext()
+                    {
+                        return index < names.length;
+                    }
+                    @Override
+                    public GNamedValue next()
+                    {
+                        return getNamedValue(names[index++]);
+                    }
+                    @Override
+                    public void remove()
+                    {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
+        };
+    }
+    
+    /**
+     * Get the local object corresponding to a remote object.
+     */
+    public static Object getRealObject(RObject remoteObj)
+    {
+        try {
+            return ExecServer.getObject(remoteObj.getInstanceName());
+        }
+        catch (RemoteException e) {
+           Debug.reportError("Unexpected exception getting remote object name", e);
+        }
+        return null;
+    }
+
+    /**
+     * Clear the cache of remote objects.
+     */
+    public static void clearRObjectCache()
+    {
+        synchronized (cachedObjects) {
+            cachedObjects.clear();
+        }
+    }
+    
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/TreeActorSet.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/TreeActorSet.java
new file mode 100644
index 0000000000000000000000000000000000000000..935bfc94da889c4badca87377bacbf568b60b9e0
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/TreeActorSet.java
@@ -0,0 +1,302 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * A set which allows specifying iteration order according to class of contained
+ * objects.
+ * 
+ * <p>TreeActorSet is really an ordered "set of sets". Each set corresponds to
+ * a class; any actors of that class are put in the set, along with any actors
+ * of subclasses as long as there isn't a more appropriate set for them.
+ * 
+ * @author Davin McCall
+ */
+public class TreeActorSet extends AbstractSet<Actor>
+{
+    @Override
+  public Spliterator<Actor> spliterator() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public boolean removeIf(Predicate<? super Actor> filter) {
+    // TODO Auto-generated method stub
+    return false;
+  }
+
+  @Override
+  public Stream<Actor> stream() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Stream<Actor> parallelStream() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void forEach(Consumer<? super Actor> action) {
+    // TODO Auto-generated method stub
+    
+  }
+
+    private List<ActorSet> subSets;
+    
+    /** ActorSet for objects of a class without a specific z-order */
+    private ActorSet generalSet;
+    
+    private HashMap<Class<?>, ActorSet> classSets;
+    
+    /**
+     * Construct an empty TreeActorSet.
+     */
+    public TreeActorSet()
+    {
+        subSets = new LinkedList<ActorSet>();
+        generalSet = new ActorSet();
+        subSets.add(generalSet);
+        
+        classSets = new HashMap<Class<?>, ActorSet>();
+    }
+    
+    /**
+     * Set the iteration order of objects. The first given class will have
+     * objects of its class last in the iteration order, the next will have
+     * objects second last in iteration order, and so on. This hold if it is
+     * reversed. If it is not reversed it will return the first one first and so
+     * on.
+     * 
+     * Objects not belonging to any of the specified classes will be first in
+     * the iteration order if reversed, or last if not reversed
+     * 
+     * @param reverse
+     *            Whether to reverse the order or not. 
+     */
+    public void setClassOrder(boolean reverse, Class<?> ... classes)
+    {
+        HashMap<Class<?>, ActorSet> oldClassSets = classSets;
+        classSets = new HashMap<Class<?>, ActorSet>();
+        
+        // A list of classes we need to sweep the superclass set of
+        LinkedList<Class<?>> sweepClasses = new LinkedList<Class<?>>();
+        
+        // For each listed class, use the ActorSet from the original classSets
+        // if it exists, or create a new one if not
+        for (int i = 0; i < classes.length; i++) {
+            ActorSet oldSet = oldClassSets.remove(classes[i]);
+            if (oldSet == null) {
+                // There was no old set for this class. We'll need to check
+                // the superclass set for actors which actually belong in
+                // the new set.
+                sweepClasses.add(classes[i]);
+                oldSet = new ActorSet();
+            }
+            classSets.put(classes[i], oldSet);
+        }
+        
+        // There may be objects in a set for some class A which
+        // belong in the set for class B which is derived from A.
+        // Now we'll "sweep" such sets.
+
+        Set<Class<?>> sweptClasses = new HashSet<Class<?>>();
+        
+        while (! sweepClasses.isEmpty()) {
+            Class<?> sweepClass = sweepClasses.removeFirst().getSuperclass();
+            ActorSet sweepSet = classSets.get(sweepClass);
+            while (sweepSet == null) {
+                sweepClass = sweepClass.getSuperclass();
+                if (sweepClass == null) {
+                    sweepSet = generalSet;
+                }
+                else {
+                    sweepSet = classSets.get(sweepClass);
+                }
+            }
+            
+            if (! sweptClasses.contains(sweepClass)) {
+                sweptClasses.add(sweepClass);
+                // go through sweep set
+                Iterator<Actor> i = sweepSet.iterator();
+                while (i.hasNext()) {
+                    Actor actor = i.next();
+                    ActorSet set = setForActor(actor);
+                    if (set != sweepSet) {
+                        set.add(actor); // add to the specific set
+                        i.remove(); // remove from the general set
+                    }
+                }
+            }
+        }
+        
+        // Now, for any old subsets not yet handled, move all the actors into
+        // the appropriate set. ("Not yet handled" means that the old subset
+        // has no equivalent in the new sets).
+        Iterator<Map.Entry<Class<?>,ActorSet>> ei = oldClassSets.entrySet().iterator();
+        for ( ; ei.hasNext(); ) {
+            Map.Entry<Class<?>,ActorSet> entry = ei.next();
+            ActorSet destinationSet = setForClass(entry.getKey());
+            destinationSet.addAll(entry.getValue());
+        }
+        
+        // Finally, re-create the subsets list
+        subSets.clear();
+        if(reverse) {
+            subSets.add(generalSet);
+            for (int i = classes.length; i > 0; ) {
+                subSets.add(classSets.get(classes[--i]));
+            }
+        }
+        else {
+            for (int i = 0; i < classes.length; i++) {
+                subSets.add(classSets.get(classes[i]));
+            }
+            subSets.add(generalSet);
+        }
+    }
+    
+    public Iterator<Actor> iterator()
+    {
+        return new TasIterator();
+    }
+    
+    public int size()
+    {
+        int size = 0;
+        for (Iterator<ActorSet> i = subSets.iterator(); i.hasNext(); ) {
+            size += i.next().size();
+        }
+        return size;
+    }
+    
+    public boolean add(Actor o)
+    {
+        if (o == null) {
+            throw new UnsupportedOperationException("Cannot add null actor.");
+        }
+        
+        return setForActor(o).add(o);
+    }
+    
+    public boolean remove(Actor o)
+    {
+        return setForActor(o).remove(o);
+    }
+    
+    public boolean contains(Actor o)
+    {
+        return setForActor(o).contains(o);
+    }
+    
+    /**
+     * Get the actor set for a particular actor, depending on its class.
+     */
+    private ActorSet setForActor(Actor o)
+    {
+        Class<?> oClass = o.getClass();
+        return setForClass(oClass);
+    }
+    
+    private ActorSet setForClass(Class<?> oClass)
+    {
+        ActorSet set = classSets.get(oClass);
+        
+        // There might be a set for some superclass
+        while (set == null && oClass != Object.class) {
+            oClass = oClass.getSuperclass();
+            set = classSets.get(oClass);
+        }
+        
+        if (set == null) {
+            set = generalSet;
+        }
+        return set;
+    }
+    
+    /**
+     * An iterator for a TreeActorSet
+     * 
+     * @author Davin McCall
+     */
+    class TasIterator implements Iterator<Actor>
+    {
+        @Override
+      public void forEachRemaining(Consumer<? super Actor> action) {
+        // TODO Auto-generated method stub
+        
+      }
+
+        private Iterator<ActorSet> setIterator;
+        private ActorSet currentSet;
+        private Iterator<Actor> actorIterator;
+        
+        public TasIterator()
+        {
+            setIterator = subSets.iterator();
+            currentSet = setIterator.next();
+            while (currentSet.isEmpty() && setIterator.hasNext()) {
+                currentSet = setIterator.next();
+            }
+            actorIterator = currentSet.iterator();
+        }
+        
+        public void remove()
+        {
+            actorIterator.remove();
+        }
+        
+        public Actor next()
+        {
+            hasNext(); // update iterator if necessary
+            return actorIterator.next();
+        }
+        
+        public boolean hasNext()
+        {
+            if (actorIterator.hasNext()) {
+                return true;
+            }
+            
+            if (! setIterator.hasNext()) {
+                return false;
+            }
+            
+            while (setIterator.hasNext()) {
+                currentSet = setIterator.next();
+                if (! currentSet.isEmpty()) {
+                    break;
+                }
+            }
+            
+            actorIterator = currentSet.iterator();
+            return actorIterator.hasNext();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/UserInfo.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/UserInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..279b5d0b0d00e7183a122b9c7943c441fda3f3f6
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/UserInfo.java
@@ -0,0 +1,339 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011, 2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import greenfoot.util.GreenfootUtil;
+
+import java.util.List;
+
+/**
+ * <p>The UserInfo class can be used to store data permanently on a server, and
+ * to share this data between different users, when the scenario runs on the
+ * Greenfoot web site. This can be used to implement shared high score tables
+ * or other examples of shared data.</p>
+ *
+ * <p>Storage is only available when the current user is logged in on the Greenfoot
+ * site, so for some users storage will not be available. Always use
+ * UserInfo.isStorageAvailable() to check before accessing the user data.</p>
+ *
+ * <p>A typical code snippet for storing a high score is as follows:</p>
+ *
+ * <pre>
+ *     if (UserInfo.isStorageAvailable()) {
+ *         UserInfo myInfo = UserInfo.getMyInfo();
+ *         if (newScore > myInfo.getScore()) {
+ *             myInfo.setScore(newScore);
+ *             myInfo.store();  // write back to server
+ *         }
+ *     }
+ * </pre>
+ * <p>Methods to retrieve user data include getting data for the current user
+ * (getMyInfo()), the top scorers (e.g. getTop(10) for the top 10), and data
+ * for users with scores near my own score (e.g. getNearby(10)).</p>
+ *
+ * <p>The data that can be stored for each user consists of a score, 10
+ * additional general purpose integers, and 5 strings (limited to 50 characters
+ * in length). In addition, the user name and user's image can be retrieved from
+ * the user data.</p>
+ *
+ * <p>For testing purposes, while running within Greenfoot (not on the web site),
+ * the user name can be set in the preferences (CTRL-SHIFT-P / CMD-SHIFT-P).
+ * This allows to simulate different users during development. When running
+ * on the web site, the user name is the name used to log in to the site.</p>
+ * 
+ * @author Neil Brown
+ * @version 2.4
+ */
+public class UserInfo
+{
+    // These may enlarge in future:
+    
+    /** The number of integers that can be stored */
+    public static final int NUM_INTS = 10;
+    /** The number of Strings that can be stored */
+    public static final int NUM_STRINGS = 5;
+    /** The maximum number of characters that can be stored in each String */    
+    public static final int STRING_LENGTH_LIMIT = 50;
+    // NB the above limit matches the database schema in the gallery storage
+    // so don't alter it!
+    private int[] ints;
+    private String[] strings;
+    private String userName;
+    private int score;
+    private int rank;
+    
+    //package-visible:
+    UserInfo(String userName, int rank)
+    {
+        this.userName = userName;
+        this.rank = rank;
+        score = 0;
+        ints = new int[NUM_INTS];
+        strings = new String[NUM_STRINGS];
+    }
+    
+    //package-visible:
+    void setRank(int n)
+    {
+        rank = n;
+    }
+    
+    /**
+     * Get the username of the user that this storage belongs to.
+     */
+    public String getUserName()
+    {
+        return userName;
+    }
+    
+    /**
+     * Get the value of the int at the given index (0 to NUM_INTS-1, inclusive).
+     * <p>
+     * The default value is zero.
+     */
+    public int getInt(int index)
+    {
+        return ints[index];
+    }
+    
+    /**
+     * Get the value of the String at the given index (0 to NUM_STRINGS-1, inclusive).
+     * <p>
+     * The default value is the empty String.
+     */
+    public String getString(int index)
+    {
+        return strings[index] == null ? "" : strings[index];
+    }
+    
+    /**
+     * Set the value of the int at the given index (0 to NUM_INTS-1, inclusive).
+     * 
+     * <p>Note that to store this value permanently, you must later call store().
+     */
+    public void setInt(int index, int value)
+    {
+        ints[index] = value;
+    }
+
+    /**
+     * Get the value of the String at the given index (0 to NUM_STRINGS-1, inclusive).
+     * Passing null is treated as a blank string.  The given String must be of STRING_LENGTH_LIMIT
+     * characters or less (or else the method will fail).
+     * 
+     * <p>Note that to store this value permanently, you must later call store().
+     */
+    public void setString(int index, String value)
+    {
+        if (value != null && value.length() > STRING_LENGTH_LIMIT)
+        {
+            System.err.println("Error: tried to store a String of length " + value.length() + " in UserInfo, which is longer than UserInfo.STRING_LENGTH_LIMIT (" + STRING_LENGTH_LIMIT + ")");
+        }
+        else
+        {
+            strings[index] = value;
+        }
+    }
+    
+    /**
+     * Get the user's score.  By default, this is zero.
+     */
+    public int getScore()
+    {
+        return score;
+    }
+    
+    /**
+     * Set the user's score.
+     * <p>
+     * Note that this really does set the user's score.  If you want to record only the user's highest
+     * score, you must code that yourself, using something like:
+     * <pre>
+     *   if (latestScore > userData.getScore())
+     *   {
+     *     userData.setScore(latestScore);
+     *   }
+     * </pre>
+     * Without some code like this, you'll always overwrite the user's previous score.
+     * 
+     * <p>Note that to store this value permanently, you must later call store().
+     */
+    public void setScore(int score)
+    {
+        this.score = score;
+    }
+    
+    /**
+     * Get the users overall rank for this scenario.
+     * <p>
+     * The user with the highest score will return 1, the user with the second highest score
+     * will return 2, and so on.  Players with equal scores will get equal ranks,
+     * so rank will not necessarily be unique.  To find the rank, scores are sorted
+     * in descending order (highest score first).  If your scores need to be lowest-first,
+     * one trick is to store them as negative numbers.
+     * <p>
+     * If the rank is unavailable (e.g. because the data hasn't been stored yet), this function will return -1.
+     */
+    public int getRank()
+    {
+        return rank;
+    }
+    
+    /**
+     * Indicate whether storage is available.
+     * <p>
+     * Storage is unavailable if the scenario is run as an applet outside the Greenfoot website,
+     * or as a stand-alone application,
+     * or if the user is not logged in to the Greenfoot website.  This last case is very common,
+     * so you should check this function before attempting to use the other static storage functions.
+     * If this function returns false, your scenario should proceed without using storage.
+     */
+    public static boolean isStorageAvailable()
+    {
+        // Returns false for applets when not on the Gallery, and stand-alone applications
+        // Returns true for inside Greenfoot, and applets on the gallery
+        return GreenfootUtil.isStorageSupported();
+    }
+    
+    /**
+     * Get the data stored for the current user.
+     * 
+     * This method returns null if:
+     * <ul>
+     * <li>there is a problem reading the local storage.csv file (for local scenarios), or</li>
+     * <li>the scenario is running as a stand-alone application, or applet on your own website, or</li>
+     * <li>there is a problem connecting to the server (for scenarios on the greenfoot.org site), or</li>
+     * <li>the user is not logged in (for scenarios on the greenfoot.org site).</li>
+     * </ul>
+     * 
+     * The last case is very common, so you should always be ready to handle a null return from this function.
+     * 
+     * @return the user's data, or null if there was a problem.
+     */
+    public static UserInfo getMyInfo()
+    {
+        return GreenfootUtil.getCurrentUserInfo();
+    }
+    
+    /**
+     * Store the data to the server.
+     * <p>
+     * You can only store data for the current user (that is, data retrieved using getMyData).
+     * If you try to store data for any user other than the current user, it is guaranteed to fail.
+     * 
+     * @return true if stored successfully, false if there was a problem.
+     */
+    public boolean store()
+    {
+        boolean success = GreenfootUtil.storeCurrentUserInfo(this);
+        
+        if (success)
+        {
+            //Update the rank (not very efficient, but simple):
+            rank = getMyInfo().rank;
+        }
+        
+        return success;
+    }
+    
+    /**
+     * Get a sorted list of the UserInfo items for this scenario, starting at the top.
+     * 
+     * <p>This will return one UserInfo item per user, and it will be sorted in descending order by the score
+     * (i.e. the return of getScore()).  The parameter allows you to specify a limit
+     * on the amount of users' data to retrieve.  If there is lots of data stored
+     * for users in your app, it may take some time (and bandwidth) to retrieve all users' data,
+     * and often you do not need all the users' data.</p>
+     * 
+     * <p>For example, if you want to show the high-scores, store the score with setScore(score) and store(),
+     * and then use getTop(10) to get the users with the top ten scores.</p> 
+     * 
+     * <p>Returns null if:
+     * <ul>
+     * <li>there is a problem reading the local file (for local scenarios), or</li>
+     * <li>the scenario is running as a stand-alone application, or applet on your own website, or</li>
+     * <li>there is a problem connecting to the server (for scenarios on the greenfoot.org site).</li>
+     * </ul>
+     * You should always be ready to handle a null return from this function.</p>
+     * 
+     * @param maxAmount The maximum number of data items to retrieve.
+     * Passing zero or a negative number will get all the data, but see the note above.  
+     * @return A list where each item is a UserInfo, or null if there was a problem
+     */
+    public static List getTop(int maxAmount)
+    {
+        // Will return an empty list if there is no previously stored data
+        // Each item is a UserInfo
+        return GreenfootUtil.getTopUserInfo(maxAmount);
+    }
+    
+    /**
+     * Get a sorted list of the UserInfo items for this scenario surrounding the current user.
+     * 
+     * <p>This will be one item per user, and it will be sorted in descending order by the score
+     * (i.e. the return of getScore()).  The parameter allows you to specify a limit
+     * on the amount of users' data to retrieve.  If there is lots of data stored
+     * for users in your app, this may take some time (and bandwidth) to retrieve all users' data,
+     * and often you do not need all the users' data.</p>
+     * 
+     * <p>The items will be those surrounding the current user.  So for example, imagine that the user is 50th
+     * of 100 total users (when sorted by getScore()).  Calling getNearby(5) will get the
+     * 48th, 49th, 50th, 51st and 52nd users in that order.  Do not rely on the user being at a fixed
+     * location in the middle of the list: calling getNearby(5) when the user is 2nd overall will get the
+     * 1st, 2nd, 3rd, 4th and 5th users, so the user will be 2nd in the list, and a similar thing will happen
+     * if the user is near the end of the list.</p>
+     * 
+     * <p>For example, if you want to show the high-scores surrounding the user, store the score with setScore(score) and store(),
+     * and then use getNearby(10) to get the ten users with scores close to the current user.</p>
+     * 
+     * <p>Returns null if:
+     * <ul>
+     * <li>there is a problem reading the local file (for local scenarios), or</li>
+     * <li>the scenario is running as a stand-alone application, or applet on your own website, or</li>
+     * <li>there is a problem connecting to the server (for scenarios on the greenfoot.org site), or</li>
+     * <li>the user is not logged in (for scenarios on the greenfoot.org site).</li>
+     * </ul>
+     * The last case is very common, so you should always be ready to handle a null return from this function.</p>
+
+     * 
+     * @param maxAmount The maximum number of data items to retrieve.
+     *            Passing zero or a negative number will get all the data, but see the note above.  
+     * @return A list where each item is a UserInfo, or null if there was a problem
+     */
+    public static List getNearby(int maxAmount)
+    {
+        return GreenfootUtil.getNearbyUserData(maxAmount);
+    }
+    
+    /**
+     * Return an image of the user. The image size is 50x50 pixels.
+     * <p>
+     * On the Greenfoot website, this is their profile picture. 
+     * If running locally (or a profile picture is unavailable), this method returns a dummy image with the username drawn on the image.
+     *
+     * @return A 50x50 pixel GreenfootImage
+     */
+    public GreenfootImage getUserImage()
+    {
+        return GreenfootUtil.getUserImage(userName);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/UserInfoVisitor.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/UserInfoVisitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca65fcd9084bd3ecf03297c7f0bd3e2d0c599003
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/UserInfoVisitor.java
@@ -0,0 +1,52 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011, 2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+public class UserInfoVisitor
+{
+    private static UserInfo myInfo;
+    
+    public static UserInfo allocate(String userName, int rank, String singletonUserName)
+    {
+        if (singletonUserName != null && singletonUserName.equals(userName))
+        {
+            if (myInfo != null && myInfo.getUserName().equals(singletonUserName))
+            {
+                myInfo.setRank(rank);
+            }
+            else
+            {
+                myInfo = new UserInfo(userName, rank);
+            }
+            return myInfo;
+        }
+        else
+        {
+            return new UserInfo(userName, rank);
+        }
+    }
+    
+    public static GreenfootImage readImage(byte[] imageFileContents)
+    {
+        return new GreenfootImage(imageFileContents);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/World.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/World.java
new file mode 100644
index 0000000000000000000000000000000000000000..b94839b847fdf3fec795c0401a3a9f14bc6200a6
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/World.java
@@ -0,0 +1,861 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import greenfoot.collision.ColManager;
+import greenfoot.collision.CollisionChecker;
+import greenfoot.collision.ibsp.Rect;
+import greenfoot.core.WorldHandler;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * World is the world that Actors live in. It is a two-dimensional grid of
+ * cells.
+ * 
+ * <p>
+ * All Actor are associated with a World and can get access to the world object.
+ * The size of cells can be specified at world creation time, and is constant
+ * after creation. Simple scenarios may use large cells that entirely contain
+ * the representations of objects in a single cell. More elaborate scenarios may
+ * use smaller cells (down to single pixel size) to achieve fine-grained
+ * placement and smoother animation.
+ * 
+ * <p>
+ * The world background can be decorated with drawings or images.
+ * 
+ * @see greenfoot.Actor
+ * @author Poul Henriksen
+ * @author Michael Kolling
+ * @version 2.4
+ */
+public abstract class World {
+  private static final Color DEFAULT_BACKGROUND_COLOR = Color.WHITE;
+
+  // private CollisionChecker collisionChecker = new GridCollisionChecker();
+  // private CollisionChecker collisionChecker = new BVHInsChecker();
+  private CollisionChecker collisionChecker = new ColManager();
+
+  // {
+  // collisionChecker = new CollisionProfiler(collisionChecker);
+  // }
+
+  // One or two sets can be used to store objects in different orders.
+  // Initially only the disordered set will be used, if later we need
+  // ordering, the disordered set might be used for an ordered set. If two
+  // orderings are used at the same time a new set will be created for the
+  // second set.
+  private TreeActorSet objectsDisordered = new TreeActorSet();
+  private TreeActorSet objectsInPaintOrder;
+  private TreeActorSet objectsInActOrder;
+
+  /** The size of the cell in pixels. */
+  int cellSize = 1;
+
+  /** Size of the world */
+  int width;
+  int height;
+
+  /** Image painted in the background. */
+  private GreenfootImage backgroundImage;
+
+  /** Whether the backgroundImage is the class image */
+  private boolean backgroundIsClassImage = true;
+
+  /** Whether actors are bound to stay inside the world */
+  private boolean isBounded;
+
+  /**
+   * Construct a new world. The size of the world (in number of cells) and the
+   * size of each cell (in pixels) must be specified.
+   * 
+   * @param worldWidth
+   *          The width of the world (in cells).
+   * @param worldHeight
+   *          The height of the world (in cells).
+   * @param cellSize
+   *          Size of a cell in pixels.
+   */
+  public World(int worldWidth, int worldHeight, int cellSize) {
+    this(worldWidth, worldHeight, cellSize, true);
+  }
+
+  /**
+   * Construct a new world. The size of the world (in number of cells) and the
+   * size of each cell (in pixels) must be specified. This constructor allows
+   * the option of creating an unbounded world, which actors can move outside
+   * the boundaries of.
+   * 
+   * @param worldWidth
+   *          The width of the world (in cells).
+   * @param worldHeight
+   *          The height of the world (in cells).
+   * @param cellSize
+   *          Size of a cell in pixels.
+   * @param bounded
+   *          Should actors be restricted to the world boundary?
+   */
+  public World(int worldWidth, int worldHeight, int cellSize, boolean bounded) {
+    initialize(worldWidth, worldHeight, cellSize);
+    this.isBounded = bounded;
+
+    backgroundIsClassImage = true;
+    setBackground(getClassImage());
+
+    // Now, the WorldHandler must be informed of the new world, so it can be
+    // used immediately. This is important for actors that are created by
+    // the world constructor, if the actors are accessing the world in their
+    // constructors (by using getWidth/Height for instance)
+    final WorldHandler wHandler = WorldHandler.getInstance();
+    if (wHandler != null) { // will be null when running unit tests.
+      wHandler.setInitialisingWorld(this);
+    }
+  }
+
+  /**
+   * Set a background image for the world. If the image size is larger than the
+   * world in pixels, it is clipped. If it is smaller than the world, it is
+   * tiled. A pattern showing the cells can easily be shown by setting a
+   * background image with a size equal to the cell size.
+   * 
+   * @see #setBackground(String)
+   * @param image
+   *          The image to be shown
+   */
+  final public void setBackground(GreenfootImage image) {
+    if (image != null) {
+      int imgWidth = image.getWidth();
+      int imgHeight = image.getHeight();
+      int worldWidth = getWidthInPixels();
+      int worldHeight = getHeightInPixels();
+      boolean tile = imgWidth < worldWidth || imgHeight < worldHeight;
+
+      if (tile) {
+        backgroundIsClassImage = false;
+        backgroundImage = new GreenfootImage(worldWidth, worldHeight);
+        backgroundImage.setColor(DEFAULT_BACKGROUND_COLOR);
+        backgroundImage.fill();
+
+        for (int x = 0; x < worldWidth; x += imgWidth) {
+          for (int y = 0; y < worldHeight; y += imgHeight) {
+            backgroundImage.drawImage(image, x, y);
+          }
+        }
+      } else {
+        // To make it behave exactly the same way as when tiling we
+        // should make a clone here. But it performs better when not
+        // cloning.
+        // Performance will be an issue for people changing the
+        // background image all the time for animated backgrounds
+        backgroundImage = image;
+      }
+    } else {
+      backgroundIsClassImage = false;
+      backgroundImage = null;
+    }
+  }
+
+  /**
+   * Set a background image for the world from an image file. Images of type
+   * 'jpeg', 'gif' and 'png' are supported. If the image size is larger than the
+   * world in pixels, it is clipped. A pattern showing the cells can easily be
+   * shown by setting a background image with a size equal to the cell size.
+   * 
+   * @see #setBackground(GreenfootImage)
+   * @param filename
+   *          The file holding the image to be shown
+   * @throws IllegalArgumentException
+   *           If the image can not be loaded.
+   */
+  final public void setBackground(String filename)
+      throws IllegalArgumentException {
+    GreenfootImage bg = new GreenfootImage(filename);
+    setBackground(bg);
+  }
+
+  /**
+   * Return the world's background image. The image may be used to draw onto the
+   * world's background.
+   * 
+   * @return The background image
+   */
+  public GreenfootImage getBackground() {
+    if (backgroundImage == null) {
+      backgroundImage = new GreenfootImage(getWidthInPixels(),
+          getHeightInPixels());
+      backgroundImage.setColor(DEFAULT_BACKGROUND_COLOR);
+      backgroundImage.fill();
+      backgroundIsClassImage = false;
+    } else if (backgroundIsClassImage) {
+      // Make the image a copy of the original to avoid modifications
+      // to the original.
+      backgroundImage = backgroundImage.getCopyOnWriteClone();
+      backgroundIsClassImage = false;
+    }
+    return backgroundImage;
+  }
+
+  /**
+   * Return the color at the centre of the cell. To paint a color, you need to
+   * get the background image for the world and paint on that.
+   *
+   * @param x
+   *          The x coordinate of the cell.
+   * @param y
+   *          The y coordinate of the cell.
+   * @see #getBackground()
+   * @throws IndexOutOfBoundsException
+   *           If the location is not within the world bounds. If there is no
+   *           background image at the location it will return Color.WHITE.
+   */
+  public Color getColorAt(int x, int y) {
+    ensureWithinXBounds(x);
+    ensureWithinYBounds(y);
+
+    int xPixel = (int) Math.floor(getCellCenter(x));
+    int yPixel = (int) Math.floor(getCellCenter(y));
+
+    if (xPixel >= backgroundImage.getWidth()) {
+      return DEFAULT_BACKGROUND_COLOR;
+    }
+    if (yPixel >= backgroundImage.getHeight()) {
+      return DEFAULT_BACKGROUND_COLOR;
+    }
+
+    return backgroundImage.getColorAt(xPixel, yPixel);
+  }
+
+  /**
+   * @return The world's width in number of cells.
+   */
+  public int getWidth() {
+    return width;
+  }
+
+  /**
+   * @return The world's height in number of cells.
+   */
+  public int getHeight() {
+    return height;
+  }
+
+  /**
+   * @return the size of a cell in pixels.
+   */
+  public int getCellSize() {
+    return cellSize;
+  }
+
+  /**
+   * Set the paint order of objects in the world. Paint order is specified by
+   * class: objects of one class will always be painted on top of objects of
+   * some other class. The order of objects of the same class cannot be
+   * specified. Objects of classes listed first in the parameter list will
+   * appear on top of all objects of classes listed later.
+   * <p>
+   * Objects of a class not explicitly specified effectively inherit the paint
+   * order from their superclass.
+   * <p>
+   * Objects of classes not listed will appear below the objects whose classes
+   * have been specified.
+   * 
+   * @param classes
+   *          The classes in desired paint order
+   */
+  @SuppressWarnings("unchecked")
+  public void setPaintOrder(Class... classes) {
+    if (classes == null) {
+      // Allow null as an argument, to specify no paint order
+      if (objectsInPaintOrder == objectsDisordered) {
+        if (objectsInActOrder == null) {
+          classes = new Class[0];
+          objectsDisordered.setClassOrder(true, classes);
+        } else {
+          objectsDisordered = objectsInActOrder;
+        }
+      }
+      objectsInPaintOrder = null;
+      return;
+    }
+
+    if (objectsInPaintOrder != null) {
+      // Just reuse existing set
+    } else if (objectsInActOrder == objectsDisordered) {
+      // Use new set because existing disordered set is in use
+      // already.
+      objectsInPaintOrder = new TreeActorSet();
+      objectsInPaintOrder.setClassOrder(true, classes);
+      objectsInPaintOrder.addAll(objectsDisordered);
+      return;
+    } else {
+      // Reuse disordered set, since it is not already in use by the
+      // act ordering
+      objectsInPaintOrder = objectsDisordered;
+    }
+    objectsInPaintOrder.setClassOrder(true, classes);
+  }
+
+  /**
+   * Set the act order of objects in the world. Act order is specified by class:
+   * objects of one class will always act before objects of some other class.
+   * The order of objects of the same class cannot be specified.
+   * 
+   * <p>
+   * Objects of classes listed first in the parameter list will act before any
+   * objects of classes listed later.
+   * 
+   * <p>
+   * Objects of a class not explicitly specified inherit the act order from
+   * their superclass.
+   * 
+   * <p>
+   * Objects of classes not listed will act after all objects whose classes have
+   * been specified.
+   * 
+   * @param classes
+   *          The classes in desired act order
+   */
+  @SuppressWarnings("unchecked")
+  public void setActOrder(Class... classes) {
+    if (classes == null) {
+      // Allow null as an argument, to specify no paint order
+      if (objectsInActOrder == objectsDisordered) {
+        if (objectsInPaintOrder == null) {
+          classes = new Class[0];
+          objectsDisordered.setClassOrder(false, classes);
+        } else {
+          objectsDisordered = objectsInPaintOrder;
+        }
+      }
+      objectsInActOrder = null;
+      return;
+    }
+
+    if (objectsInActOrder != null) {
+      // Just reuse existing set
+    } else if (objectsInPaintOrder == objectsDisordered) {
+      // Use new set because existing disordered set is in use
+      // already.
+      objectsInActOrder = new TreeActorSet();
+      objectsInActOrder.setClassOrder(false, classes);
+      objectsInActOrder.addAll(objectsDisordered);
+      return;
+    } else {
+      // Reuse disordered set, since it is not already in use by the
+      // paint ordering
+      objectsInActOrder = objectsDisordered;
+    }
+    objectsInActOrder.setClassOrder(false, classes);
+  }
+
+  /**
+   * Add an Actor to the world.
+   * 
+   * @param object
+   *          The new object to add.
+   * @param x
+   *          The x coordinate of the location where the object is added.
+   * @param y
+   *          The y coordinate of the location where the object is added.
+   */
+  public void addObject(Actor object, int x, int y) {
+    if (object.world != null) {
+      if (object.world == this) {
+        return; // Actor is already in the world
+      }
+      object.world.removeObject(object);
+    }
+
+    objectsDisordered.add(object);
+    addInPaintOrder(object);
+    addInActOrder(object);
+
+    // Note we must call this before adding the object to the collision checker,
+    // so that the cached bounds are cleared:
+    object.addToWorld(x, y, this);
+
+    collisionChecker.addObject(object);
+    object.addedToWorld(this);
+
+    WorldHandler whInstance = WorldHandler.getInstance();
+    if (whInstance != null) {
+      WorldHandler.getInstance().objectAddedToWorld(object);
+    }
+  }
+
+  /**
+   * Remove an object from the world.
+   * 
+   * @param object
+   *          the object to remove
+   */
+  public void removeObject(Actor object) {
+    if (object == null || object.world != this) {
+      return;
+    }
+
+    objectsDisordered.remove(object);
+    collisionChecker.removeObject(object);
+    if (objectsDisordered != objectsInActOrder && objectsInActOrder != null) {
+      objectsInActOrder.remove(object);
+    } else if (objectsDisordered != objectsInPaintOrder
+        && objectsInPaintOrder != null) {
+      objectsInPaintOrder.remove(object);
+    }
+    object.setWorld(null);
+  }
+
+  /**
+   * Remove a list of objects from the world.
+   * 
+   * @param objects
+   *          A list of Actors to remove.
+   */
+  @SuppressWarnings("unchecked")
+  public void removeObjects(Collection objects) {
+    for (Iterator iter = objects.iterator(); iter.hasNext();) {
+      Actor actor = (Actor) iter.next();
+      removeObject(actor);
+    }
+  }
+
+  /**
+   * Get all the objects in the world, or all the objects of a particular class.
+   * <p>
+   * If a class is specified as a parameter, only objects of that class (or its
+   * subclasses) will be returned.
+   * <p>
+   * 
+   * @param cls
+   *          Class of objects to look for ('null' will find all objects).
+   * 
+   * @return A list of objects.
+   */
+  @SuppressWarnings("unchecked")
+  public List getObjects(Class cls) {
+    List<Actor> result = new ArrayList<Actor>();
+
+    Iterator<Actor> i = objectsDisordered.iterator();
+    while (i.hasNext()) {
+      Actor actor = i.next();
+      if (cls == null || cls.isInstance(actor)) {
+        result.add(actor);
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * Get the number of actors currently in the world.
+   * 
+   * @return The number of actors
+   */
+  public int numberOfObjects() {
+    return objectsDisordered.size();
+  }
+
+  /**
+   * Repaints the world.
+   */
+  public void repaint() {
+    WorldHandler.getInstance().repaintAndWait();
+  }
+
+  /**
+   * Act method for world. The act method is called by the greenfoot framework
+   * at each action step in the environment. The world's act method is called
+   * before the act method of any objects in the world.
+   * <p>
+   * 
+   * This method does nothing. It should be overridden in subclasses to
+   * implement an world's action.
+   */
+  public void act() {
+    // by default, do nothing
+  }
+
+  /**
+   * This method is called by the Greenfoot system when the execution has
+   * started. This method can be overridden to implement custom behaviour when
+   * the execution is started.
+   * <p>
+   * This default implementation is empty.
+   */
+  public void started() {
+    // by default, do nothing
+  }
+
+  /**
+   * This method is called by the Greenfoot system when the execution has
+   * stopped. This method can be overridden to implement custom behaviour when
+   * the execution is stopped.
+   * <p>
+   * This default implementation is empty.
+   */
+  public void stopped() {
+    // by default, do nothing
+  }
+
+  // =================================================
+  //
+  // COLLISION STUFF
+  //
+  // =================================================
+
+  /**
+   * Return all objects at a given cell.
+   * <p>
+   * 
+   * An object is defined to be at that cell if its graphical representation
+   * overlaps the center of the cell.
+   * 
+   * @param x
+   *          X-coordinate of the cell to be checked.
+   * @param y
+   *          Y-coordinate of the cell to be checked.
+   * @param cls
+   *          Class of objects to look return ('null' will return all objects).
+   */
+  @SuppressWarnings("unchecked")
+  public List getObjectsAt(int x, int y, Class cls) {
+    return collisionChecker.getObjectsAt(x, y, cls);
+  }
+
+  // =================================================
+  // PACKAGE-PROTECTED METHODS
+  //
+  // used by other classes internally in Greenfoot
+  // =================================================
+
+  /**
+   * Return the world's background image but without initialising it first
+   * 
+   * @return The background image or null if not initialised yet.
+   */
+  GreenfootImage getBackgroundNoInit() {
+    return backgroundImage;
+  }
+
+  /**
+   * Test whether this world is bounded.
+   */
+  boolean isBounded() {
+    return isBounded;
+  }
+
+  /**
+   * Return all the objects that intersect the given object. This takes the
+   * graphical extent of objects into consideration.
+   * 
+   * @param actor
+   *          An Actor in the world
+   * @param cls
+   *          Class of objects to look for (null or Object.class will find all
+   *          classes)
+   */
+  @SuppressWarnings("unchecked")
+  List getIntersectingObjects(Actor actor, Class cls) {
+    return collisionChecker.getIntersectingObjects(actor, cls);
+  }
+
+  /**
+   * Returns all objects with the logical location within the specified circle.
+   * In other words an object A is within the range of an object B if the
+   * distance between the centre of the two objects is less than r.
+   * 
+   * @param x
+   *          Centre of the cirle
+   * @param y
+   *          Centre of the cirle
+   * @param r
+   *          Radius of the cirle
+   * @param cls
+   *          Class of objects to look for (null or Object.class will find all
+   *          classes)
+   */
+  @SuppressWarnings("unchecked")
+  List getObjectsInRange(int x, int y, int r, Class cls) {
+    return collisionChecker.getObjectsInRange(x, y, r, cls);
+  }
+
+  /**
+   * Returns the neighbours to the given location. This method only looks at the
+   * logical location and not the extent of objects. Hence it is most useful in
+   * scenarios where objects only span one cell.
+   *
+   * @param actor
+   *          The actor whose neighbours to locate
+   * @param distance
+   *          Distance in which to look for other objects
+   * @param diag
+   *          Is the distance also diagonal?
+   * @param cls
+   *          Class of objects to look for (null or Object.class will find all
+   *          classes)
+   * @return A collection of all neighbours found
+   */
+  @SuppressWarnings("unchecked")
+  List getNeighbours(Actor actor, int distance, boolean diag, Class cls) {
+    if (distance < 0) {
+      throw new IllegalArgumentException(
+          "Distance must not be less than 0. It was: " + distance);
+    }
+    return collisionChecker.getNeighbours(actor, distance, diag, cls);
+  }
+
+  /**
+   * Return all objects that intersect a straight line from the location at a
+   * specified angle. The angle is clockwise.
+   * 
+   * @param x
+   *          x-coordinate
+   * @param y
+   *          y-coordinate
+   * @param angle
+   *          The angle relative to current rotation of the object. (0-359)
+   * @param length
+   *          How far we want to look (in cells)
+   * @param cls
+   *          Class of objects to look for (passing 'null' will find all
+   *          objects).
+   */
+  @SuppressWarnings("unchecked")
+  List getObjectsInDirection(int x0, int y0, int angle, int length, Class cls) {
+    return collisionChecker.getObjectsInDirection(x0, y0, angle, length, cls);
+  }
+
+  /**
+   * Get the height of the world in pixels.
+   */
+  int getHeightInPixels() {
+    return height * cellSize;
+  }
+
+  /**
+   * Get the width of the world in pixels.
+   */
+  int getWidthInPixels() {
+    return width * cellSize;
+  }
+
+  /**
+   * Converts the pixel location into a cell, rounding up.
+   */
+  int toCellCeil(int pixel) {
+    return (int) Math.ceil((double) pixel / cellSize);
+  }
+
+  /**
+   * Converts the pixel location into a cell, rounding down.
+   */
+  int toCellFloor(int pixel) {
+    return (int) Math.floor((double) pixel / cellSize);
+  }
+
+  /**
+   * Returns the centre of the cell. It should be rounded down with Math.floor()
+   * if the integer version is needed.
+   * 
+   * @param l
+   *          Cell location.
+   * @return Absolute location of the cell centre in pixels.
+   */
+  double getCellCenter(int l) {
+    double cellCenter = l * cellSize + cellSize / 2.;
+    return cellCenter;
+  }
+
+  Collection<Actor> getObjectsAtPixel(int x, int y) {
+    // This is a very naive and slow way of getting the objects at a given
+    // pixel.
+    // However, it makes sure that it doesn't use the collision checker
+    // which we want to keep optimised.
+    // It will be very slow with a lot of rotated objects. It is only used
+    // when using the mouse to select objects, which is not a time-critical
+    // task.
+
+    List<Actor> result = new LinkedList<Actor>();
+    TreeActorSet objects = getObjectsListInPaintOrder();
+    for (Actor actor : objects) {
+      Rect bounds = actor.getBoundingRect();
+      if (x >= bounds.getX() && x <= bounds.getRight() && y >= bounds.getY()
+          && y <= bounds.getTop()) {
+        if (actor.containsPoint(x, y)) {
+          result.add(actor);
+        }
+      }
+    }
+
+    return result;
+  }
+
+  void updateObjectLocation(Actor object, int oldX, int oldY) {
+    collisionChecker.updateObjectLocation(object, oldX, oldY);
+  }
+
+  void updateObjectSize(Actor object) {
+    collisionChecker.updateObjectSize(object);
+  }
+
+  /**
+   * Used to indicate the start of an animation sequence. For use in the
+   * collision checker.
+   * 
+   * @see greenfoot.collision.CollisionChecker#startSequence()
+   */
+  void startSequence() {
+    collisionChecker.startSequence();
+  }
+
+  @SuppressWarnings("unchecked")
+  Actor getOneObjectAt(Actor object, int dx, int dy, Class cls) {
+    return collisionChecker.getOneObjectAt(object, dx, dy, cls);
+  }
+
+  @SuppressWarnings("unchecked")
+  Actor getOneIntersectingObject(Actor object, Class cls) {
+    return collisionChecker.getOneIntersectingObject(object, cls);
+  }
+
+  /**
+   * Get the list of all objects in the world. This returns a live list which
+   * should not be modified by the caller. If iterating over this list, it
+   * should be synchronized on itself or the World to avoid concurrent
+   * modifications.
+   */
+  TreeActorSet getObjectsListInPaintOrder() {
+    if (objectsInPaintOrder != null) {
+      return objectsInPaintOrder;
+    } else {
+      return objectsDisordered;
+    }
+  }
+
+  /**
+   * Get the list of all objects in the world. This returns a live list which
+   * should not be modified by the caller. The world lock must be held while
+   * iterating over this list.
+   */
+  TreeActorSet getObjectsListInActOrder() {
+    if (objectsInActOrder != null) {
+      return objectsInActOrder;
+    } else {
+      return objectsDisordered;
+    }
+  }
+
+  void paintDebug(Graphics g) {
+    /*
+     * g.setColor(Color.BLACK); g.drawString("# of Objects: " + objects.size(),
+     * 50,50);
+     */
+    // collisionChecker.paintDebug(g);
+  }
+
+  // =================================================
+  //
+  // PRIVATE MEHTHODS
+  //
+  // =================================================
+
+  /**
+   * Sets the size of the world.
+   */
+  private void initialize(int width, int height, int cellSize) {
+    this.width = width;
+    this.height = height;
+    this.cellSize = cellSize;
+    collisionChecker.initialize(width, height, cellSize, false);
+  }
+
+  /**
+   * Get the default image for objects of this class. May return null.
+   */
+  private GreenfootImage getClassImage() {
+    Class<?> clazz = getClass();
+    while (clazz != null) {
+      GreenfootImage image = null;
+      try {
+        image = Actor.getDelegate().getImage(clazz.getName());
+      } catch (Throwable e) {
+        // Ignore exception and continue looking for images
+      }
+      if (image != null) {
+        return image;
+      }
+      clazz = clazz.getSuperclass();
+    }
+
+    return null;
+  }
+
+  /**
+   * Methods that throws an exception if the location is out of bounds.
+   * 
+   * @throws IndexOutOfBoundsException
+   */
+  private void ensureWithinXBounds(int x) throws IndexOutOfBoundsException {
+    if (x >= getWidth()) {
+      throw new IndexOutOfBoundsException("The x-coordinate is: " + x
+          + ". It must be smaller than: " + getWidth());
+    }
+    if (x < 0) {
+      throw new IndexOutOfBoundsException("The x-coordinate is: " + x
+          + ". It must be larger than: 0");
+    }
+  }
+
+  /**
+   * Methods that throws an exception if the location is out of bounds.
+   * 
+   * @throws IndexOutOfBoundsException
+   */
+  private void ensureWithinYBounds(int y) throws IndexOutOfBoundsException {
+    if (y >= getHeight()) {
+      throw new IndexOutOfBoundsException("The y-coordinate is: " + y
+          + ". It must be smaller than: " + getHeight());
+    }
+    if (y < 0) {
+      throw new IndexOutOfBoundsException("The x-coordinate is: " + y
+          + ". It must be larger than: 0");
+    }
+  }
+
+  private void addInActOrder(Actor object) {
+    if (objectsInActOrder != null) {
+      objectsInActOrder.add(object);
+    }
+  }
+
+  private void addInPaintOrder(Actor object) {
+    if (objectsInPaintOrder != null) {
+      objectsInPaintOrder.add(object);
+    }
+  }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/WorldVisitor.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/WorldVisitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..a1f7c6e8fa7a71c063c5bf476734c29c43c4f9e4
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/WorldVisitor.java
@@ -0,0 +1,129 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot;
+
+import java.awt.Graphics;
+import java.util.Collection;
+
+/**
+ * Class that makes it possible for classes outside the greenfoot package to get
+ * access to world methods that are package protected. We need some
+ * package-protected methods in the world, because we don't want them to show up
+ * in the public interface visible to users.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class WorldVisitor
+{
+    public static int getWidthInCells(World w)
+    {
+        return w.width;
+    }
+    
+    public static int getHeightInCells(World w)
+    {
+        return w.height;
+    }
+    
+    public static int getWidthInPixels(World w)
+    {
+        return w.getWidthInPixels();
+    }
+
+    public static int getHeightInPixels(World w)
+    {
+        return w.getHeightInPixels();
+    }
+
+    public static int getCellSize(World w)
+    {
+        return w.cellSize;
+    }
+    
+    public static Collection<Actor> getObjectsAtPixel(World w, int x, int y)
+    {
+        return w.getObjectsAtPixel(x, y);
+    }
+
+    /**
+     * Used to indicate the start of an animation sequence. For use in the collision checker.
+     * @see greenfoot.collision.CollisionChecker#startSequence()
+     */
+    public static void startSequence(World w)
+    {
+        w.startSequence();
+    }
+
+    public static void paintDebug(World world, Graphics g)
+    {
+        world.paintDebug(g);
+    }
+    
+    /**
+     * Convert a location in pixels into a cell location
+     */
+    public static int toCellFloor(World world, int x)
+    {
+        return world.toCellFloor(x);
+    }
+    
+    /**
+     * Returns the center of the cell. It should be rounded down with Math.floor() if the integer version is needed.
+     * @param l Cell location.
+     * @return Absolute location of the cell center in pixels.
+     */
+    public static  double getCellCenter(World w, int c)
+    {
+        return w.getCellCenter(c);
+    }
+    
+    /**
+     * Get the list of all objects in the world. This returns a live list which
+     * should not be modified by the caller. If iterating over this list, it
+     * should be synchronized on the world lock.
+     */
+    public static TreeActorSet getObjectsListInPaintOrder(World world)
+    {
+        return world.getObjectsListInPaintOrder(); 
+    }
+    
+    /**
+     * Get the list of all objects in the world. This returns a live list which
+     * should not be modified by the caller. If iterating over this list, it
+     * should be synchronized on itself or the World to avoid concurrent
+     * modifications.
+     */
+    public static TreeActorSet getObjectsListInActOrder(World world)
+    {
+        return world.getObjectsListInActOrder(); 
+    }
+
+    /**
+     * Get the background image for the world, but without initialising it if it is not yet created.
+     * 
+     * @return Background of the world or null if not create yet.
+     */
+    public static GreenfootImage getBackgroundImage(World world)
+    {
+        return world.getBackgroundNoInit();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/AboutGreenfootAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/AboutGreenfootAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..555d1bced20dfdb7028272e7095ddca140b34ef7
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/AboutGreenfootAction.java
@@ -0,0 +1,69 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.gui.AboutGreenfootDialog;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFrame;
+
+import bluej.Boot;
+import bluej.Config;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id$
+ */
+public class AboutGreenfootAction extends AbstractAction
+{
+    private static AboutGreenfootAction instance;
+    
+     /**
+     * Singleton factory method for action.
+     */
+    public static AboutGreenfootAction getInstance(JFrame parent)
+    {
+        if(instance == null)
+            instance = new AboutGreenfootAction(parent);
+        return instance;
+    }
+    
+    
+    private AboutGreenfootDialog aboutGreenfoot;
+    private JFrame parent;
+
+    private AboutGreenfootAction(JFrame parent)
+    {
+        super(Config.getString("greenfoot.about"));
+        this.parent = parent;
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+        if (aboutGreenfoot == null) {
+            aboutGreenfoot = new AboutGreenfootDialog(parent, Boot.GREENFOOT_VERSION);
+        }
+        aboutGreenfoot.setVisible(true);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/BrowseImagesAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/BrowseImagesAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..56e65808b827f861badd372b1cd523b8cf4376a1
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/BrowseImagesAction.java
@@ -0,0 +1,86 @@
+/*
+ This file is part of the Greenfoot program.
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ This file is subject to the Classpath exception as provided in the
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.gui.images.ImageFilePreview;
+import greenfoot.gui.images.ImageFilter;
+import greenfoot.util.GreenfootUtil;
+import greenfoot.util.Selectable;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+
+import javax.swing.AbstractAction;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import bluej.Config;
+
+/**
+ * Action that will launch a file chooser for choosing image files. When an
+ * image file has been chosen it will be copied to the specified directory.
+ * 
+ * @author Poul Henriksen
+ */
+public class BrowseImagesAction extends AbstractAction
+{
+
+
+    private JDialog owner;
+    private File projImagesDir;
+    private Selectable<File> selectable;
+
+    /**
+     * 
+     * @param name Name of the action.
+     * @param owner The dialog that will be the parent of the file chooser.
+     * @param destDir Directory where the chosen image will be copied to.
+     * @param selectable When the file has been copied, it will select it in this selectable (if it is not null).
+     */
+    public BrowseImagesAction(String name, JDialog owner, File destDir, Selectable<File> selectable)
+    {
+        super(name);
+        this.owner = owner;
+        this.projImagesDir = destDir;
+        this.selectable = selectable;
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+        JFileChooser chooser = new JFileChooser();
+        new ImageFilePreview(chooser);
+        chooser.setAcceptAllFileFilterUsed(false);
+        ImageFilter filter = new ImageFilter();
+        chooser.addChoosableFileFilter(filter);
+        chooser.addChoosableFileFilter(chooser.getAcceptAllFileFilter());
+        chooser.setFileFilter(filter);
+        int choice = chooser.showDialog(owner, Config.getString("imagelib.choose.button"));
+        if (choice == JFileChooser.APPROVE_OPTION) {
+            File file = chooser.getSelectedFile();
+            File newFile = new File(projImagesDir, file.getName());
+            GreenfootUtil.copyFile(file, newFile);
+            if(selectable != null) {
+                selectable.select(newFile);
+            }
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ClassAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ClassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..804fb952173f752bd49b5a1498ab751e4b22b13d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ClassAction.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.classbrowser.ClassBrowser;
+import greenfoot.gui.classbrowser.ClassView;
+
+import javax.swing.AbstractAction;
+
+
+/**
+ * Superclass for actions that depends on the selected class.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: ClassAction.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public abstract class ClassAction extends AbstractAction
+{
+    private GreenfootFrame gfFrame;
+
+    public ClassAction(String name, GreenfootFrame gfFrame)
+    {
+        super(name);
+        this.gfFrame = gfFrame;
+    }
+    
+    protected ClassView getSelectedClassView()
+    {
+    	ClassBrowser classBrowser = gfFrame.getClassBrowser();
+    	Object selected = classBrowser.getSelectionManager().getSelected();
+    	if (selected instanceof ClassView) {
+    		return (ClassView) selected;
+    	}
+    	else {
+    		return null;
+    	}
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/CloseProjectAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/CloseProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae0679456dacf9ebff219120dfad3c7a4bb08b05
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/CloseProjectAction.java
@@ -0,0 +1,52 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.core.GreenfootMain;
+import greenfoot.gui.GreenfootFrame;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import bluej.Config;
+
+/**
+ * @author Poul Henriksen
+ * @version $Id$
+ */
+public class CloseProjectAction extends AbstractAction
+{
+	private GreenfootFrame gfFrame;
+    
+    public CloseProjectAction(GreenfootFrame gfFrame)
+    {
+        super(Config.getString("project.close"));
+        this.gfFrame = gfFrame;
+        setEnabled(false);
+    }
+    
+    public void actionPerformed(ActionEvent e)
+    {
+        GreenfootMain.closeProject(gfFrame, false);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/CompileAllAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/CompileAllAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..bce9e25689064807c2baf80454a29524e75da6f9
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/CompileAllAction.java
@@ -0,0 +1,71 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.core.GProject;
+import greenfoot.core.Simulation;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+/**
+ * Action that compiles all classes that needs compilation.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class CompileAllAction extends AbstractAction
+{
+    private GProject project;
+    
+    public CompileAllAction(GProject project)
+    {
+        super(Config.getString("compile.all"));
+        setProject(project);
+    }
+    
+    public void setProject(GProject project)
+    {
+        this.project = project;
+        setEnabled(project != null);
+    }
+
+    /**
+     * Compiles all classes.
+     *  
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        int numOfClasses = project.getDefaultPackage().getClasses(false).length;
+        // we only want to compile if there are classes in the project
+        if(numOfClasses < 1) {
+            return;
+        }
+        Simulation.getInstance().setPaused(true);
+        project.getDefaultPackage().compileAll();
+        
+        // Disable the action until the compilation is finished, when it
+        // will be re-enabled.
+        setEnabled(false);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/CompileClassAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/CompileClassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..d2a6a841f72f1b509829e8b8ea6772711e597483
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/CompileClassAction.java
@@ -0,0 +1,76 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.core.GClass;
+import greenfoot.core.Simulation;
+import greenfoot.gui.GreenfootFrame;
+
+import java.awt.event.ActionEvent;
+import java.rmi.RemoteException;
+
+import bluej.extensions.CompilationNotStartedException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: CompileClassAction.java 8313 2010-09-14 13:02:19Z nccb $
+ */
+public class CompileClassAction extends ClassAction
+{
+    public CompileClassAction(GreenfootFrame gfFrame)
+    {
+        super(Config.getString("compile.class"), gfFrame);
+    }
+
+    /**
+     * Compiles the currently selected class. If no class is selected it does
+     * nothing.
+     * 
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+    	GClass selectedClass = getSelectedClassView().getGClass();
+    	
+        Simulation.getInstance().setPaused(true);
+        try {
+            if (selectedClass != null) {
+                selectedClass.compile(false, false);
+            }
+        }
+        catch (RemoteException e1) {
+            e1.printStackTrace();
+        }
+        catch (ProjectNotOpenException e1) {
+            e1.printStackTrace();
+        }
+        catch (PackageNotFoundException e1) {
+            e1.printStackTrace();
+        }
+        catch (CompilationNotStartedException e1) {
+            e1.printStackTrace();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/DragProxyAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/DragProxyAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..939a68dd518608f5f8657252b917019c0fef5609
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/DragProxyAction.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009, 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.GreenfootImage;
+import greenfoot.core.ObjectDragProxy;
+import greenfoot.core.WorldHandler;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+/**
+ * An action that creates an ObjectDragProxy when performed and initiates a drag
+ * with that ObjectDragProxy.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class DragProxyAction extends AbstractAction
+{
+
+    private GreenfootImage dragImage;
+    private Action dropAction;
+
+    public DragProxyAction(GreenfootImage dragImage, Action dropAction)
+    {
+        super((String)dropAction.getValue(Action.NAME));
+        this.dragImage = dragImage;
+        this.dropAction = dropAction;
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+        ObjectDragProxy object = new ObjectDragProxy(dragImage, dropAction);
+        WorldHandler.getInstance().getInputManager().objectCreated(object);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/EditClassAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/EditClassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..acaef75d78ec9325f91cb69997da9f2ade5d40a5
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/EditClassAction.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.core.GClass;
+import greenfoot.gui.classbrowser.ClassBrowser;
+import greenfoot.gui.classbrowser.ClassView;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import bluej.Config;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class EditClassAction extends AbstractAction
+{
+	private ClassBrowser classBrowser;
+	
+    public EditClassAction(ClassBrowser classBrowser)
+    {
+        super(Config.getString("edit.class"));
+        this.classBrowser = classBrowser;
+    }
+    
+    /**
+     * Edits the currently selected class. If no class is selected it does
+     * nothing.
+     * 
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+    	ClassView selectedView = (ClassView) classBrowser.getSelectionManager().getSelected();
+    	GClass selectedClass = selectedView.getGClass();
+    	
+    	if (selectedClass != null) {
+    	    selectedClass.edit();
+    	}
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ExportProjectAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ExportProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..54cae351a1d40b50b4cd2c80f381e9d2bac2a539
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ExportProjectAction.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.export.ExportDialog;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import bluej.Config;
+
+/**
+ * Action to export a project to a standalone program.
+ * 
+ * @author Poul Henriksen, Michael Kolling
+ */
+public class ExportProjectAction extends AbstractAction 
+{
+    private ExportDialog exportDialog;
+    private GreenfootFrame gfFrame;
+    private boolean share; // The action is from the share button, so show Gallery export
+    
+    public ExportProjectAction(GreenfootFrame gfFrame, boolean share)
+    {
+        super(Config.getString("export.project"));
+        this.gfFrame = gfFrame;
+        this.share = share;
+        setEnabled(false);
+    }
+
+    public void actionPerformed(ActionEvent event)
+    {       
+        if(exportDialog == null) {
+            exportDialog = new ExportDialog(gfFrame);
+        }
+        if (share) {
+            exportDialog.selectGalleryPane();
+        }
+        exportDialog.display();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ImportClassAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ImportClassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..500cd0b7ecde9848512e74c6ad385f1a4dc1039c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ImportClassAction.java
@@ -0,0 +1,73 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.core.GClass;
+import greenfoot.core.GProject;
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.ImportClassWindow;
+import greenfoot.gui.classbrowser.ClassBrowser;
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.record.InteractionListener;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+
+import javax.swing.AbstractAction;
+import javax.swing.JOptionPane;
+
+import bluej.Config;
+
+/**
+ * The action that shows the import-class dialog
+ * (which allows you to import a supplied common class),
+ * and imports whatever you select into the project
+ * 
+ * @author neil
+ */
+public class ImportClassAction extends AbstractAction
+{   
+    private GreenfootFrame gfFrame;
+    private InteractionListener interactionListener;
+    private ImportClassWindow dlg;
+
+    public ImportClassAction(GreenfootFrame gfFrame, InteractionListener interactionListener)
+    {
+        super(Config.getString("import.action"));
+        setEnabled(false);
+        this.gfFrame = gfFrame;
+        this.interactionListener = interactionListener;
+    }   
+    
+    @Override
+    public void actionPerformed(ActionEvent e)
+    {
+        if (dlg == null)
+        {
+            dlg = new ImportClassWindow(gfFrame, interactionListener);
+        }
+        
+        dlg.setVisible(true);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/InspectClassAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/InspectClassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..25388cb0ec1bb7c1d15b1e99b1d6df600ffb5ab9
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/InspectClassAction.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import java.awt.event.ActionEvent;
+import javax.swing.AbstractAction;
+import javax.swing.JFrame;
+
+import bluej.Config;
+import bluej.pkgmgr.Package;
+import bluej.debugger.DebuggerClass;
+import bluej.debugmgr.inspector.InspectorManager;
+
+/**
+ * Action to inspect a class.
+ * 
+ * @author Poul Henriksen
+ */
+public class InspectClassAction extends AbstractAction
+{
+    private InspectorManager inspectorManager;
+    private DebuggerClass cls;
+    private Package pkg;
+    private JFrame frame;
+    
+    public InspectClassAction(DebuggerClass cls, Package pkg, InspectorManager inspMan, JFrame parent) 
+    {
+        super(Config.getString("inspect.class"));
+        inspectorManager = inspMan;
+        this.pkg = pkg;
+        this.cls = cls;
+        this.frame = parent;
+    }
+    
+    public void actionPerformed(ActionEvent e)
+    {
+        inspectorManager.getClassInspectorInstance(cls, pkg, frame);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NYIAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NYIAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b3009e696a258204395387941d7efbebc26f39b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NYIAction.java
@@ -0,0 +1,54 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import java.awt.event.ActionEvent;
+import javax.swing.AbstractAction;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+/**
+ * NYIAction: An action to display a NYI (Not Yet Implemented) dialogue.
+ *
+ * @author mik
+ */
+public class NYIAction extends AbstractAction
+{
+    private JFrame parent;
+
+    /** 
+     * Creates a new instance of NYIAction 
+     */
+    public NYIAction(String name, JFrame parent) 
+    {
+        super(name);
+        setEnabled(false);
+        this.parent = parent;
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+        JOptionPane.showMessageDialog(parent, Config.getString("greenfoot.nyi"));
+    }
+   
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NewClassAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NewClassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d0d4d59e2ae4342ef1a3a8cb8f9ddda30c7a47a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NewClassAction.java
@@ -0,0 +1,100 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.core.GClass;
+import greenfoot.core.GPackage;
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.NewClassDialog;
+import greenfoot.gui.classbrowser.ClassBrowser;
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.gui.classbrowser.role.NormalClassRole;
+import greenfoot.platforms.ide.GreenfootUtilDelegateIDE;
+import greenfoot.record.InteractionListener;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.IOException;
+import java.rmi.RemoteException;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFrame;
+
+import bluej.Config;
+
+/**
+ * An action for creating a new (non-Actor, non-World) class.
+ * 
+ * @author Davin McCall
+ */
+public class NewClassAction extends AbstractAction
+{
+    private GreenfootFrame gfFrame;
+    private InteractionListener interactionListener;
+
+    /**
+     * Construct a NewClassAction instance.
+     */
+    public NewClassAction(GreenfootFrame gfFrame, InteractionListener interactionListener)
+    {
+        super(Config.getString("new.class"));
+        setEnabled(false);
+        this.gfFrame = gfFrame;
+        this.interactionListener = interactionListener;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent arg0)
+    {
+        JFrame f = gfFrame;
+        ClassBrowser classBrowser = gfFrame.getClassBrowser();
+        GPackage pkg = null;
+        pkg = classBrowser.getProject().getDefaultPackage();
+        
+        NewClassDialog dialog = new NewClassDialog(f, pkg);
+        dialog.setVisible(true);
+        if (!dialog.okPressed()) {
+            return;
+        }
+        
+        String className = dialog.getClassName();
+        
+        try {
+            File dir = pkg.getProject().getDir();
+            File newJavaFile = new File(dir, className + ".java");
+            GreenfootUtilDelegateIDE.getInstance().createSkeleton(className, null, newJavaFile,
+                    NormalClassRole.getInstance().getTemplateFileName(), pkg.getProject().getCharsetName());
+
+            GClass newClass = pkg.newClass(className, false);
+
+            ClassView classView = new ClassView(classBrowser, newClass, interactionListener);
+            classBrowser.addClass(classView);
+        }
+        catch (RemoteException re) {
+            re.printStackTrace();
+        }
+        catch (IOException ioe) {
+            // TODO definitely should report an error condition via dialog
+            ioe.printStackTrace();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NewProjectAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NewProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..32a82f31f9f8b527a91df7c779fef248532d6a3f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NewProjectAction.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.core.GreenfootMain;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: NewProjectAction.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class NewProjectAction extends AbstractAction
+{
+    private static NewProjectAction instance = new NewProjectAction();
+    
+    /**
+     * Singleton factory method for action.
+     */
+    public static NewProjectAction getInstance()
+    {
+        return instance;
+    }
+
+    
+    private NewProjectAction()
+    {
+        super(Config.getString("new.project"));
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        GreenfootMain.getInstance().newProject();
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NewSubclassAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NewSubclassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..182e9204844e13ae60c87e17bc747d11008d0b1d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/NewSubclassAction.java
@@ -0,0 +1,131 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.core.GClass;
+import greenfoot.core.GPackage;
+import greenfoot.gui.NewClassDialog;
+import greenfoot.gui.classbrowser.ClassBrowser;
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.gui.classbrowser.role.ImageClassRole;
+import greenfoot.gui.images.ImageLibFrame;
+import greenfoot.record.InteractionListener;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+import bluej.Config;
+import bluej.utility.DialogManager;
+
+
+/**
+ * Action that creates a new class as a subclass of an existing class
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class NewSubclassAction extends AbstractAction
+{
+    private ClassView superclass;
+    private ClassBrowser classBrowser;
+    private InteractionListener interactionListener;
+
+    /**
+     * Creates a new subclass of the class represented by the view
+     * 
+     * @param view
+     *            The class that is to be the superclass
+     * @param name
+     *            Name of the action that appears in the menu
+     * @param interactionListener
+     *            The listener to be notified of interactions (instance creation, method calls) which
+     *            occur on the new class.
+     */
+    public NewSubclassAction(ClassView view, ClassBrowser classBrowser, InteractionListener interactionListener)
+    {
+        super(Config.getString("new.subclass"));
+        this.superclass = view;
+        this.classBrowser = classBrowser;
+        this.interactionListener = interactionListener;
+    }
+    
+    public void actionPerformed(ActionEvent e)
+    {
+        GClass superG = superclass.getGClass();
+        
+        boolean imageClass = superG.isActorClass() || superG.isActorSubclass();
+        imageClass |= superG.isWorldClass() || superG.isWorldSubclass();
+            
+        if (imageClass) {
+            createImageClass();
+        } else {
+            createNonActorClass();
+        }
+    }
+    
+    public void createImageClass()
+    {
+        JFrame f = (JFrame) SwingUtilities.getWindowAncestor(classBrowser);
+        
+        ImageLibFrame dialog = new ImageLibFrame(f, superclass.getGClass());
+        DialogManager.centreDialog(dialog);
+        dialog.setVisible(true);
+        if (! (dialog.getResult() == ImageLibFrame.OK)) {
+            return;
+        }
+        
+        String className = dialog.getClassName();
+        GClass gClass = superclass.createSubclass(className);
+       
+        if (gClass != null) {
+            ClassView classView = new ClassView(classBrowser, gClass, interactionListener);
+
+            SelectImageAction.setClassImage(classView,
+                    (ImageClassRole) classView.getRole(),
+                    dialog.getSelectedImageFile());
+
+            classBrowser.addClass(classView);
+        }
+    }
+    
+    public void createNonActorClass()
+    {
+        JFrame f = (JFrame) SwingUtilities.getWindowAncestor(classBrowser);
+        GPackage pkg = classBrowser.getProject().getDefaultPackage();
+        NewClassDialog dialog = new NewClassDialog(f, pkg);
+        dialog.setVisible(true);
+        if (!dialog.okPressed()) {
+            return;
+        }
+
+        String className = dialog.getClassName();
+        GClass gClass = superclass.createSubclass(className);   
+        
+        if (gClass != null) {
+            ClassView classView = new ClassView(classBrowser, gClass, interactionListener);
+            classBrowser.addClass(classView);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/OpenProjectAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/OpenProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a0671b94890eb871941ab1da036907012bb11bf
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/OpenProjectAction.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.core.GreenfootMain;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+/**
+ * Action to allow the user to select a project for opening.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class OpenProjectAction extends AbstractAction
+{
+    private static OpenProjectAction instance = new OpenProjectAction();
+    
+    /**
+     * Singleton factory method for action.
+     */
+    public static OpenProjectAction getInstance()
+    {
+        return instance;
+    }
+    
+    private OpenProjectAction()
+    {
+        super(Config.getString("open.project"));
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e)
+    {
+        GreenfootMain.getInstance().openProjectBrowser();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/OpenRecentProjectAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/OpenRecentProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..078cbd5e0a9c234eba619e7f711eab50b1ce7d0b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/OpenRecentProjectAction.java
@@ -0,0 +1,74 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.core.GreenfootMain;
+
+import java.awt.event.ActionEvent;
+import java.rmi.RemoteException;
+
+import javax.swing.AbstractAction;
+import javax.swing.JMenuItem;
+
+/**
+ * @author Bruce Quig
+ * @version $Id: OpenProjectAction.java 4062 2006-05-02 09:38:55Z mik $
+ */
+public class OpenRecentProjectAction extends AbstractAction
+{
+    private static OpenRecentProjectAction instance = new OpenRecentProjectAction();
+    
+    /**
+     * Singleton factory method for action.
+     * @return singleton instance of the action for this VM
+     */
+    public static OpenRecentProjectAction getInstance()
+    {
+        return instance;
+    }
+    
+    
+    private OpenRecentProjectAction()
+    {
+        super(Config.getString("open.recentProject"));
+    }
+    
+    public void actionPerformed(final ActionEvent e)
+    {
+        Object obj = e.getSource();
+        if(obj instanceof JMenuItem){
+            final JMenuItem item = (JMenuItem)obj;
+            Thread t = new Thread(){
+                public void run() {
+                    try {
+                        GreenfootMain.getInstance().openProject(item.getText());
+                    }
+                    catch(RemoteException ex){
+                        ex.printStackTrace();
+                    }
+                }
+            };
+            t.start();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/PauseSimulationAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/PauseSimulationAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c12d75f9e517e60b5198ce85c806a74484894a7
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/PauseSimulationAction.java
@@ -0,0 +1,113 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.core.Simulation;
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+
+import java.awt.EventQueue;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.ImageIcon;
+
+import bluej.utility.Debug;
+
+/**
+ * @author Poul Henriksen
+ * @version $Id: PauseSimulationAction.java 8628 2011-02-02 05:07:36Z davmac $
+ */
+public class PauseSimulationAction extends AbstractAction
+    implements SimulationListener
+{
+    private static final String iconFile = "pause.png";
+    private static PauseSimulationAction instance = new PauseSimulationAction();
+    
+    /**
+     * Singleton factory method for action.
+     */
+    public static PauseSimulationAction getInstance()
+    {
+        return instance;
+    }
+    
+    private Simulation simulation;
+    protected boolean stateOnDebugResume;
+
+    private PauseSimulationAction()
+    {
+        super(Config.getString("pause.simulation"), new ImageIcon(PauseSimulationAction.class.getClassLoader().getResource(iconFile)));
+    }
+
+    /**
+     * Attach this action to a simulation object that it controls.
+     */
+    public void attachSimulation(Simulation simulation)
+    {
+        this.simulation = simulation;
+        simulation.addSimulationListener(this);
+    }
+    
+    /**
+     * This action was fired.
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        if(simulation == null) {
+            Debug.reportError("attempt to pause a simulation while none exists.");
+        }
+        else {
+            simulation.setPaused(true);
+        }
+    }
+
+    /**
+     * Observing for the simulation state so we can dis/en-able us appropriately
+     */
+    public void simulationChanged(final SimulationEvent e)
+    {
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                int eventType = e.getType();
+                if (eventType == SimulationEvent.STOPPED) {
+                    setEnabled(stateOnDebugResume = false);
+                }
+                else if (eventType == SimulationEvent.STARTED) {
+                    setEnabled(stateOnDebugResume = true);
+                }
+                else if (eventType == SimulationEvent.DISABLED) {
+                    setEnabled(stateOnDebugResume = false);
+                }
+                else if (eventType == SimulationEvent.DEBUGGER_PAUSED) {
+                    stateOnDebugResume = isEnabled();
+                    setEnabled(false);                        
+                }
+                else if (eventType == SimulationEvent.DEBUGGER_RESUMED) {
+                    setEnabled(stateOnDebugResume);
+                }
+            }            
+        });
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/PreferencesAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/PreferencesAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ffa5a9f761979e759457fd276512480a30d0291
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/PreferencesAction.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.core.GreenfootMain;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+/**
+ * Action to display preferences.
+ * 
+ * @author Michael Kolling
+ */
+public class PreferencesAction extends AbstractAction
+{
+    private static PreferencesAction instance;
+    
+     /**
+     * Singleton factory method for action.
+     */
+    public static PreferencesAction getInstance()
+    {
+        if(instance == null)
+            instance = new PreferencesAction();
+        return instance;
+    }
+    
+    private PreferencesAction()
+    {
+        super(Config.getString("greenfoot.preferences"));
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+        GreenfootMain.getInstance().showPreferences();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/QuitAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/QuitAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..a5900815c1734628fe3b629d2e717d60345dfe1b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/QuitAction.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.core.GreenfootMain;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+/**
+ * An action to Quit (close all Greenfoot projects and exit the application)
+ * 
+ * @author Davin McCall
+ * @version $Id: QuitAction.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class QuitAction extends AbstractAction
+{
+    private static QuitAction instance;
+    
+    public static QuitAction getInstance()
+    {
+        if (instance == null) {
+            instance = new QuitAction();
+        }
+        return instance;
+    }
+    
+    private QuitAction()
+    {
+        super(Config.getString("greenfoot.quit"));
+    }
+    
+    public void actionPerformed(ActionEvent e)
+    {
+        GreenfootMain.closeAll();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RemoveClassAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RemoveClassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..5725ecd664b3243d94643f30352a1f147031242a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RemoveClassAction.java
@@ -0,0 +1,78 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.gui.classbrowser.ClassView;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFrame;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import javax.swing.JOptionPane;
+
+
+/**
+ * Removes a class.
+ * 
+ * @author Poul Henriksen
+ */
+public class RemoveClassAction extends AbstractAction
+{
+    private ClassView cls;
+    private JFrame frame;
+
+    private static String confirmRemoveTitle = Config.getString("remove.confirm.title");
+    private static String confirmRemoveText1 = Config.getString("remove.confirm.text1");
+    private static String confirmRemoveText2 = Config.getString("remove.confirm.text2");
+    
+    public RemoveClassAction(ClassView view, JFrame frame)
+    {
+        super(Config.getString("remove.class"));
+        this.cls = view;
+        this.frame = frame;
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+        if (confirmRemoveClass(cls, frame)) {
+            cls.remove();
+        }
+    }
+    
+    public static boolean confirmRemoveClass(ClassView cls, JFrame frame)
+    {
+        String[] options = new String[] { Config.getString("remove.class"), BlueJTheme.getCancelLabel() };
+        int remove = 0;
+        int response = JOptionPane.showOptionDialog(frame,
+                confirmRemoveText1 + " " + cls.getClassName() + ". " + confirmRemoveText2,
+                confirmRemoveTitle,
+                JOptionPane.YES_NO_OPTION,
+                JOptionPane.QUESTION_MESSAGE,
+                null,
+                options,
+                options[0]);
+        return response == remove;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RemoveSelectedClassAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RemoveSelectedClassAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..97563a01a96e73bbfd2ba3f70b261b68414df0e6
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RemoveSelectedClassAction.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.classbrowser.ClassView;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.JFrame;
+
+import bluej.Config;
+
+/**
+ * An action to remove the currently selected class.
+ * 
+ * @author davmac
+ * @version $Id: RemoveSelectedClassAction.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class RemoveSelectedClassAction extends ClassAction
+{
+    private JFrame frame;
+
+    /**
+     * Construct a remove action to remove the currently selected class.
+     * The constructed action should be set as selection listener for the
+     * class browser.
+     */
+    public RemoveSelectedClassAction(GreenfootFrame gfFrame)
+    {
+        super(Config.getString("remove.selected"), gfFrame);
+        setEnabled(false);
+        this.frame = gfFrame;
+    }
+    
+    public void actionPerformed(ActionEvent e)
+    {
+    	ClassView cls = getSelectedClassView();
+    	
+    	boolean confirmed = RemoveClassAction.confirmRemoveClass(cls, frame);
+        if (confirmed) {
+            cls.remove();
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ResetWorldAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ResetWorldAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..577b01b54c7a5e72cbfbd4425b0b96333365a39e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ResetWorldAction.java
@@ -0,0 +1,114 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009, 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.core.Simulation;
+import greenfoot.core.WorldHandler;
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+
+import java.awt.EventQueue;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.ImageIcon;
+
+import bluej.Config;
+import bluej.utility.Debug;
+
+public class ResetWorldAction extends AbstractAction implements SimulationListener
+{
+
+    private Simulation simulation;
+    private static ResetWorldAction instance = new ResetWorldAction();
+
+    private static final String iconFile = "reset.png";
+    
+    /**
+     * Singleton factory method for action.
+     */
+    public static ResetWorldAction getInstance()
+    {
+        return instance;
+    }
+    
+    private ResetWorldAction()
+    {
+        super(Config.getString("reset.world"), new ImageIcon(ResetWorldAction.class.getClassLoader().getResource(iconFile)));
+    }
+
+    /**
+     * Attach this action to a simulation object that it controls.
+     */
+    public void attachSimulation(Simulation simulation)
+    {
+        this.simulation = simulation;
+        simulation.addSimulationListener(this);
+    }
+    
+    /**
+     * If the simulation is not null, it disables the simulation, discards the world
+     * and instantiates a new world
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        if(simulation == null) 
+        {
+            Debug.reportError("attempt to reset a simulation while none exists.");
+        }
+        else {
+            resetWorld();
+        }
+    }
+    
+    // Identify this method so that the debugger can notice when the user has clicked reset:
+    public static final String RESET_WORLD = "resetWorld";    
+    private void resetWorld()
+    {
+        simulation.setEnabled(false);
+        WorldHandler.getInstance().discardWorld();
+        WorldHandler.getInstance().instantiateNewWorld();
+    }
+
+    /**
+     * Observing for the simulation state so we can dis/en-able us appropiately
+     */
+    public void simulationChanged(final SimulationEvent e)
+    {
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                int eventType = e.getType();
+                if (eventType == SimulationEvent.STOPPED) {
+                    setEnabled(true);
+                }
+                else if (eventType == SimulationEvent.STARTED) {
+                    setEnabled(true);
+                }
+                else if (eventType == SimulationEvent.DISABLED) {
+                    setEnabled(false);
+                }
+            }
+        });
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RunOnceSimulationAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RunOnceSimulationAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f6926858ee3e6dbda9590ed1adc11d9e0a30d93
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RunOnceSimulationAction.java
@@ -0,0 +1,124 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.core.Simulation;
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+import greenfoot.event.SimulationUIListener;
+
+import java.awt.EventQueue;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.ImageIcon;
+
+import bluej.utility.Debug;
+
+/**
+ * An action to "act once" all the actors in the world.
+ * 
+ * @author Poul Henriksen
+ */
+public class RunOnceSimulationAction extends AbstractAction
+    implements SimulationListener
+{
+    private static final String iconFile = "step.png";
+    private static RunOnceSimulationAction instance = new RunOnceSimulationAction();
+
+    private Simulation simulation;
+    protected boolean stateOnDebugResume;
+    private SimulationUIListener listener; 
+    
+    /**
+     * Singleton factory method for action.
+     */
+    public static RunOnceSimulationAction getInstance()
+    {
+        return instance;
+    }
+    
+    private RunOnceSimulationAction()
+    {
+        super(Config.getString("run.once"), new ImageIcon(RunOnceSimulationAction.class.getClassLoader().getResource(iconFile)));
+    }
+
+    /**
+     * Attach this action to a simulation object that it controls.
+     */
+    public void attachSimulation(Simulation simulation)
+    {
+        this.simulation = simulation;
+        simulation.addSimulationListener(this);
+    }
+    
+    /**
+     * Attach a listener to be notified when the action fires.
+     */
+    public void attachListener(SimulationUIListener listener)
+    {
+        this.listener = listener;
+    }
+    
+    public void actionPerformed(ActionEvent e)
+    {
+        if(simulation == null) {
+            Debug.reportError("attempt to pause a simulation while none exists.");
+            return;
+        }
+        
+        if (listener != null) {
+            listener.simulationActive();
+        }
+        simulation.runOnce();
+    }
+
+    /**
+     * Observing for the simulation state so we can dis/en-able us appropiately
+     */
+    public void simulationChanged(final SimulationEvent e)
+    {
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                int eventType = e.getType();
+                if (eventType == SimulationEvent.STOPPED) {
+                    setEnabled(stateOnDebugResume = true);
+                }
+                else if (eventType == SimulationEvent.STARTED) {
+                    setEnabled(stateOnDebugResume = false);
+                }
+                else if (eventType == SimulationEvent.DISABLED) {
+                    setEnabled(stateOnDebugResume = false);
+                }
+                else if (eventType == SimulationEvent.DEBUGGER_PAUSED) {
+                    stateOnDebugResume = isEnabled();
+                    setEnabled(false);                        
+                }
+                else if (eventType == SimulationEvent.DEBUGGER_RESUMED) {
+                    setEnabled(stateOnDebugResume);
+                }
+            }
+        });
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RunSimulationAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RunSimulationAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..d32c4b661329b2ea7647200e7606b3857fd1e614
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/RunSimulationAction.java
@@ -0,0 +1,124 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.core.Simulation;
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+import greenfoot.event.SimulationUIListener;
+
+import java.awt.EventQueue;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.ImageIcon;
+
+import bluej.utility.Debug;
+
+/**
+ * An action to run the simulation.
+ * 
+ * @author Poul Henriksen
+ */
+public class RunSimulationAction extends AbstractAction
+    implements SimulationListener
+{
+    private static final String iconFile = "run.png";
+    private static RunSimulationAction instance = new RunSimulationAction();
+
+    private Simulation simulation;
+    protected boolean stateOnDebugResume;
+    private SimulationUIListener listener; 
+
+    /**
+     * Singleton factory method for action.
+     */
+    public static RunSimulationAction getInstance()
+    {
+        return instance;
+    }
+
+    private RunSimulationAction()
+    {
+        super(Config.getString("run.simulation"), new ImageIcon(RunSimulationAction.class.getClassLoader().getResource(iconFile)));
+    }
+
+    /**
+     * Attach this action to a simulation object that it controls.
+     */
+    public void attachSimulation(Simulation simulation)
+    {
+        this.simulation = simulation;
+        simulation.addSimulationListener(this);
+    }
+    
+    /**
+     * Attach a listener to be notified when the action fires.
+     */
+    public void attachListener(SimulationUIListener listener)
+    {
+        this.listener = listener;
+    }
+    
+    public void actionPerformed(ActionEvent e)
+    {
+        if(simulation == null) {
+            Debug.reportError("attempt to run a simulation while none exists.");
+            return;
+        }
+        
+        if (listener != null) {
+            listener.simulationActive();
+        }
+        simulation.setPaused(false);
+    }
+
+    /**
+     * Observing for the simulation state so we can dis/en-able us appropiately
+     */
+    public void simulationChanged(final SimulationEvent e)
+    {
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                int eventType = e.getType();
+                if (eventType == SimulationEvent.STOPPED) {
+                    setEnabled(stateOnDebugResume = true);
+                }
+                else if (eventType == SimulationEvent.STARTED) {
+                    setEnabled(stateOnDebugResume = false);
+                }
+                else if (eventType == SimulationEvent.DISABLED) {
+                    setEnabled(stateOnDebugResume = false);
+                }
+                else if (eventType == SimulationEvent.DEBUGGER_PAUSED) {
+                    stateOnDebugResume = isEnabled();
+                    setEnabled(false);                        
+                }
+                else if (eventType == SimulationEvent.DEBUGGER_RESUMED) {
+                    setEnabled(stateOnDebugResume);
+                }
+            }
+        });
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SaveAsAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SaveAsAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..1947fbc6e64a1312b92e451d41368a374f07d309
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SaveAsAction.java
@@ -0,0 +1,110 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.core.GProject;
+import greenfoot.gui.GreenfootFrame;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.rmi.RemoteException;
+
+import javax.swing.AbstractAction;
+
+import rmiextension.wrappers.RBlueJ;
+
+import bluej.Config;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+
+/**
+ * An action to save a copy of a project into another location, then close the current project
+ * and open the new copy.
+ * 
+ * @author Davin McCall
+ */
+public class SaveAsAction extends AbstractAction
+{
+    private GreenfootFrame gfFrame;
+    private RBlueJ rBlueJ;
+    
+    public SaveAsAction(GreenfootFrame gfFrame, RBlueJ rBlueJ)
+    {
+        super(Config.getString("project.saveAs"));
+        this.gfFrame = gfFrame;
+        this.rBlueJ = rBlueJ;
+        setEnabled(false);
+    }
+    
+    public void actionPerformed(ActionEvent e)
+    {
+        // get a file name to save under
+        File newFile = FileUtility.getDirName(gfFrame,
+                Config.getString("project.saveAs.title"),
+                Config.getString("pkgmgr.saveAs.buttonLabel"), false, true);
+                
+        if (newFile != null) {
+            GProject project = gfFrame.getProject();
+
+            int result = FileUtility.COPY_ERROR;
+            
+            try {
+                project.save();
+
+                result = FileUtility.copyDirectory(project.getDir(),
+                        newFile);
+                
+                if (result == FileUtility.NO_ERROR)
+                {
+                    // It's very important to set the new copy opening
+                    // before closing the old project.  If you close the old one
+                    // first, Greenfoot realises that it has no projects open
+                    // and exits.  So it has to be in this order:
+                    rBlueJ.openProject(newFile);
+                    project.close();
+                }
+            }
+            catch (RemoteException re) {
+                re.printStackTrace();
+            }
+            catch (ProjectNotOpenException pnoe) {
+                // can't happen
+                pnoe.printStackTrace();
+            }
+
+            switch (result) {
+                case FileUtility.NO_ERROR:
+                    break;
+
+                case FileUtility.DEST_EXISTS:
+                    DialogManager.showError(gfFrame, "project-already-exists");
+                    return;
+
+                case FileUtility.SRC_NOT_DIRECTORY:
+                case FileUtility.COPY_ERROR:
+                    DialogManager.showError(gfFrame, "cannot-save-project");
+                    return;
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SaveProjectAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SaveProjectAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3bb2b86815cc331db9c25b3ad6d3f12fe547d5b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SaveProjectAction.java
@@ -0,0 +1,63 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.gui.GreenfootFrame;
+
+import java.awt.event.ActionEvent;
+import java.rmi.RemoteException;
+
+import javax.swing.AbstractAction;
+
+import bluej.extensions.ProjectNotOpenException;
+import bluej.utility.Debug;
+
+/**
+ * @author Poul Henriksen
+ * @version $Id$
+ */
+public class SaveProjectAction extends AbstractAction
+{
+    private GreenfootFrame gfFrame;
+    
+    public SaveProjectAction(GreenfootFrame gfFrame)
+    {
+        super(Config.getString("project.save"));
+        this.gfFrame = gfFrame;
+        setEnabled(false);
+    }
+    
+    public void actionPerformed(ActionEvent e)
+    {
+        try {
+            gfFrame.getProject().save();
+        }
+        catch (ProjectNotOpenException e1) {
+            Debug.reportError("Could not save scenario because it is not open.");
+        }
+        catch (RemoteException e1) {
+            Debug.reportError("Could not save scenario because of a remote exception.");
+            e1.printStackTrace();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SaveWorldAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SaveWorldAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..9887152655a5a102729a33e1b2331f8ce9d6ee5a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SaveWorldAction.java
@@ -0,0 +1,163 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.core.ClassStateManager;
+import greenfoot.core.ClassStateManager.CompiledStateListener;
+import greenfoot.core.GClass;
+import greenfoot.record.GreenfootRecorder;
+
+import java.awt.EventQueue;
+import java.awt.event.ActionEvent;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+
+import bluej.Config;
+import bluej.utility.Debug;
+
+/**
+ * Action to "save the world" - i.e. write out code which restores the world and the
+ * actors in it.
+ */
+public class SaveWorldAction extends AbstractAction implements CompiledStateListener
+{
+    private GreenfootRecorder recorder;
+    private boolean recordingValid;
+    private GClass lastWorldGClass;
+
+    /**
+     * Construct a new action to save the world state.
+     */
+    public SaveWorldAction(GreenfootRecorder recorder, ClassStateManager classStateManager)
+    {
+        super(Config.getString("save.world"));
+        setEnabled(false);
+        this.recorder = recorder;
+        if (classStateManager != null) {
+            classStateManager.addCompiledStateListener(this);
+        }
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent arg0)
+    {
+        final String methodName = GreenfootRecorder.METHOD_NAME;
+        
+        List<String> code = recorder.getCode();
+                
+        final String oneIndent = "    ";
+        final String twoIndent = oneIndent + oneIndent;
+        
+        StringBuffer comment = new StringBuffer();
+        comment.append("\n").append(oneIndent).append("/**\n");
+        comment.append(oneIndent).append("* ").append(Config.getString("record.method.comment1")).append("\n");
+        comment.append(oneIndent).append("* ").append(Config.getString("record.method.comment2")).append("\n");
+        comment.append(oneIndent).append("*/\n");
+        
+        StringBuffer method = new StringBuffer();
+        for (String line : code) {
+            method.append(twoIndent).append(line).append("\n");
+        }
+               
+        try {
+            GClass lastWorld = getLastWorldGClass();
+            lastWorld.insertMethodCallInConstructor(methodName, false);
+            lastWorld.insertAppendMethod(comment.toString(), "private", methodName, method.toString(), true, false);
+            lastWorld.showMessage(Config.getString("record.saved.message"));
+            // Now that we've inserted the code, we must reset the recorder,
+            // so that if the user saves the world again before re-compiling,
+            // it doesn't insert the same code twice.  If the user scrubs our method
+            // and saves the world before re-compiling this will then go wrong
+            // (by inserting code depending on objects no longer there) but that
+            // seems less likely:
+            recorder.clearCode(false);
+            
+            lastWorld.compile(false, true);
+        }
+        catch (Exception e) {
+            Debug.reportError("Error trying to get editor for world class and insert method (with call)", e);
+        }
+    }
+
+    /**
+     * Check whether the action should currently be enabled.
+     */
+    private synchronized boolean shouldBeEnabled()
+    {
+        GClass lastWorld = getLastWorldGClass();
+        return recordingValid && lastWorld != null && lastWorld.isCompiled();
+    }
+
+    /**
+     * Set the recording state as valid or not. If invalid, the action becomes disabled.
+     * This can be called from any thread.
+     */
+    public synchronized void setRecordingValid(boolean valid)
+    {
+        boolean oldValid = recordingValid;
+        recordingValid = valid;
+        if (oldValid != recordingValid) {
+            //This action will actually change the status of the menu
+            EventQueue.invokeLater(new Runnable() {
+                @Override
+                public void run()
+                {
+                    updateEnabledStatus();
+                }
+            });
+        }        
+    }
+    
+    private void updateEnabledStatus()
+    {
+        setEnabled(shouldBeEnabled());
+    }
+
+    @Override
+    public void compiledStateChanged(final GClass gclass, boolean compiled)
+    {
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                GClass lastClass = getLastWorldGClass();
+                if (lastClass != null && gclass.getQualifiedName().equals(lastClass.getQualifiedName())) {            
+                    updateEnabledStatus();
+                }
+            }
+        });
+    }
+    
+    private synchronized GClass getLastWorldGClass()
+    {
+        return lastWorldGClass;
+    }
+    
+    /**
+     * Set the most recently interactively instantiated world class.
+     * This is currently called from any & every thread.
+     */
+    public synchronized void setLastWorldGClass(GClass lastWorld)
+    {
+        lastWorldGClass = lastWorld;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SelectImageAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SelectImageAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..1169d2c013705468d6ddc2879b17527a5e97d96c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SelectImageAction.java
@@ -0,0 +1,156 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009, 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.GreenfootImage;
+import greenfoot.World;
+import greenfoot.WorldVisitor;
+import greenfoot.core.GClass;
+import greenfoot.core.GreenfootMain;
+import greenfoot.core.Simulation;
+import greenfoot.core.WorldHandler;
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.gui.classbrowser.role.ImageClassRole;
+import greenfoot.gui.images.ImageLibFrame;
+import greenfoot.gui.images.ImageSelectionWatcher;
+
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.IOException;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFrame;
+
+import bluej.Config;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+
+/**
+ * Action to select an image for a class.
+ * 
+ * @author Davin McCall
+ * @author Philip Stevens
+ */
+public class SelectImageAction extends AbstractAction
+{
+    private ClassView classView;
+    private ImageClassRole gclassRole;
+    
+    public SelectImageAction(ClassView classView, ImageClassRole gcr)
+    {
+        super(Config.getString("select.image"));
+        this.classView = classView;
+        this.gclassRole = gcr;
+    }
+    
+    /**
+     * Will save the currently selected image as the image of the class
+     * if OK is pressed.
+     * 
+     * If performed on the current world this will allow for previewing of
+     * the currently selected image, but revert to the original background
+     * image of cancelled.
+     * @param e ignored
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        final World currentWorld = WorldHandler.getInstance().getWorld();
+        // save the original background if possible
+        final GreenfootImage originalBackground = ((currentWorld == null) ? 
+                null : WorldVisitor.getBackgroundImage(currentWorld));
+
+        // allow the previewing if we are setting the image of the current world.
+        ImageSelectionWatcher watcher = null;
+        if (currentWorld != null && currentWorld.getClass().getName().equals(classView.getGClass().getQualifiedName())) {
+            watcher = new ImageSelectionWatcher() {
+                @Override
+                public void imageSelected(final File imageFile)
+                {
+                    if (imageFile != null) {
+                        Simulation.getInstance().runLater(new Runnable() {
+                            @Override
+                            public void run()
+                            {
+                                if (WorldHandler.getInstance().getWorld() == currentWorld) {
+                                    currentWorld.setBackground(imageFile.getAbsolutePath());
+                                }
+                            }
+                        });
+                    }
+                }
+            };
+        }
+        
+        // initialise our image library frame
+        JFrame gfFrame = GreenfootMain.getInstance().getFrame();
+        ImageLibFrame imageLibFrame = new ImageLibFrame(gfFrame, classView, watcher);
+        DialogManager.centreDialog(imageLibFrame);
+        imageLibFrame.setVisible(true);
+
+        // set the image of the class to the selected file
+        if (imageLibFrame.getResult() == ImageLibFrame.OK) {
+            File currentImageFile = imageLibFrame.getSelectedImageFile();
+            setClassImage(classView, gclassRole, currentImageFile);
+            gfFrame.repaint();
+        }
+        // or if cancelled reset the world background to the original format
+        // to avoid white screens or preview images being left there. 
+        else if (currentWorld != null && imageLibFrame.getResult() == ImageLibFrame.CANCEL) {
+            Simulation.getInstance().runLater(new Runnable() {
+                @Override
+                public void run()
+                {
+                    currentWorld.setBackground(originalBackground);
+                }
+            });
+        }
+    }
+
+    public static void setClassImage(ClassView classView, ImageClassRole gclassRole, File imageFile)
+    {
+        GClass gclass = classView.getGClass();
+        File projImagesDir = gclass.getPackage().getProject().getImageDir();            
+        if (imageFile != null) {
+            if (! imageFile.getParentFile().getAbsoluteFile().equals(projImagesDir)) {
+                // An image was selected from an external dir. We need
+                // to copy it into the project images directory first.
+                File destFile = new File(projImagesDir, imageFile.getName());
+                try {
+                    FileUtility.copyFile(imageFile, destFile);
+                    imageFile = destFile;
+                }
+                catch (IOException e) {
+                    Debug.reportError("Error when copying file: " + imageFile + " to: " + destFile, e);
+                }
+            }
+
+            gclass.setClassProperty("image", imageFile.getName());
+        } 
+        else {
+            imageFile = null;
+            gclass.setClassProperty("image", null);
+        }
+        gclassRole.changeImage();
+        gclass.getPackage().getProject().getProjectProperties().save();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SetPlayerAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SetPlayerAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..e30f43240bb5d09f936874f70f8a0d49c1167452
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/SetPlayerAction.java
@@ -0,0 +1,53 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.SetPlayerDialog;
+import greenfoot.platforms.ide.GreenfootUtilDelegateIDE;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+import bluej.Config;
+
+public class SetPlayerAction extends AbstractAction
+{
+    private GreenfootFrame frame;
+    
+    public SetPlayerAction(GreenfootFrame frame)
+    {
+        super(Config.getString("set.player"));
+        
+        this.frame = frame;
+    }
+        
+    @Override
+    public void actionPerformed(ActionEvent e)
+    {
+        SetPlayerDialog dlg = new SetPlayerDialog(frame, GreenfootUtilDelegateIDE.getInstance().getUserName());
+        dlg.setVisible(true);
+        Config.putPropString("greenfoot.player.name", dlg.getPlayerName());
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowApiDocAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowApiDocAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..b540bd7de43e717a98841e04bc6d9e1aa23623d9
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowApiDocAction.java
@@ -0,0 +1,71 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+
+import javax.swing.AbstractAction;
+
+/**
+ * Action to open the Greenfoot API documentation in an external web browser.
+ *
+ * @author Poul Henriksen
+ */
+public class ShowApiDocAction extends AbstractAction {
+    private String page = "index.html";
+    
+    /**
+     * Will show the index.html of the API Documentation
+     * @param name
+     */
+    public ShowApiDocAction(String name)
+    {
+        super(name);
+    }
+    
+
+    /**
+     * Opens the given page of the Greenfoot API documentation in a web browser.
+     * @param page name of the page relative to the root of the API doc.
+     * @throws IOException If the greenfoot directory can not be read
+     */
+    public ShowApiDocAction(String name, String page)
+    {
+        super(name);
+        this.page = page;
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+        try {
+            GreenfootUtil.showApiDoc(page);
+            // TODO: show status message: browser opened
+        }
+        catch (IOException e1) {
+            // TODO: show status message: problem opening  
+        }   
+       
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowCopyrightAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowCopyrightAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..8b24bab9d10722a982b4eec1fb26ec179007364a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowCopyrightAction.java
@@ -0,0 +1,76 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import java.awt.event.ActionEvent;
+import javax.swing.AbstractAction;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+/**
+ * Action to display a copyright notice.
+ *
+ * @author mik
+ */
+public class ShowCopyrightAction extends AbstractAction
+{
+    private static ShowCopyrightAction instance;
+    
+     /**
+     * Singleton factory method for action.
+     */
+    public static ShowCopyrightAction getInstance(JFrame parent)
+    {
+        if(instance == null) {
+            instance = new ShowCopyrightAction(parent);
+        }
+        return instance;
+    }
+
+
+    private JFrame parent;
+
+    /** 
+     *  Creates a new instance of ShowCopyrightAction 
+     */
+    private ShowCopyrightAction(JFrame parent) 
+    {
+        super(Config.getString("greenfoot.copyright"));
+        this.parent = parent;
+    }
+    
+    /**
+     * The action was fired...
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+            JOptionPane.showMessageDialog(parent, new String[]{
+                "Greenfoot \u00a9 2005-2011 Michael K\u00F6lling, Poul Henriksen.", " ",
+                "Greenfoot is available under the GNU General Public License",
+                "version 2 with Classpath exception.",
+                "For more information please see the files LICENSE.txt",
+                "and THIRDPARTYLICENSE.txt."
+                }, 
+                "Copyright, License and Redistribution", JOptionPane.INFORMATION_MESSAGE);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowReadMeAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowReadMeAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1d8c83643e8c7d369ab19ae76e244ffbfb1098f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowReadMeAction.java
@@ -0,0 +1,56 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.Config;
+import greenfoot.gui.GreenfootFrame;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+/**
+ * Action that compiles all classes that needs compilation.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: ShowReadMeAction.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class ShowReadMeAction extends AbstractAction
+{
+	private GreenfootFrame gfFrame;
+    
+    public ShowReadMeAction(GreenfootFrame gfFrame)
+    {
+        super(Config.getString("show.readme"));
+    	this.gfFrame = gfFrame;
+        setEnabled(false);
+    }
+
+    /**
+     * Compiles all classes.
+     *  
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        gfFrame.getProject().openReadme();
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowWebsiteAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowWebsiteAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..e85a20fcd98d0cabf4722346aafb42aaa1060fde
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ShowWebsiteAction.java
@@ -0,0 +1,52 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import bluej.utility.Utility;
+import java.awt.event.ActionEvent;
+import javax.swing.AbstractAction;
+
+/**
+ * Action to open a URL in an external web browser.
+ *
+ * @author mik
+ */
+public class ShowWebsiteAction extends AbstractAction {
+    
+    private String url;
+    
+    /** Creates a new instance of ShowWebsiteAction */
+    public ShowWebsiteAction(String name, String url) {
+        super(name);
+        this.url = url;
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+        if (Utility.openWebBrowser(url)) {
+            // TODO: show status message: browser opened
+        }
+        else {
+            // TODO: show status message: problem opening            
+        }      
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ToggleAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ToggleAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..53077dae50150109c257190a87cd4431ec988ed0
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ToggleAction.java
@@ -0,0 +1,82 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 1999-2009  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import java.awt.event.ActionEvent;
+
+import greenfoot.core.GProject;
+
+import javax.swing.AbstractAction;
+import javax.swing.ButtonModel;
+
+/**
+ * Subclasses {@link AbstractAction} allowing overriding
+ * of the ActionPerformed, but also requiring subclasses
+ * to implement their own getToggleModel.
+ * 
+ * Holds the current GProject to allow subclasses access
+ * to project specific methods.
+ * @author Philip Stevens
+ */
+public abstract class ToggleAction extends AbstractAction 
+{
+
+	/**
+	 * Project to associate this action with.
+	 */
+	protected GProject project;
+
+	/**
+	 * Sets the project to the project provided and
+	 * passes the title onto the AbstractAction constructor.
+	 * @param title		Mainly used as the display of the window/menu item.
+	 * @param project	Current project to associate this action with.
+	 */
+	public ToggleAction(String title, GProject project) 
+	{
+		super(title);
+		setProject(project);
+	}
+
+	/**
+	 * Can be overridden to perform an action.
+	 */
+	@Override
+	public void actionPerformed(ActionEvent e) 
+	{
+		// do nothing
+	}
+	
+	/**
+	 * @param project	Set the debuggers project to be this parameter
+	 */
+	public void setProject(GProject project)
+	{
+		this.project = project;
+	}
+	
+	/**
+	 * Abstract method to be implemented by subclasses.
+	 */
+    public abstract ButtonModel getToggleModel();
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ToggleDebuggerAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ToggleDebuggerAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..dac5c7c39b7441706d7dcfb6522c69b04806862e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ToggleDebuggerAction.java
@@ -0,0 +1,98 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.actions;
+
+import greenfoot.core.GProject;
+
+import javax.swing.ButtonModel;
+import javax.swing.JToggleButton;
+
+/**
+ * Creates the debugger window when called, also setting
+ * the checkbox of its menu item to its current state
+ * (visible or not).
+ * 
+ * @author Philip Stevens
+ */
+public class ToggleDebuggerAction extends ToggleAction 
+{
+    public ToggleDebuggerAction(String title, GProject project) 
+    {
+        super(title, project);
+    }
+
+    /**
+     * @param project	Set the debuggers project to be this parameter
+     */
+    @Override
+    public void setProject(GProject project)
+    {
+        this.project = project;
+    }
+
+    /**
+     * Creates a new {@link ExecControlButtonModel} to
+     * determine the state of the debugger window,
+     * in terms of visibility.
+     */
+    @Override
+    public ButtonModel getToggleModel() 
+    {
+        return new ExecControlButtonModel();
+    }
+
+    /**
+     * Subclass that updates the check box field and also
+     * opens the debugger or closes it depending on its
+     * current state.
+     * 
+     * @author Philip Stevens
+     */
+    public class ExecControlButtonModel extends JToggleButton.ToggleButtonModel
+    {
+        /**
+         * Returns whether or not the debugger window is currently visible.
+         */
+        @Override
+        public boolean isSelected()
+        {
+            if (project != null) {
+                return project.isExecControlVisible();
+            }
+            return false;
+        }
+
+        /**
+         * Updates the visibility of the debugger window, and
+         * sets the checkbox to the parameter.
+         * @param b	State to set the checkbox to.
+         */
+        @Override
+        public void setSelected(boolean b)
+        {
+            if (project != null && b != isSelected()) {
+                super.setSelected(b);
+                project.toggleExecControls();
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ToggleSoundAction.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ToggleSoundAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..dfba6abfc5c2ad8d1138ae809b5e0e70737ae964
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/actions/ToggleSoundAction.java
@@ -0,0 +1,48 @@
+package greenfoot.actions;
+
+import greenfoot.core.GProject;
+import greenfoot.gui.soundrecorder.SoundRecorderControls;
+
+import javax.swing.ButtonModel;
+import javax.swing.JToggleButton;
+
+public class ToggleSoundAction extends ToggleAction 
+{
+	private SoundRecorderControls recorder;
+	
+    public ToggleSoundAction(String title, GProject project) {
+		super(title, project);
+	}
+
+	@Override
+	public ButtonModel getToggleModel() 
+	{
+		return new JToggleButton.ToggleButtonModel() {
+			
+		    /**
+		     * Returns whether or not the sound recorder window is currently visible.
+		     */
+			@Override
+		    public boolean isSelected()
+		    {
+		    	return recorder != null && recorder.isVisible();
+		    }
+
+		    /**
+		     * @param b	Set the state to this value
+		     */
+			@Override
+		    public void setSelected(boolean b)
+		    {
+			    if (b) {
+			        if (recorder == null) {
+			            recorder = new SoundRecorderControls(project);
+			        }
+			        recorder.setVisible(true);
+			    } else if (recorder != null) {
+				    recorder.closeAndStopRecording();
+			    }
+		    }
+		};
+	}
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/BVHInsChecker.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/BVHInsChecker.java
new file mode 100644
index 0000000000000000000000000000000000000000..31d0fc1d1f10de1ad11ffe1ced0f9436d65ed362
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/BVHInsChecker.java
@@ -0,0 +1,907 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+import greenfoot.util.Circle;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.PriorityQueue;
+
+/**
+ * This collision checker is based on a Bounding Volume Hierarchy formed by
+ * circles. The tree is build by insertion.
+ * <p>
+ * 
+ * Some of the good properties of this:
+ * <ul>
+ * <li>On-line, which means it is cheap to insert and remove objects.</li>
+ * <li>Good for many kinds of object distributions.</li>
+ * <li>Moderate tree construction time</li>
+ * <li> </li>
+ * </ul>
+ * 
+ * Some of the bad properties of this:
+ * <ul>
+ * <li>Only decent for strictly cell based scenarios.</li>
+ * </ul>
+ * 
+ * <p>
+ * 
+ * This implementation is based on the Balltree On-line Insertion algorithm
+ * described in: <a
+ * href="http://www.icsi.berkeley.edu/ftp/global/pub/techreports/1989/tr-89-063.pdf">Five
+ * Balltree Construction Algorithms by Stephen M. Omohundro</a>
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class BVHInsChecker
+    implements CollisionChecker
+{
+
+    class Node
+    {
+        public Node parent;
+        public Node left; // child
+        public Node right; // child
+        public Circle circle;
+        private Actor actor;
+
+        public Node(Circle circle)
+        {
+            this.circle = circle;
+        }
+
+        public Node()
+        {
+            circle = new Circle();
+        }
+
+        public Node(Circle circle, Actor actor)
+        {
+            if(actor == null) {
+                throw new NullPointerException("Actor may not be null.");
+            }
+            this.circle = circle;
+            this.actor = actor;
+        }
+
+        public Actor getActor()
+        {
+            return actor;
+        }
+
+        public boolean isLeaf()
+        {
+            return (left == null && right == null);
+        }
+
+        /**
+         * Get collisions with the circle b and then use the specific collision
+         * checker for the Actors to make low-level collision check.
+         * 
+         * @param c
+         *            Circle to find intersections with
+         * @param checker
+         *            Optional collision checker. If null it will just find
+         *            collisions based on the circle.
+         * @param result
+         *            List to put the result in.
+         */
+        public void getIntersections(Circle c, CollisionQuery checker, List<Actor> result)
+        {
+            if (!c.intersects(this.circle)) {
+                return;
+            }
+                if (isLeaf() && (checker != null && checker.checkCollision(getActor()))) {
+                    result.add(getActor());
+                }
+                else if (!isLeaf()) {
+                    left.getIntersections(c, checker, result);
+                    right.getIntersections(c, checker, result);
+                }
+        }
+
+        private Actor getOneIntersectingObject(Circle c, CollisionQuery checker)
+        {
+            return getOneIntersectingObjectUpwards(c, checker);
+        }
+
+        private Actor getOneIntersectingObjectDownwards(Circle c, CollisionQuery checker)
+        {
+
+            if (!c.intersects(this.circle)) {
+                return null;
+            }
+            if (isLeaf() && (checker != null && checker.checkCollision(getActor()))) {
+                return getActor();
+            }
+            else if (!isLeaf()) {
+                // TODO maybe decide which one to traverse first based on size,
+                // distance of/between circles
+                // maybe calculate the "insideness" of two circles as dist/r
+                // where dist is the distance
+                // between centers of the two circles and r is the largest of
+                // the two circles' radius'.
+                // Insideness should probably be r/dist to get higher value for
+                // better.
+                Actor res = left.getOneIntersectingObjectDownwards(c, checker);
+                if (res != null) {
+                    return res;
+                }
+                else {
+                    return right.getOneIntersectingObjectDownwards(c, checker);
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Searches for intersections with the circle c, starting from this node and going upwards in the tree.
+         * @param c Circle to check collision against
+         * @param checker Query to do fine grained checks
+         * @return
+         */
+        private Actor getOneIntersectingObjectUpwards(Circle c, CollisionQuery checker)
+        {
+            Node sibling = getSibling();
+            Actor result = null;
+            if (sibling != null) {
+                result = sibling.getOneIntersectingObjectDownwards(sibling.circle, checker);
+            }
+
+            if (result == null && parent != null) {
+                return parent.getOneIntersectingObjectUpwards(c, checker);
+            }
+            else if (result != null) {
+                return result;
+            }
+            return null;
+        }
+
+        /**
+         * Removes this node from the tree it is in by clearing all pointers to
+         * and from this node. Resets all fields in this node and any pointers
+         * from parent or children. The node will have the same state as when it
+         * was created.
+         */
+        public void reset()
+        {
+            if (left != null && left.parent == this) {
+                left.parent = null;
+            }
+            if (right != null && right.parent == this) {
+                right.parent = null;
+            }
+            if (parent != null) {
+                if (parent.left == this) {
+                    parent.left = null;
+                }
+                else if (parent.right == this) {
+                    parent.right = null;
+                }
+            }
+            parent = null;
+            left = null;
+            right = null;
+        }
+
+        private Node getSibling()
+        {
+            if (parent != null) {
+                if (parent.left == this) {
+                    return parent.right;
+                }
+                else {
+                    return parent.left;
+                }
+            }
+            return null;
+        }
+
+    }
+
+    /**
+     * A circle fringe represents extra information calculated about a node in a
+     * tree. In particular the "ancestor expansion" which is the total increase
+     * in the size of the ancestor when insert a new node as a sibling to this
+     * node. 
+     * 
+     * @author Poul Henriksen
+     * 
+     */
+    static class CircleFringe
+        implements Comparable<CircleFringe>
+    {
+        /** The sibling node for this circle fring e*/
+        private Node node;
+        /** Total expansion of all the ancestors of node */
+        private double ancestorExpansion;
+        /** Volume of the new parent for the sibling node and the new node */         
+        private double volume;
+
+        public CircleFringe(Node n, double ancestorExpansion, double volume)
+        {
+            this.ancestorExpansion = ancestorExpansion;
+            this.volume = volume;
+            this.node = n;
+        }
+
+        /**
+         * Will create a new fringe with the same contents as the other fringe.
+         * 
+         * @param other
+         */
+        public CircleFringe(CircleFringe other)
+        {
+            copyValuesFrom(other);
+        }
+
+        public void copyValuesFrom(CircleFringe other) {
+            node = other.getNode();
+            ancestorExpansion = other.getAncestorExpansion();
+            volume = other.getVolume();
+        }
+        
+        /**
+         * Get total increase in the size of the ancestor when insert a new node
+         * as a sibling to this node.
+         */
+        public double getAncestorExpansion()
+        {
+            return ancestorExpansion;
+        }
+
+        /**
+         * Set total increase in the size of the ancestor when insert a new node
+         * as a sibling to this node.
+         */
+        public void setAncestorExpansion(double ancestorExpansion)
+        {
+            this.ancestorExpansion = ancestorExpansion;
+        }
+
+        public int compareTo(CircleFringe other)
+        {
+            return (int) (this.ancestorExpansion - other.getAncestorExpansion());
+        }
+
+        /**
+         * The node that this fringe relates to.
+         */
+        public Node getNode()
+        {
+            return node;
+        }
+
+        /**
+         * The node that this fringe relates to.
+         */
+        public void setNode(Node node)
+        {
+            this.node = node;
+        }
+
+        /**
+         * Set the volume of this fringe. That is, the size of the new parent
+         * from inserting the new node as a sibling to this node.
+         * 
+         */
+        public void setVolume(double volume)
+        {
+            this.volume = volume;
+        }
+
+        /**
+         * Get the volume of this fringe. That is, the size of the new parent
+         * from inserting the new node as a sibling to this node.
+         * 
+         */
+        public double getVolume()
+        {
+            return volume;
+        }
+        
+        /**
+         * Return the cost of this fringe. That is: volume + ancestor expansion
+         * @return
+         */
+        public double getCost() {
+            return ancestorExpansion + volume;
+        }
+
+    }
+
+    /**
+     * Tree of circles. The leaf nodes contains the objects. Each objects has a
+     * bounding circle. The parent of the two nodes has a bounding circle which
+     * is the bounding circle of the two child circles.
+     * 
+     * @author Poul Henriksen
+     * 
+     */
+    class CircleTree
+    {
+        private Node root;
+        private int size;
+        // where did we insert a node the last time? This can speed up insertion
+        // when iterating thorugh the world from one end to the other. Have to
+        // make sure that this node is not deleted from the tree in the
+        // meantime though.
+        private Node lastInsertionPoint; 
+        
+        public void addNode(Node n, Node bestGuess)
+        {
+            Node sibling = bestSibling(n, bestGuess);
+            insertAtNode(n, sibling);
+        }
+
+        public void addNode(Node n)
+        {            
+            //The last insertion point could have been removed
+            if (! contains(lastInsertionPoint)) {
+                lastInsertionPoint = null;
+            }           
+            
+            Node sibling = bestSibling(n, lastInsertionPoint);            
+            insertAtNode(n, sibling);
+            lastInsertionPoint = n.getSibling();            
+        }
+
+        private boolean contains(Node n)
+        {
+            if (n == null) {
+                return false;
+            }            
+            if (root == n || n.parent != null) {
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Find the best place to insert the new node.
+         */
+        public Node bestSibling(Node newNode, Node bestGuess)
+        {
+            if (getRoot() == null) {
+                return null;
+            }
+
+            if(root.isLeaf()) {
+                return root;
+            }            
+            
+            CircleFringe rootFringe = createFringe(newNode, root);            
+
+            // Lets set the initial best one to be the root
+            final CircleFringe best = new CircleFringe(rootFringe);   
+            
+            // There is a good chance that bestGuess will have a better cost
+            // than the root, so we use this to get an initial good value for
+            // the best cost to quickly disregard branches that we do not need
+            // to traverse.
+            if (bestGuess != null) {
+                CircleFringe newFringe = createFringe(newNode, bestGuess);
+                if(newFringe.getCost() < best.getCost()) {
+                    best.copyValuesFrom(newFringe);               
+                }
+            } 
+
+            // Priority queue ordered by ancestor expansion
+            // This priority queue holds the fringe elements
+            PriorityQueue<CircleFringe> fringeQueue = new PriorityQueue<CircleFringe>();
+            
+            // Add the fringe for the root
+            fringeQueue.add(rootFringe);
+
+            bestSiblingSearch(newNode, best, fringeQueue);
+
+            return best.getNode();
+        }
+  
+        /**
+         * Searches through the tree for the best sibling.
+         */
+        private void bestSiblingSearch(Node newNode, final CircleFringe best,
+                PriorityQueue<CircleFringe> fringeQueue)
+        {
+            // Search for the best location to insert
+            while (!fringeQueue.isEmpty()) {
+                // get best candidate
+                CircleFringe tf = fringeQueue.poll();
+                if (tf.getAncestorExpansion() >= (best.getCost())) {
+                    // If the ancestorExpansion of the current fringe is larger
+                    // than the best cost found so far, then we are done.
+                    break;
+                }
+                else {
+                    // calculate new ancestor expansion for the children's fringes
+                    double newAExp = tf.getCost() - tf.getNode().circle.getVolume();
+                    processNode(newNode, tf.getNode().left, newAExp, best, fringeQueue);
+                    processNode(newNode, tf.getNode().right, newAExp, best, fringeQueue);
+                }
+            }
+        }
+        
+        /**
+         * Creates the fringe for newNode at currentNode.
+         * 
+         * TODO: Find the best fringe from the currentNode and up to the root instead of only the fringe at the current node.
+         * @param newNode The new node that is to be inserted
+         * @param currentNode The node for which to create the fringe
+         * @return
+         */
+        private CircleFringe createFringe(Node newNode, Node currentNode)
+        {
+            Circle bestCircle;
+            double bestCost;
+            bestCircle = new Circle();
+            bestCircle.merge(currentNode.circle, newNode.circle);
+
+            bestCost = bestCircle.getVolume();
+            double ae = 0;
+            Node n = currentNode;
+            while (n.parent != null) {
+                Circle enclosingCircle = new Circle();
+                enclosingCircle.merge(n.circle, newNode.circle);
+                double delta = enclosingCircle.getVolume() - n.parent.circle.getVolume();
+                if (delta == 0) {
+                    break;
+                }
+                ae += delta;
+                n = n.parent;
+            }
+            CircleFringe newFringe = new CircleFringe(currentNode, ae, bestCost);
+
+            return newFringe;
+        }
+
+        /**
+         * Looks at a node and checks if it is better than the currently best
+         * result. It also creates a new fringe and inserts it into the queue.
+         */
+        private void processNode(Node newNode, Node childNode, double newAExp, final CircleFringe best,
+                PriorityQueue<CircleFringe> fringeQueue)
+        {
+            Circle enclosingCircle = new Circle();
+            enclosingCircle.merge(childNode.circle, newNode.circle);
+            double enclosingVolume = enclosingCircle.getVolume();
+            
+            // have we found a better cost?
+            if ( (newAExp + enclosingVolume) < best.getCost()) {
+                best.setVolume(enclosingVolume);
+                best.setAncestorExpansion(enclosingVolume);
+                best.setNode(childNode);
+            }
+            if (!childNode.isLeaf()) {
+                CircleFringe newFringe = new CircleFringe(childNode, newAExp, enclosingVolume);
+                fringeQueue.add(newFringe);
+            }
+        }
+
+        /**
+         * Insert new node as a sibling of a node in the tree.
+         * 
+         * @param newNode
+         *            The new node
+         * @param sibling
+         *            A node already in the tree the new node will be a sibling
+         *            of.
+         */
+        public void insertAtNode(Node newNode, Node sibling)
+        {
+            if (getRoot() == null) {
+                setRoot(newNode);
+            }
+            else {
+                Node newParent = new Node();
+                newParent.parent = sibling.parent;
+                if (sibling.parent == null) {
+                    setRoot(newParent);
+                }
+                else if (sibling.parent.left == sibling) {
+                    // parent is a left child
+                    sibling.parent.left = newParent;
+                }
+                else {
+                    // parent is a right child
+                    sibling.parent.right = newParent;
+                }
+
+                newParent.left = sibling;
+                newParent.right = newNode;
+
+                newNode.parent = newParent;
+                sibling.parent = newParent;
+                newParent.circle.merge(newNode.circle, sibling.circle);
+                repairParents(newParent);
+
+            }
+            size++;
+        }
+
+        /**
+         * Adjust the parents bounding volumes to fit with this node.
+         * 
+         * @param newParent
+         */
+        private void repairParents(Node newParent)
+        {
+            Node p = newParent.parent;
+            while (p != null) {
+                int radius = p.circle.getRadius();
+                p.circle.merge(p.left.circle, p.right.circle);
+                // break this loop if the radius no longer changes.
+                if (p.circle.getRadius() == radius) {
+                    break;
+                }
+                p = p.parent;
+            }
+        }
+
+        /**
+         * Used when a node has moved or changed size.
+         * 
+         */
+        public void repairNode(Node n)
+        {
+            if (n == null)
+                return;
+            Node sibling = removeNode(n);
+            addNode(n, sibling);
+        }
+
+        /**
+         * @return The sibling from which it was removed.
+         */
+        public Node removeNode(Node n)
+        {
+            Node sibling = null;
+            if (n == null) {
+                return null;
+            }
+            else if (n == root) {
+                //WTF ? I can't.just delete the root! I can because the node will be a leaf and hence is the only element if it is also the root
+                setRoot(null);
+            }
+            else {
+                sibling = n.getSibling();
+                Node parent = n.parent;
+
+                sibling.parent = parent.parent;
+                if (parent.parent == null) {
+                    setRoot(sibling);
+                }
+                else if (parent.parent.left == parent) {
+                    parent.parent.left = sibling;
+                }
+                else {
+                    parent.parent.right = sibling;
+                }
+                parent.reset();
+                repairParents(sibling);
+            }
+            n.reset();
+            size--;
+            return sibling;
+        }
+
+        public List<Actor> getIntersections(Circle b, CollisionQuery c)
+        {
+            List<Actor> result = new ArrayList<Actor>();
+            if (getRoot() == null) {
+                return result;
+            }
+
+            getRoot().getIntersections(b, c, result);
+
+            return result;
+        }
+
+        public Actor getOneIntersectingObject(Node node, Circle circle, CollisionQuery checker)
+        {
+            if(node != null) {
+                return node.getOneIntersectingObject(circle, checker);
+            }
+            else if(root != null) {
+                return root.getOneIntersectingObject(circle, checker);
+            } 
+            else {
+                return null;
+            }
+        }
+        
+        public Actor getOneIntersectingObject(Node node, CollisionQuery checker)
+        {
+            return node.getOneIntersectingObject(node.circle, checker);
+        }
+
+        public void paintDebug(Graphics g)
+        {
+            if (getRoot() != null) {
+                paintNode(getRoot(), g);
+            }
+        }
+
+        private void paintNode(Node n, Graphics g)
+        {
+            paintCircle(n.circle, g);
+            if (n.left != null) {
+                g.setColor(Color.BLUE);
+                paintLine(n, n.left, g);
+                paintNode(n.left, g);
+            }
+            if (n.right != null) {
+                g.setColor(Color.GREEN);
+                paintLine(n, n.right, g);
+                paintNode(n.right, g);
+            }
+        }
+
+        private void paintLine(Node from, Node to, Graphics g)
+        {
+            if (from == null || to == null) {
+                return;
+            }
+            g.drawLine(from.circle.getX(), from.circle.getY(), to.circle.getX(), to.circle.getY());
+        }
+
+        private void paintCircle(Circle b, Graphics g)
+        {
+            if (b != null) {
+                g.setColor(Color.RED);
+                g.drawOval(b.getX() - b.getRadius(), b.getY() - b.getRadius(), b.getRadius() * 2, b.getRadius() * 2);
+            }
+        }
+
+        public int size()
+        {
+            return size;
+        }
+
+        public void setRoot(Node root)
+        {
+            this.root = root;
+        }
+
+        public Node getRoot()
+        {
+            return root;
+        }
+
+    }
+
+    public CircleTree tree;
+    private GOCollisionQuery actorQuery = new GOCollisionQuery();
+    private NeighbourCollisionQuery neighbourQuery = new NeighbourCollisionQuery();
+    private PointCollisionQuery pointQuery = new PointCollisionQuery();
+    private int cellSize;
+    private List<Actor> objects;
+
+    public void initialize(int width, int height, int cellSize, boolean wrap)
+    {
+        tree = new CircleTree();
+        this.cellSize = cellSize;
+        objects = new ArrayList<Actor>();
+    }
+
+    public synchronized void addObject(Actor actor)
+    {   
+        if (objects.contains(actor)) {
+            return;
+        }
+
+        Node n = createNode(actor);
+        ActorVisitor.setData(actor, n);
+        tree.addNode(n);
+        objects.add(actor);
+    }
+
+    private Node createNode(Actor actor)
+    {
+        Circle c = getCircle(actor);
+        Node n = new Node(c, actor);
+        return n;
+    }
+
+    public synchronized void removeObject(Actor object)
+    {
+        tree.removeNode((Node) ActorVisitor.getData(object));       
+        
+        ActorVisitor.setData(object, null);
+        objects.remove(object);
+    }
+
+    public synchronized void updateObjectLocation(Actor object, int oldX, int oldY)
+    {
+        int ax = ActorVisitor.getX(object);
+        int ay = ActorVisitor.getY(object);
+        if(ax == oldX && ay == oldY) {
+            return;
+        }
+        Node n = (Node) ActorVisitor.getData(object);
+        Circle c = getCircle(object);
+        if (c != null && n != null) {
+            n.circle.setX(c.getX());
+            n.circle.setY(c.getY());
+            tree.repairNode(n);
+        }
+    }
+
+    public synchronized void updateObjectSize(Actor object)
+    {
+        // Node n = (Node) ActorVisitor.getData(object);
+        throw new RuntimeException("No longer working because of missing bounding circle");
+        /*Circle c = ActorVisitor.getBoundingCircle(object);
+        if (c != null && n != null) {
+            n.circle.setRadius(c.getRadius() * cellSize);
+            tree.repairNode(n);
+        }*/
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getObjectsAt(int x, int y, Class<T> cls)
+    {
+        int halfCell = cellSize / 2;
+        Circle b = new Circle(x * cellSize + halfCell, y * cellSize + halfCell, 0);
+        synchronized (pointQuery) {
+            pointQuery.init(x, y, cls);
+            return (List<T>) tree.getIntersections(b, pointQuery);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getIntersectingObjects(Actor actor, Class<T> cls)
+    {
+        Circle b = getCircle(actor);
+        synchronized (actorQuery) {
+            actorQuery.init(cls, actor);
+            return (List<T>) tree.getIntersections(b, actorQuery);
+        }
+    }
+
+    private Circle getCircle(Actor actor)
+    {
+        throw new RuntimeException("No longer working because of missing bounding circle");
+       /* Circle c = ActorVisitor.getBoundingCircle(actor);
+        if (c == null) {
+            return null;
+        }
+        Circle b = new Circle(c.getX() * cellSize, c.getY() * cellSize, c.getRadius() * cellSize);
+        return b;*/
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getObjectsInRange(int x, int y, int r, Class<T> cls)
+    {
+        Circle b = new Circle(x * cellSize, y * cellSize, r * cellSize);
+        synchronized (actorQuery) {
+            actorQuery.init(cls, null);
+            return (List<T>) tree.getIntersections(b, actorQuery);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getNeighbours(Actor a, int distance, boolean diag, Class<T> cls)
+    {
+        int x = ActorVisitor.getX(a);
+        int y = ActorVisitor.getY(a);
+        int xPixel = x * cellSize;
+        int yPixel = y * cellSize;
+        int dPixel = distance * cellSize;
+        int r = 0;
+        if (diag) {
+            r = (int) Math.ceil(Math.sqrt(dPixel * dPixel + dPixel * dPixel));
+        }
+        else {
+            double dy = 0.5 * cellSize;
+            double dx = dPixel + dy;
+            r = (int) Math.sqrt(dy * dy + dx * dx);
+        }
+        Circle c = new Circle(xPixel, yPixel, r);
+
+        synchronized (neighbourQuery) {
+            neighbourQuery.init(x, y, distance, diag, cls);
+            return (List<T>) tree.getIntersections(c, neighbourQuery);
+        }
+
+    }
+
+    public <T extends Actor> List<T> getObjectsInDirection(int x, int y, int angle, int length, Class<T> cls)
+    {
+        // TODO complete
+        throw new RuntimeException("NOT IMPLEMENTED YET");
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getObjects(Class<T> cls)
+    {
+        if (cls == null) {
+            return (List<T>) new ArrayList<Actor>(objects);
+        }
+        List<T> l = new ArrayList<T>();
+        for (Iterator<Actor> iter = objects.iterator(); iter.hasNext();) {
+            Actor actor = iter.next();
+            if (cls.isInstance(actor)) {
+                l.add((T) actor);
+            }
+        }
+        return l;
+    }
+
+    public List<Actor> getObjectsList()
+    {
+        return objects;
+    }
+
+    public void startSequence()
+    {}
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> T getOneObjectAt(Actor actor, int x, int y, Class<T> cls)
+    {		
+        int halfCell = cellSize / 2;
+        Circle b = new Circle(x * cellSize + halfCell, y * cellSize + halfCell, 0);
+        synchronized (pointQuery) {
+            pointQuery.init(x, y, cls);
+            Node node = (Node) ActorVisitor.getData(actor);
+            return (T) tree.getOneIntersectingObject(node, b, pointQuery);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> T getOneIntersectingObject(Actor object, Class<T> cls)
+    {
+        synchronized (actorQuery) {
+            actorQuery.init(cls, object);
+
+            Node node = (Node) ActorVisitor.getData(object);
+            if(node == null) {
+                return null;
+            }
+            return (T) tree.getOneIntersectingObject(node, actorQuery);            
+        }
+
+    }
+
+    /**
+     * Paint bounding boxes used in the circletree.
+     */
+    public void paintDebug(Graphics g)
+    {
+        int missing = 0;
+        synchronized (this) {
+            missing = (objects.size() - tree.size());
+            tree.paintDebug(g);
+        }
+        if (missing > 0) {
+            System.out.println("Objects missing: " + missing);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ClassQuery.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ClassQuery.java
new file mode 100644
index 0000000000000000000000000000000000000000..62f6d2a0a19dd3e1772d57cf425d59304b0f11cb
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ClassQuery.java
@@ -0,0 +1,47 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+
+public class ClassQuery implements CollisionQuery
+{
+    private Class<?> cls;
+    private CollisionQuery subQuery;
+    
+    public ClassQuery(Class<?> cls, CollisionQuery subQuery)
+    {
+        this.cls = cls;
+        this.subQuery = subQuery;
+    }
+    
+    public boolean checkCollision(Actor actor)
+    {
+        if (cls.isInstance(actor)) {
+            return subQuery.checkCollision(actor);
+        }
+        else {
+            return false;
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ColManager.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ColManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..67daa623fc687efe0da4680a229b171c4b000074
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ColManager.java
@@ -0,0 +1,237 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+import greenfoot.collision.ibsp.IBSPColChecker;
+
+import java.awt.Graphics;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+
+/**
+ * This class manages collision checkers. It doesn't do any collision checking
+ * itself but optimises the collision checking by deciding how to delegate
+ * collision checking to other collision checkers.
+ * 
+ * @author Poul Henriksen
+ */
+public class ColManager
+    implements CollisionChecker
+{
+
+    /** Map from classes to objects that are not part of the collision checking (yet). */
+    private Map<Class<? extends Actor>, LinkedList<Actor>> freeObjects = new HashMap<Class<? extends Actor>, LinkedList<Actor>>();
+    
+    /** Classes that are part of the collision checking. */
+    private Set<Class<? extends Actor>> collisionClasses = new HashSet<Class<? extends Actor>>();
+    
+    /** The actual collision checker. */
+    private CollisionChecker collisionChecker = new IBSPColChecker();
+
+    /**
+     * Ensures that objects of this class are in the collision checker
+     * 
+     */
+    private void makeCollisionObjects(Class<? extends Actor> cls, boolean includeSubclasses)
+    {
+        if (cls == null) {
+            //long start = System.nanoTime();
+            Set<Entry<Class<? extends Actor>, LinkedList<Actor>>> entries = freeObjects.entrySet();
+            for (Entry<Class<? extends Actor>, LinkedList<Actor>> entry : entries) {
+                // TODO: bulk add could be faster if implemented in collision checker?
+                for (Actor actor : entry.getValue()) {
+                    collisionChecker.addObject(actor);
+                }
+                collisionClasses.add(entry.getKey());
+            }
+            //long end = System.nanoTime();
+
+            //System.out.println("move all took seconds: " + (end - start) / 1000000000d);
+            freeObjects.clear();
+        }
+        else if (collisionClasses.contains(cls)) {
+        }
+        else {
+            List<? extends Actor> classSet = freeObjects.remove(cls);
+
+            if( classSet != null) {
+                collisionClasses.add(cls);
+    
+                // Add all the objects to the collision checker
+                // TODO: bulk add could be faster if implemented in collision checker?
+                for (Actor actor : classSet) {
+                    collisionChecker.addObject(actor);
+                }
+            }
+        }
+
+        if (includeSubclasses) {
+            // Run through all classes to see if any of them is a subclass.
+            Set<Entry<Class<? extends Actor>, LinkedList<Actor>>> entries = freeObjects.entrySet();
+            // Clone it, so we avoid concurrent modification:
+            entries = new HashSet<Entry<Class<? extends Actor>, LinkedList<Actor>>>(entries);
+            for (Entry<Class<? extends Actor>, LinkedList<Actor>> entry : entries) {
+                if(cls.isAssignableFrom(entry.getKey())) {
+                    makeCollisionObjects(entry.getKey(), false);
+                }
+            }
+        }
+    }
+
+    /**
+     * Ensure that objects of the actors class and all objects of 'cls' or a
+     * subclass is part of the collision detection.
+     * 
+     */
+    private <T extends Actor> void prepareForCollision(Actor actor, Class<T> cls)
+    {
+        makeCollisionObjects(actor.getClass(), false);
+        makeCollisionObjects(cls, true);
+    }
+
+    public void addObject(Actor actor)
+    {
+        Class<? extends Actor> cls = actor.getClass();
+
+        if (collisionClasses.contains(cls)) {
+            collisionChecker.addObject(actor);
+        }
+        else {
+            LinkedList<Actor> classSet = freeObjects.get(cls);
+            if (classSet == null) {
+                classSet = new LinkedList<Actor>();
+                freeObjects.put(cls, classSet);
+            }
+            classSet.add(actor);
+        }
+    }
+
+    public <T extends Actor> List<T> getIntersectingObjects(Actor actor, Class<T> cls)
+    {
+        prepareForCollision(actor, cls);
+        return collisionChecker.getIntersectingObjects(actor, cls);
+    }
+
+    public <T extends Actor> List<T> getNeighbours(Actor actor, int distance, boolean diag, Class<T> cls)
+    {
+        prepareForCollision(actor, cls);
+        return collisionChecker.getNeighbours(actor, distance, diag, cls);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getObjects(Class<T> cls)
+    {
+        List<T> result = collisionChecker.getObjects(cls);
+
+        Set<Entry<Class<? extends Actor>, LinkedList<Actor>>> entries = freeObjects.entrySet();
+        for (Entry<Class<? extends Actor>, LinkedList<Actor>> entry : entries) {
+            if (cls == null || cls.isAssignableFrom(entry.getKey())) {
+                result.addAll((Collection<? extends T>) entry.getValue());
+            }
+        }
+        return result;
+    }
+
+    public <T extends Actor> List<T> getObjectsAt(int x, int y, Class<T> cls)
+    {
+        makeCollisionObjects(cls, true);
+        return collisionChecker.getObjectsAt(x, y, cls);
+    }
+
+    public <T extends Actor> List<T> getObjectsInDirection(int x, int y, int angle, int length, Class<T> cls)
+    {
+        makeCollisionObjects(cls, true);
+        return collisionChecker.getObjectsInDirection(x, y, angle, length, cls);
+    }
+
+    public <T extends Actor> List<T> getObjectsInRange(int x, int y, int r, Class<T> cls)
+    {
+        makeCollisionObjects(cls, true);
+        return collisionChecker.getObjectsInRange(x, y, r, cls);
+    }
+
+    public List<Actor> getObjectsList()
+    {
+        return getObjects(null);
+    }
+
+    public <T extends Actor> T getOneIntersectingObject(Actor object, Class<T> cls)
+    {
+        prepareForCollision(object, cls);
+        return collisionChecker.getOneIntersectingObject(object, cls);
+    }
+
+    public <T extends Actor> T getOneObjectAt(Actor object, int dx, int dy, Class<T> cls)
+    {
+        prepareForCollision(object, cls);
+        return collisionChecker.getOneObjectAt(object, dx, dy, cls);
+    }
+
+    public void initialize(int width, int height, int cellSize, boolean wrap)
+    {
+        collisionChecker.initialize(width, height, cellSize, wrap);
+    }
+
+    public void paintDebug(Graphics g)
+    {
+        collisionChecker.paintDebug(g);
+    }
+
+    public void removeObject(Actor object)
+    {
+        LinkedList<Actor> classSet = freeObjects.get(object.getClass());
+        if (classSet != null) {
+            classSet.remove(object);
+        }
+        else {
+            collisionChecker.removeObject(object);
+        }
+    }
+
+    public void startSequence()
+    {
+        collisionChecker.startSequence();
+    }
+
+    public void updateObjectLocation(Actor object, int oldX, int oldY)
+    {
+        if (!freeObjects.containsKey(object.getClass())) {
+            collisionChecker.updateObjectLocation(object, oldX, oldY);
+        }
+    }
+
+    public void updateObjectSize(Actor object)
+    {
+        if (!freeObjects.containsKey(object.getClass())) {
+            collisionChecker.updateObjectSize(object);
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/CollisionChecker.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/CollisionChecker.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca756868085cac18e559bc53b189d4c1fd7f90e2
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/CollisionChecker.java
@@ -0,0 +1,199 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+
+import java.awt.Graphics;
+import java.util.List;
+
+/**
+ * Interface for an implementation of a particular collision checker algorithm.
+ * 
+ * @author Poul Henriksen
+ */
+public interface CollisionChecker
+{
+    /**
+     * This method is called when the collision checker should initialise.
+     * 
+     * @param width Width of the world
+     * @param height Height of the world
+     * @param cellSize size of one cell
+     * @param wrap Whether the world wraps around the edges
+     */
+    public void initialize(int width, int height, int cellSize, boolean wrap);
+
+    /**
+     * Called when an object is added into the world
+     */
+    public void addObject(Actor actor);
+
+    /**
+     * Called when an object is removed from the world
+     */
+    public void removeObject(Actor object);
+
+    /**
+     * Called when an object has changed its location in the world.
+     * 
+     * @param oldX
+     *            Old location
+     * @param oldY
+     *            Old location
+     */
+    public void updateObjectLocation(Actor object, int oldX, int oldY);
+
+    /**
+     * Called when an object has changed its size in the world.
+     */
+    public void updateObjectSize(Actor object);
+
+    /**
+     * Returns all objects that intersects the given location.
+     * 
+     * @param x   Cell X coordinate
+     * @param y   Cell y coordinate
+     * @param cls
+     *            Class of objects to look for (null or Object.class will find
+     *            all classes)
+     */
+    public <T extends Actor> List<T> getObjectsAt(int x, int y, Class<T> cls);
+
+    /**
+     * Returns all the objects that intersects the given object. This takes the
+     * graphical extent of objects into consideration.
+     * 
+     * @param actor
+     *            An Actor in the world
+     * @param cls
+     *            Class of objects to look for (null or Object.class will find
+     *            all classes)
+     */
+    public <T extends Actor> List<T> getIntersectingObjects(Actor actor, Class<T> cls);
+
+    /**
+     * Returns all objects with the logical location within the specified
+     * circle. In other words an object A is within the range of an object B if
+     * the distance between the center of the two objects is less thatn r.
+     * 
+     * @param x
+     *            Center of the cirle
+     * @param y
+     *            Center of the cirle
+     * @param r
+     *            Radius of the cirle
+     * @param cls
+     *            Class of objects to look for (null or Object.class will find
+     *            all classes)
+     */
+    public <T extends Actor> List<T> getObjectsInRange(int x, int y, int r, Class<T> cls);
+
+    /**
+     * Returns the neighbours to the given location. This method only looks at
+     * the logical location and not the extent of objects. Hence it is most
+     * useful in scenarios where objects only span one cell.
+     * 
+     * @param x
+     *            Location
+     * @param y
+     *            Location
+     * @param distance
+     *            Distance in which to look for other objects
+     * @param diag
+     *            Is the distance also diagonal?
+     * @param cls
+     *            Class of objects to look for (null or Object.class will find
+     *            all classes)
+     * @return A collection of all neighbours found
+     */
+    public <T extends Actor> List<T> getNeighbours(Actor actor, int distance, boolean diag, Class<T> cls);
+
+    /**
+     * Return all objects that intersect a straight line from this object at
+     * a specified angle. The angle is clockwise relative to the current 
+     * rotation of the object.  <br>
+     * 
+     * If the world is wrapped, the line will wrap around the edges.
+     * 
+     * @param x x-coordinate
+     * @param y y-coordinate
+     * @param angle The angle relative to current rotation of the object.
+     * @param length How far we want to look (in cells)
+     * @param cls Class of objects to look for (passing 'null' will find all objects).
+     */
+    public <T extends Actor> List<T> getObjectsInDirection(int x, int y, int angle, int length, Class<T> cls);
+    
+    /**
+     * Get all the objects in the world, or all the objects of a particular class.
+     * <p>
+     * If a class is specified as a parameter, only objects of that class (or
+     * its subclasses) will be returned.
+     * <p>
+     * 
+     * @param cls Class of objects to look for ('null' will find all objects).
+     * 
+     * @return A list of objects.
+     */
+    public <T extends Actor> List<T> getObjects(Class<T> cls);
+    
+    /**
+     * Returns the list of all objects. The returned list may be live (updated
+     * when objects are added/removed from the collision checker) and should not
+     * be directly modified.
+     */
+    public List<Actor> getObjectsList();
+    
+    /**
+     * Methods that marks that a new sequence is started. A sequence in
+     * greenfoot is most likely to start when a new act-iteration is begun
+     * through all the objects. When calling methods interactively or using the
+     * act button, that single invocation should be considered a sequence.
+     * 
+     * <br>
+     * 
+     * This method will initially be used only for performance testing, but
+     * collision detection algorithms might also take advantage of this
+     * information - especially if we will implement an all-at-once algortihm.
+     */
+    public void startSequence();
+
+    /**
+     * Find a single object which intersects the center point of the given cell.
+     * 
+     * @param <T>  The type of actor to be returned (normally inferred from cls)
+     * @param object  The actor performing the query; this actor will not be returned
+     * @param dx  The X co-ordinate of the cell to check
+     * @param dy  The Y co-ordinate of the cell to check
+     * @param cls  The type of object to return. If non-null, the returned object will be
+     *             an instance of this class.
+     * @return An actor intersecting the cell center, or null if no actor of the specified
+     *         type (other than the querying actor) intersects the cell center. 
+     */
+    public <T extends Actor> T getOneObjectAt(Actor object, int dx, int dy, Class<T> cls);
+
+    public <T extends Actor> T  getOneIntersectingObject(Actor object, Class<T> cls);
+
+    public void paintDebug(Graphics g);
+
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/CollisionProfiler.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/CollisionProfiler.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4c7fbc521b7b587ec3938b4c257569a3cbc2318
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/CollisionProfiler.java
@@ -0,0 +1,299 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+
+import java.awt.Graphics;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.List;
+
+public class CollisionProfiler
+    implements CollisionChecker
+{
+    // Set this to true for output to console
+    private static boolean to_console = true;
+    
+    // Set this to true for more complete output
+    private static boolean verbose = true;
+    
+    // Set this to the number of sequences to collect times for,
+    // before outputting the results and resetting the times
+    private static final int MAX_SEQ_COUNT = 100;
+
+    private CollisionChecker checker;
+    
+    private long addObjectTime;
+    private long removeObjectTime;
+    private long updateObjectLocationTime;
+    private long updateObjectSizeTime;
+    private long getObjectsAtTime;
+    private long getIntersectingObjectsTime;
+    private long getObjectsInRangeTime;
+    private long getNeighboursTime;
+    private long getObjectsInDirectionTime;
+    private long getObjectsTime;
+    private long getOneObjectAtTime;
+    private long getOneIntersectingObjectTime;
+    private long getObjectsListTime;
+
+    private int sequenceCount;
+    private int sequences;
+    
+    private PrintStream fileStream;
+
+    private int objectCount;
+    
+    public CollisionProfiler(CollisionChecker checker)
+    {
+        this.checker = checker;
+    }
+    
+    public void initialize(int width, int height, int cellSize, boolean wrap)
+    {
+        checker.initialize(width, height, cellSize, wrap);
+        if (to_console) {
+            fileStream = System.out;
+        }
+        else {
+            File f = new File(System.getProperty("user.home"));
+            f = new File(f, "profile.txt");
+            try {
+                f.createNewFile();
+            }
+            catch (IOException e1) {
+                // TODO Auto-generated catch block
+                e1.printStackTrace();
+            }
+            try {
+                fileStream = new PrintStream(f);
+            }
+            catch (FileNotFoundException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public synchronized void addObject(Actor actor)
+    {
+        long t1 = System.nanoTime();
+        checker.addObject(actor);
+        long t2 = System.nanoTime();
+        addObjectTime += t2 - t1;
+    }
+
+    public synchronized void removeObject(Actor object)
+    {
+        long t1 = System.nanoTime();
+        checker.removeObject(object);
+        long t2 = System.nanoTime();
+        removeObjectTime += t2 - t1;
+    }
+
+    public  synchronized void updateObjectLocation(Actor object, int oldX, int oldY)
+    {
+
+        long t1 = System.nanoTime();
+        checker.updateObjectLocation(object, oldX, oldY);
+        long t2 = System.nanoTime();
+        updateObjectLocationTime += t2 - t1;
+        
+    }
+
+    public  synchronized void updateObjectSize(Actor object)
+    {
+        long t1 = System.nanoTime();
+        checker.updateObjectSize(object);
+        long t2 = System.nanoTime();
+        updateObjectSizeTime += t2 - t1;
+        
+    }
+
+    public <T extends Actor> List<T> getObjectsAt(int x, int y, Class<T> cls)
+    {
+        long t1 = System.nanoTime();
+        List<T> l  = checker.getObjectsAt(x, y, cls);
+        long t2 = System.nanoTime();
+        getObjectsAtTime += t2 - t1;
+        return l;
+    }
+
+    public <T extends Actor> List<T> getIntersectingObjects(Actor actor, Class<T> cls)
+    {
+
+        long t1 = System.nanoTime();
+        List<T> l = checker.getIntersectingObjects(actor, cls);
+        long t2 = System.nanoTime();
+        getIntersectingObjectsTime += t2 - t1;
+        return l;
+    }
+
+    public <T extends Actor> List<T> getObjectsInRange(int x, int y, int r, Class<T> cls)
+    {
+        long t1 = System.nanoTime();
+        List<T> l = checker.getObjectsInRange(x, y, r, cls);
+        long t2 = System.nanoTime();
+        getObjectsInRangeTime += t2 - t1;
+        return l;
+    }
+
+    public <T extends Actor> List<T> getNeighbours(Actor actor, int distance, boolean diag, Class<T> cls)
+    {
+        long t1 = System.nanoTime();
+        List<T> l = checker.getNeighbours(actor, distance, diag, cls);
+        long t2 = System.nanoTime();
+        getNeighboursTime += t2 - t1;
+        return l;
+    }
+
+    public <T extends Actor> List<T> getObjectsInDirection(int x, int y, int angle, int length, Class<T> cls)
+    {
+        long t1 = System.nanoTime();
+        List<T> l = checker.getObjectsInDirection(x, y, angle, length, cls);
+        long t2 = System.nanoTime();
+        getObjectsInDirectionTime += t2 - t1;
+        return l;
+    }
+
+    public synchronized <T extends Actor> List<T> getObjects(Class<T> cls)
+    {
+        long t1 = System.nanoTime();
+        List<T> l = checker.getObjects(cls);
+        long t2 = System.nanoTime();
+        getObjectsTime += t2 - t1;
+        return l;
+    }
+    
+    public List<Actor> getObjectsList()
+    {
+        long t1 = System.nanoTime();
+        List<Actor> l = checker.getObjectsList();
+        long t2 = System.nanoTime();
+        getObjectsListTime += t2 - t1;
+        return l;
+    }
+    
+
+    public void startSequence()
+    {
+        checker.startSequence();
+        sequenceCount++;
+        objectCount += checker.getObjects(null).size();
+        if(sequenceCount > MAX_SEQ_COUNT) {
+            
+            printTimes();
+            
+            addObjectTime = 0;
+            removeObjectTime = 0;
+            updateObjectLocationTime = 0;
+            updateObjectSizeTime = 0;
+            getObjectsAtTime = 0;
+            getIntersectingObjectsTime = 0;
+            getObjectsInRangeTime = 0;
+            getNeighboursTime = 0;
+            getObjectsInDirectionTime = 0;
+            getObjectsTime = 0;
+            getOneObjectAtTime = 0;
+            getOneIntersectingObjectTime = 0;
+            getObjectsListTime = 0;
+            
+            objectCount = 0;
+            
+            sequenceCount = 0;
+        }
+        
+        //Should write the file?
+        fileStream.flush();
+    }
+
+    private void printTimes()
+    {
+        sequences++;
+        if (verbose) {
+            fileStream.println("Sequence # " + sequences);
+        }
+        
+        long totalTime = 0;
+        totalTime += addObjectTime;
+        totalTime += removeObjectTime;
+        totalTime += updateObjectLocationTime;
+        totalTime += updateObjectSizeTime;
+        totalTime += getObjectsAtTime;
+        totalTime += getIntersectingObjectsTime ;
+        totalTime += getObjectsInRangeTime;
+        totalTime += getNeighboursTime;
+        totalTime += getObjectsInDirectionTime;
+        totalTime += getObjectsTime;
+        totalTime += getOneObjectAtTime;
+        totalTime += getOneIntersectingObjectTime;
+        // totalTime += getObjectsListTime;
+        
+    
+        
+        if (verbose) {
+            fileStream.println("addObjectTime                : " + addObjectTime);
+            fileStream.println("removeObjectTime             : " + removeObjectTime);
+            fileStream.println("updateObjectLocationTime     : " + updateObjectLocationTime);
+            fileStream.println("updateObjectSizeTime         : " + updateObjectSizeTime);
+            fileStream.println("getObjectsAtTime             : " + getObjectsAtTime);
+            fileStream.println("getIntersectingObjectsTime   : " + getIntersectingObjectsTime);
+            fileStream.println("getObjectsInRanageTime       : " + getObjectsInRangeTime);
+            fileStream.println("getNeighboursTime            : " + getNeighboursTime);
+            fileStream.println("getObjectsInDirectionTime    : " + getObjectsInDirectionTime);
+            fileStream.println("getObjectsTime               : " + getObjectsTime);
+            fileStream.println("getOneObjectAtTime           : " + getOneObjectAtTime);
+            fileStream.println("getOneIntersectingObjectTime : " + getOneIntersectingObjectTime);
+        }
+        
+        // System.out.println("Delay pr. object (nanosec/obj , objects): " + delay  + "," + objects);
+        fileStream.println(  totalTime +","+ objectCount / sequenceCount);
+        fileStream.println("========================");
+    }
+
+    public <T extends Actor> T getOneObjectAt(Actor actor, int dx, int dy, Class<T> cls)
+    {
+        long t1 = System.nanoTime();
+        T o = checker.getOneObjectAt(actor, dx, dy, cls);
+        long t2 = System.nanoTime();
+        getOneObjectAtTime += t2 - t1;
+        return o;
+    }
+
+    public <T extends Actor> T getOneIntersectingObject(Actor object, Class<T> cls)
+    {
+        long t1 = System.nanoTime();
+        T o = checker.getOneIntersectingObject(object, cls);
+        long t2 = System.nanoTime();
+        getOneIntersectingObjectTime += t2 - t1;
+        return o;
+    }
+
+    public void paintDebug(Graphics g)
+    {
+     //    checker.paintDebug(g);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/CollisionQuery.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/CollisionQuery.java
new file mode 100644
index 0000000000000000000000000000000000000000..1cd5a285b8dd27ed3ff60a3206cd646b71680ccf
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/CollisionQuery.java
@@ -0,0 +1,36 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+
+/**
+ * This is an interface for doing low level collision checks with a Actor. 
+ * 
+ * @author Poul Henriksen
+ */
+public interface CollisionQuery {
+     /**
+      * Does the Actor collide with this collision checker?
+      */
+     public boolean checkCollision(Actor actor);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/GOCollisionQuery.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/GOCollisionQuery.java
new file mode 100644
index 0000000000000000000000000000000000000000..90f38fca67aa139b4bece29c349b737ca543b651
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/GOCollisionQuery.java
@@ -0,0 +1,68 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+
+/**
+ * Checks collisions between GreenfooObjects.
+ * 
+ * @author Poul Henriksen
+ *
+ */
+public class GOCollisionQuery implements CollisionQuery
+{
+    private Class<?> cls;
+    private Actor compareObject;
+
+    /**
+     * Initialise.
+     * 
+     * @param cls   If not null, the compared object must be of this class. If null, the compared
+     *              object's class is not considered.
+     * @param actor Object to compare against other objects.
+     */
+    public void init(Class<?> cls, Actor actor)
+    {
+        this.cls = cls;
+        this.compareObject = actor;
+    }        
+    
+    /**
+     * Checks if the other object collides with this object and if it is of the given class.
+     */
+    public boolean checkCollision(Actor other)
+    {   
+        if(cls != null && !cls.isInstance(other)) {
+            return false;
+        }
+        
+        if(compareObject == null) {
+            return true;
+        }
+        else if(ActorVisitor.intersects(compareObject, other)) {
+            return true;
+        } 
+        return false;
+    }     
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/GridCollisionChecker.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/GridCollisionChecker.java
new file mode 100644
index 0000000000000000000000000000000000000000..3780a4fd0bf704ddb3b6a04d45f61bb30cebc837
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/GridCollisionChecker.java
@@ -0,0 +1,805 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+
+import java.awt.Graphics;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+/**
+ * Very good when objects only span one cell. <br>
+ * Good when most of the cells are occupied by objects. It has a store for each
+ * cell location, so it could potentially take up a lot of memory if the world
+ * is big. <br>
+ * Very poor performance when objects span multiple cells (noOfObjects^2) <br>
+ * TODO: check performance with objects that spans multiple cells.
+ * 
+ * @author Poul Henriksen
+ */
+public class GridCollisionChecker
+    implements CollisionChecker
+{
+    class Cell
+    {
+        private HashMap<Class<?>,List<Actor>> classMap = new HashMap<Class<?>,List<Actor>>();
+        private List<Actor> objects = new ArrayList<Actor>();
+
+        public void add(Actor thing)
+        {
+            Class<?> clazz = thing.getClass();
+            List<Actor> list = classMap.get(clazz);
+            if (list == null) {
+                list = new ArrayList<Actor>();
+                classMap.put(clazz, list);
+            }
+            if(!list.contains(thing)) {
+                list.add(thing);
+            }
+            if(!objects.contains(thing)) {
+                objects.add(thing);
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> List<T> get(Class<T> cls)
+        {
+            return (List<T>) classMap.get(cls);
+        }
+
+        public void remove(Actor object)
+        {
+            objects.remove(object);
+            List<Actor> classes = classMap.get(object.getClass());
+            if(classes != null) {
+                classes.remove(object);
+            }
+        }
+
+        public boolean isEmpty()
+        {
+            return objects.isEmpty();
+        }
+
+        /**
+         * Returns all objects in this cell. Be carefull not to modify this
+         * collection!!!
+         * 
+         * TODO For performace testing it has not been made imuttable...
+         * 
+         * @return
+         */
+        public List<Actor> getAll()
+        {
+            return objects;
+        }
+    }
+
+    /**
+     * A grid world is made up of cells. Each location in the grid is
+     * represented by a cell.
+     * 
+     * @author Poul Henriksen
+     */
+    private class GridWorld
+    {
+        protected Cell[][] world;
+
+        public GridWorld(int width, int height)
+        {
+            world = new Cell[width][height];
+        }
+
+        public Cell get(int x, int y)
+        {
+            return world[x][y];
+        }
+
+        public void set(int x, int y, Cell cell)
+        {
+            world[x][y] = cell;
+        }
+
+        public int getWidth()
+        {
+            return world.length;
+        }
+
+        public int getHeight()
+        {
+            return world[0].length;
+        }
+    }
+
+    private class WrappingGridWorld extends GridWorld
+    {
+        public WrappingGridWorld(int width, int height)
+        {
+            super(width, height);
+        }
+
+        public Cell get(int x, int y)
+        {
+            x = wrap(x, getWidth());
+            y = wrap(y, getHeight());
+            return world[x][y];
+        }
+
+        public void set(int x, int y, Cell cell)
+        {
+            x = wrap(x, getWidth());
+            y = wrap(y, getHeight());
+            world[x][y] = cell;
+        }
+
+        
+    }
+
+    public static class Statistics {
+        
+        private static final String format = "%15s%15s%15s%15s%15s";
+        private long objectsAt;
+        private long intersectionObjects;
+        private long objectsInRange;
+        private long neighbours;
+        private long objectsInDirection;
+        private long startTime = -1;
+
+        public void incGetObjectsAt() {
+            initStartTime();
+            objectsAt++;
+        }
+
+        public void incGetIntersectingObjects() {
+            initStartTime();
+            intersectionObjects++;
+        }
+
+        public void incGetObjectsInRange() {
+            initStartTime();
+            objectsInRange++;
+        }
+
+        public void incGetNeighbours() {
+            initStartTime();
+            neighbours++;
+        }
+
+        public void incGetObjectsInDirection() {
+            initStartTime();
+            objectsInDirection++;
+        }
+
+        private void initStartTime()
+        {
+            if(startTime == -1) {
+                startTime = System.currentTimeMillis();
+            }
+        }
+        
+        public String toString() {
+            return String.format(format, new Object[] {
+                    Long.valueOf(startTime),
+                    Long.valueOf(objectsAt),
+                    Long.valueOf(intersectionObjects),
+                    Long.valueOf(objectsInRange),
+                    Long.valueOf(neighbours),
+                    Long.valueOf(objectsInDirection)
+                    });
+        }
+        
+        public static String headerString() {
+            return String.format(format, new Object[] {
+                    "startTime",
+                    "objectsAt",
+                    "intersection",
+                    "oinRange",
+                    "neighbours",
+                    "inDirection"
+                    });
+        }
+    }
+    
+    
+    private Set<Actor> objects;
+
+    private boolean wrap;
+
+    private GridWorld world;
+    private int cellSize;
+    
+    private Statistics currentStats = new Statistics();
+    private List<Statistics> allStats = new ArrayList<Statistics>();
+    private static boolean PRINT_STATS = false;  
+    
+
+    public void initialize(int width, int height, int cellSize, boolean wrap)
+    {
+        this.wrap = wrap;
+        this.cellSize = cellSize;
+        objects = null;
+        if (PRINT_STATS) {
+            System.out.println(Statistics.headerString());
+            objects = new TreeSet<Actor>(new Comparator<Actor>() {
+                @Override
+              public Comparator<Actor> reversed() {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<Actor> thenComparing(
+                  Comparator<? super Actor> other) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public <U> Comparator<Actor> thenComparing(
+                  Function<? super Actor, ? extends U> keyExtractor,
+                  Comparator<? super U> keyComparator) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public <U extends Comparable<? super U>> Comparator<Actor> thenComparing(
+                  Function<? super Actor, ? extends U> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<Actor> thenComparingInt(
+                  ToIntFunction<? super Actor> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<Actor> thenComparingLong(
+                  ToLongFunction<? super Actor> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<Actor> thenComparingDouble(
+                  ToDoubleFunction<? super Actor> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+                public int compare(Actor arg0, Actor arg1)
+                {
+                    return arg0.hashCode() - arg1.hashCode();
+                }
+            });
+        }
+        else {
+            objects = new HashSet<Actor>();
+        }
+        
+        if (wrap) {
+            world = new WrappingGridWorld(width, height);
+        }
+        else {
+            world = new GridWorld(width, height);
+        }
+    }
+
+    /**
+     * Adds a Actor to the world. <br>
+     * If the coordinates of the object is outside the worlds bounds, an
+     * exception is thrown.
+     * 
+     * @param thing
+     *            The new object to add.
+     */
+    public synchronized void addObject(Actor thing)
+        throws ArrayIndexOutOfBoundsException
+    {
+        testBounds(thing);
+
+        if (!objects.contains(thing)) {
+            int xpos = ActorVisitor.getX(thing);
+            int ypos = ActorVisitor.getY(thing);
+            Cell cell = world.get(xpos, ypos);
+            if (cell == null) {
+                cell = new Cell();
+                world.set(xpos, ypos, cell);
+            }
+            cell.add(thing);
+            objects.add(thing);
+        }
+    }
+
+    private void testBounds(Actor thing)
+    {
+        int ax = ActorVisitor.getX(thing);
+        int ay = ActorVisitor.getY(thing);
+        
+        if (ax >= getWidth()) {
+            throw new ArrayIndexOutOfBoundsException(ax);
+        }
+        if (ay >= getHeight()) {
+            throw new ArrayIndexOutOfBoundsException(ay);
+        }
+        if (ax < 0) {
+            throw new ArrayIndexOutOfBoundsException(ax);
+        }
+        if (ay < 0) {
+            throw new ArrayIndexOutOfBoundsException(ay);
+        }
+    }
+
+    /*
+     * TODO: Bad performance. Can be improved MUCH if we only handle worlds
+     * wehre objects spans a single cell.
+     * 
+     * @see Actor#contains(int, int)
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getObjectsAt(int x, int y, Class<T> cls)
+    {
+        if(wrap) {
+            x = wrap(x, world.getWidth());
+            y = wrap(y, world.getWidth());
+        }
+        List<T> objectsThere = new ArrayList<T>();
+        for (Iterator<Actor> iter = objects.iterator(); iter.hasNext();) {
+            currentStats.incGetObjectsAt();
+            Actor actor = iter.next();
+            int ax = x * cellSize + cellSize / 2;
+            int ay = y * cellSize + cellSize / 2;
+            if ((cls == null || cls.isInstance(actor)) && ActorVisitor.containsPoint(actor, ax, y - ay)) {
+                objectsThere.add((T) actor);
+            }
+        }
+        return objectsThere;
+    }
+
+    /**
+     * Gets all objects within the given radius and of the given class (or
+     * subclass).
+     * 
+     * 
+     * The center of the circle is considered to be at the center of the cell.
+     * Objects which have the center within the circle is considered to be in
+     * range.
+     * 
+     * @param x
+     *            The x-coordinate of the center
+     * @param y
+     *            The y-coordinate of the center
+     * @param r
+     *            The radius
+     * @param cls
+     *            Only objects of this class (or subclasses) are returned
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getObjectsInRange(int x, int y, int r, Class<T> cls)
+    {
+        // TODO Optimise: if it is faster, run through all grid cells in the
+        // distance instead. (based on number of objects vs. cells to run
+        // through)
+        Iterator<Actor> iter = objects.iterator();
+        List<T> neighbours = new ArrayList<T>();
+        while (iter.hasNext()) {
+            Object o = iter.next();
+            currentStats.incGetObjectsInRange();
+            if (cls == null || cls.isInstance(o)) {
+                Actor g = (Actor) o;
+                if (distance(x, y, g) <= r) {
+                    neighbours.add((T) g);
+                }
+            }
+        }
+        return neighbours;
+    }
+
+    /**
+     * Returns the shortest distance from the cell (center of cell ) to the
+     * center of the greenfoot object.
+     * 
+     * @param x
+     *            x-coordinate of the cell
+     * @param y
+     *            y-coordinate of the cell
+     * @param actor
+     * @return
+     */
+    private double distance(int x, int y, Actor actor)
+    {
+        // TODO should x,y be wrapped?
+        double gx = ActorVisitor.getX(actor);
+        double gy = ActorVisitor.getY(actor);
+        double dx = Math.abs(gx - x);
+        double dy = Math.abs(gy - y);
+
+        if (wrap) {
+            double dxWrap = getWidth() - dx;
+            double dyWrap = getWidth() - dy;
+            if (dx >= dxWrap) {
+                dx = dxWrap;
+            }
+            if (dy >= dyWrap) {
+                dy = dyWrap;
+            }
+        }
+
+        return Math.sqrt(dx * dx + dy * dy);
+    }
+
+    /**
+     * Removes the object
+     * 
+     * @param object
+     *            the object to remove
+     */
+    public synchronized void removeObject(Actor object)
+    {
+        int ax = ActorVisitor.getX(object);
+        int ay = ActorVisitor.getY(object);
+        Cell cell = world.get(ax, ay);
+        if (cell != null) {
+            cell.remove(object);
+            if (cell.isEmpty()) {
+                world.set(ax, ay, null);
+            }
+        } 
+        objects.remove(object);
+    }
+
+    /**
+     * Gets the width of the world.
+     */
+    public int getWidth()
+    {
+        return world.getWidth();
+    }
+
+    /**
+     * Gets the height of the world.
+     */
+    public int getHeight()
+    {
+        return world.getHeight();
+    }
+
+    /*
+     * Updates the location of the object in the world.
+     * 
+     * 
+     * @param object
+     *            The object which should be updated
+     * @param oldX
+     *            The old X location of the object
+     * @param oldY
+     *            The old Y location of the object
+     */
+    public void updateObjectLocation(Actor object, int oldX, int oldY)
+    {
+        Cell cell = world.get(oldX, oldY);
+        if (cell != null) {
+            cell.remove(object);
+            if (cell.isEmpty()) {
+                // Do we really want to do this?
+                world.set(oldX, oldY, null);
+            }
+
+        }
+
+        int ax = ActorVisitor.getX(object);
+        int ay = ActorVisitor.getY(object);
+        cell = world.get(ax, ay);
+        if (cell == null) {
+            cell = new Cell();
+            world.set(ax, ay, cell);
+        }
+        cell.add(object);
+    }
+
+    public void updateObjectSize(Actor object)
+    {
+        // we don't care, because we do not directly use the object size for
+        // anything.
+        return;
+    }
+
+    /*
+     * This is very slow in this implementation as it checks against all objects
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getIntersectingObjects(Actor actor, Class<T> cls)
+    {
+        List<T> intersecting = new ArrayList<T>();
+        for (Iterator<Actor> iter = objects.iterator(); iter.hasNext();) {
+            Actor element = iter.next();
+            currentStats.incGetIntersectingObjects();
+            if (element != actor && ActorVisitor.intersects(actor, element) && (cls == null || cls.isInstance(element))) {
+                intersecting.add((T) element);
+            }
+        }
+        return intersecting;
+    }
+
+    /*
+     * @see greenfoot.collision.CollisionChecker#getNeighbours(int, boolean,
+     *      java.lang.Class)
+     */
+    public <T extends Actor> List<T> getNeighbours(Actor actor, int distance, boolean diag, Class<T> cls)
+    {
+        int x = ActorVisitor.getX(actor);
+        int y = ActorVisitor.getY(actor);
+        List<T> c = new ArrayList<T>();
+        if (diag) {
+            for (int dx = x - distance; dx <= x + distance; dx++) {
+                if (!wrap) {
+                    if (dx < 0)
+                        continue;
+                    if (dx >= world.getWidth())
+                        break;
+                }
+                for (int dy = y - distance; dy <= y + distance; dy++) {
+                    if (!wrap) {
+                        if (dy < 0)
+                            continue;
+                        if (dy >= world.getHeight())
+                            break;
+                    }
+                    if (dx == x && dy == y)
+                        continue;
+                    Cell cell = world.get(dx, dy);
+                    currentStats.incGetNeighbours();
+                    if (cell != null) {
+                        Collection<T> found = cell.get(cls);
+                        if (found != null) {
+                            c.addAll(found);
+                        }
+                    }
+                }
+            }
+        }
+        else {
+            int d = distance;
+            int xStart = x;
+            int yStart = y;
+
+            int dyEnd = d;
+            for (int dx = 0; dx <= d; dx++) {
+                for (int dy = dx - d; dy <= dyEnd; dy++) {
+                    int xPos = xStart + dx;
+                    int xNeg = xStart - dx;
+                    int yPos = yStart + dy;
+                    if (!wrap) {
+                        if (yPos >= world.getHeight()) {
+                            break;
+                        }
+                        if (yPos < 0) {
+                            continue;
+                        }
+                    }
+                    if (dx == 0 && dy == 0) {
+                        continue;
+                    }
+                    currentStats.incGetNeighbours();
+                    if (withinBounds(xPos, getWidth())) {
+                        Cell cell = world.get(xPos, yPos);
+                        if (cell != null) {
+                            Collection<T> found = cell.get(cls);
+                            if (found != null) {
+                                c.addAll(found);
+                            }
+                        }
+                    }
+                    if (dx != 0 && withinBounds(xNeg, getWidth())) {
+                        Cell cell = world.get(xNeg, yPos);
+                        if (cell != null) {
+                            Collection<T> found = cell.get(cls);
+                            if (found != null) {
+                                c.addAll(found);
+                            }
+                        }
+                    }
+                }
+                dyEnd--;
+            }
+        }
+        return c;
+    }
+
+    /**
+     * Return all objects that intersect a straight line from this object at a
+     * specified angle. The angle is clockwise relative to the current rotation
+     * of the object. <br>
+     * 
+     * This implementation is likely to change. Currently it uses a Bresenham algorithm. 
+     *
+     * @param x x-coordinate
+     * @param y y-coordinate
+     * @param angle The angle relative to current rotation of the object.
+     * @param length How far we want to look (in cells)
+     * @param cls Class of objects to look for (passing 'null' will find all
+     *            objects).
+     */
+    public <T extends Actor> List<T> getObjectsInDirection(int x, int y, int angle, int length, Class<T> cls)
+    {
+        // The current implementation is using a Bresenham algorithm which is
+        // probably not the one we want to use. The definition should probably
+        // be the following:
+        // Draw a line from the center of the start cell. EVERY object that is in a cell that this line intersects should be returned.
+        
+        // using Bresenham algo
+        List<T> result = new ArrayList<T>();
+        double dy = (2 * Math.sin(Math.toRadians(angle)));
+        double dx =  (2 * Math.cos(Math.toRadians(angle)));
+        int lxMax = (int) Math.abs(Math.round(length * Math.cos(Math.toRadians(angle))));
+        int lyMax = (int) Math.abs(Math.round(length * Math.sin(Math.toRadians(angle))));
+        
+        int stepx, stepy;
+
+        if (dy < 0) {
+            dy = -dy;
+            stepy = -1;
+        }
+        else {
+            stepy = 1;
+        }
+        if (dx < 0) {
+            dx = -dx;
+            stepx = -1;
+        }
+        else {
+            stepx = 1;
+        }
+
+        result.addAll(getObjectsAt(x, y, cls));
+        if (dx > dy) {
+            double fraction = dy - (dx / 2); // same as 2*dy - dx
+            for(int l=0; l< lxMax; l++) {
+                currentStats.incGetObjectsInDirection();
+                if (fraction >= 0) {
+                    y += stepy;
+                    fraction -= dx; // same as fraction -= 2*dx
+                }
+                x += stepx;
+                fraction += dy; // same as fraction -= 2*dy
+
+                result.addAll(getObjectsAt(x, y, cls));
+            }
+        }
+        else {
+            double fraction = dx - (dy / 2);
+            for(int l=0; l< lyMax; l++) {
+                currentStats.incGetObjectsInDirection();
+                if (fraction >= 0) {
+                    x += stepx;
+                    fraction -= dy;
+                }
+                y += stepy;
+                fraction += dx;
+                result.addAll(getObjectsAt(x, y, cls));
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 
+     * Determines if x lies between 0 and width. If wrapping is on this will
+     * always return true.
+     * 
+     * @param xPos
+     * @return
+     */
+    private boolean withinBounds(int x, int width)
+    {
+        return wrap || (!wrap && x >= 0 && x < width);
+    }
+    
+    /**
+     * wraps the number x with the width
+     */
+    private int wrap(int x, int width)
+    {
+        int remainder = x % width;
+        if (remainder < 0) {
+            return width + remainder;
+        }
+        else {
+            return remainder;
+        }
+    }
+
+
+    public void startSequence()
+    {
+        if (PRINT_STATS) {
+            System.out.println(currentStats);
+        }
+        allStats.add(currentStats);
+        currentStats = new Statistics();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getObjects(Class<T> cls)
+    {
+        List<T> objectsThere = new ArrayList<T>();
+        for (Iterator<Actor> iter = objects.iterator(); iter.hasNext();) {
+            currentStats.incGetObjectsAt();
+            Actor actor = iter.next();
+            if (cls == null || cls.isInstance(actor)) {
+                objectsThere.add((T) actor);
+            }
+        }
+        return objectsThere;
+    }
+
+    public List<Actor> getObjectsList()
+    {
+        List<Actor> l = new ArrayList<Actor>(objects);
+        return l;
+    }
+    
+    public <T extends Actor> T getOneObjectAt(Actor actor, int dx, int dy, Class<T> cls)
+    {
+        List<T> neighbours = getObjectsAt(dx, dy, cls);
+        neighbours.remove(actor);
+        if(!neighbours.isEmpty()) {
+            return neighbours.get(0);
+        } else {
+            return null;
+        }
+    }
+
+    public <T extends Actor> T getOneIntersectingObject(Actor object, Class<T> cls)
+    {
+        List<T> intersecting = getIntersectingObjects(object, cls);
+        if(!intersecting.isEmpty()) {
+            return intersecting.get(0);
+        } else {
+            return null; 
+        }
+    }
+
+    public void paintDebug(Graphics g)
+    {
+        // TODO Auto-generated method stub
+        
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/InRangeQuery.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/InRangeQuery.java
new file mode 100644
index 0000000000000000000000000000000000000000..d288c1713c4178ea1d538b5980cf4ef14b0360dc
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/InRangeQuery.java
@@ -0,0 +1,69 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+
+/**
+ * A collision query to check for actors within a certain range of a certain
+ * point
+ * 
+ * @author Davin McCall
+ */
+public class InRangeQuery
+    implements CollisionQuery
+{
+    /** x-coordinate of the center of the circle. In pixels. */
+    private int x;
+    /** y-coordinate of the center of the circle. In pixels. */
+    private int y;
+    /** radius of the circle. In pixels. */
+    private int r;
+
+    /**
+     * Initialise with the given circle. Units are in pixels!
+     */
+    public void init(int x, int y, int r)
+    {
+        this.x = x;
+        this.y = y;
+        this.r = r;
+    }
+
+    /**
+     * Return true if the distance from some point on the actor to the center of
+     * the circle, is less than or equal to the radius of the circle.
+     */
+    public boolean checkCollision(Actor actor)
+    {
+        int actorX = ActorVisitor.toPixel(actor, ActorVisitor.getX(actor));
+        int actorY = ActorVisitor.toPixel(actor, ActorVisitor.getY(actor));   
+        
+        int dx = actorX - x;
+        int dy = actorY - y;
+        int dist = (int) Math.sqrt(dx * dx + dy * dy);
+
+        return (dist) <= r;
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/NeighbourCollisionQuery.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/NeighbourCollisionQuery.java
new file mode 100644
index 0000000000000000000000000000000000000000..13bec0bda8ed8aa35133aa250ef0cb351071faeb
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/NeighbourCollisionQuery.java
@@ -0,0 +1,87 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+
+/**
+ * Checks if a Greenfoot object is within a specific neighbourhood.
+ * 
+ * <p>For the "in the neighbourhood" check, only the object's center point is considered,
+ * not its graphical extent (size).
+ *
+ * @author Poul Henriksen
+ */
+public class NeighbourCollisionQuery implements CollisionQuery
+{
+    private int x;
+    private int y;
+    private int distance;
+    private boolean diag;
+    private Class<?> cls;
+    
+    /**
+     * Set the NeighbourCollisionQuery parameters.
+     * @param x       The X co-ordinate of the center point, in cells
+     * @param y       The Y co-ordinate of the center point, in cells
+     * @param distance  The distance, in cells, as a number of steps from the center point
+     * @param diag    Whether the distance can include diagonal steps
+     * @param cls     The class of actor to look for. If non-null, any actor not of this
+     *                class will not be found by this query. 
+     */
+    public void init(int x, int y, int distance, boolean diag, Class<?> cls) 
+    {
+        this.x = x;
+        this.y = y;
+        this.distance = distance;
+        this.diag = diag;
+        this.cls = cls;
+    }
+
+    public boolean checkCollision(Actor actor)
+    {
+        if(cls != null && !cls.isInstance(actor)) {
+            return false;
+        }
+        
+        int actorX = ActorVisitor.getX(actor);
+        int actorY = ActorVisitor.getY(actor);
+        
+        if(actorX == x && actorY == y) {
+            return false;
+        }       
+        int ax = ActorVisitor.getX(actor);
+        int ay = ActorVisitor.getY(actor);
+        if(diag) {
+            int x1 = x - distance;            
+            int y1 = y - distance;            
+            int x2 = x + distance;            
+            int y2 = y + distance;
+            return (ax >= x1 && ay >=y1 && ax <= x2 && ay <=y2);
+        } else {
+            int dx = Math.abs(ax - x);
+            int dy = Math.abs(ay - y);
+            return ((dx+dy) <= distance);            
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/PointCollisionQuery.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/PointCollisionQuery.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed61134b7a4f9bad9e6700f38f13e1ddfdc2e33d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/PointCollisionQuery.java
@@ -0,0 +1,61 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+
+/**
+ * Checks a collision against a point.
+ *
+ * @author Poul Henriksen
+ */
+public class PointCollisionQuery implements CollisionQuery
+{
+    private int x;
+    private int y;
+    private Class<?> cls;
+    
+    /**
+     * Set the point collision query parameters.
+     * @param x   The X co-ordinate (in pixels)
+     * @param y   The Y co-ordinate (in pixels)
+     * @param cls   The class of actors to locate. If null, locate any actor.
+     */
+    public void init(int x, int y, Class<?> cls)
+    {
+        this.x = x;
+        this.y = y;
+        this.cls = cls;
+    }
+
+    /*
+     * @see greenfoot.collision.CollisionQuery#checkCollision(greenfoot.Actor)
+     */
+    public boolean checkCollision(Actor actor)
+    {
+        if (cls != null && !cls.isInstance(actor)) {
+            return false;
+        }
+        return ActorVisitor.containsPoint(actor, x, y);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/ActorNode.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/ActorNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..4eabcabaec4b80cb11235583e53db6103d5d0f99
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/ActorNode.java
@@ -0,0 +1,136 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision.ibsp;
+
+import greenfoot.Actor;
+
+/**
+ * An ActorNode represents a piece (or whole) of an Actor within the IBSP collision
+ * checking tree. Because an actor can be split over several tree nodes, it may be
+ * represented by several ActorNodes, which are linked together in a linked list. 
+ * 
+ * @author Davin McCall
+ */
+public final class ActorNode
+{
+    private Actor actor;
+    private BSPNode node;
+    private ActorNode next;
+    private ActorNode prev;
+    private boolean mark;
+    
+    public ActorNode(Actor actor, BSPNode node)
+    {
+        this.actor = actor;
+        this.node = node;
+        
+        // insert into linked list
+        ActorNode first = IBSPColChecker.getNodeForActor(actor);
+        this.next = first;
+        IBSPColChecker.setNodeForActor(actor, this);
+        if (next != null) {
+            next.prev = this;
+        }
+        
+        mark = true;
+    }
+    
+    /**
+     * Clar the mark on this ActorNode. This is used by the collision
+     * checker when actors reposition or resize.
+     */
+    public void clearMark()
+    {
+        mark = false;
+    }
+    
+    /**
+     * Mark this ActorNode. This is used by the collision checker when
+     * actors reposition or resize.
+     */
+    public void mark()
+    {
+        mark = true;
+    }
+    
+    /**
+     * Check, and clear, the mark on this ActorNode. This is used by the
+     * collision checker when actors reposition or resize. Returns the
+     * mark value before it was cleared.
+     */
+    public boolean checkMark()
+    {
+        boolean markVal = mark;
+        mark = false;
+        return markVal;
+    }
+    
+    public Actor getActor()
+    {
+        return actor;
+    }
+    
+    public BSPNode getBSPNode()
+    {
+        return node;
+    }
+    
+    /**
+     * Get the next ActorNode for the same actor. Returns null if this
+     * is the last ActorNode for the actor.
+     */
+    public ActorNode getNext()
+    {
+        return next;
+    }
+    
+    /**
+     * Remove this actor node. The node is removed from both the BSPNode
+     * which contains it, and the linked list of actor nodes for the actor.
+     * The next() call will still be valid, unless the next actor is also
+     * removed.
+     */
+    public void remove()
+    {
+        removed();
+        node.actorRemoved(actor);
+    }
+    
+    /**
+     * Notify this actor node that it has been removed from the BSPNode.
+     * It must remove itself from the linked list of actor nodes for the
+     * actor.
+     */
+    public void removed()
+    {
+        if (prev == null) {
+            IBSPColChecker.setNodeForActor(actor, next);
+        }
+        else {
+            prev.next = next;
+        }
+        
+        if (next != null) {
+            next.prev = prev;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/BSPNode.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/BSPNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..96c57b183d65c110718cd6cbe4dfa9ba5a811dfd
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/BSPNode.java
@@ -0,0 +1,256 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2012,2013  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision.ibsp;
+
+import greenfoot.Actor;
+
+import java.util.*;
+
+/**
+ * A node in a BSP tree. Each node covers a rectangular area, and is potentially split
+ * down either axis to allow two child nodes. A BSP node area contains one or more
+ * Actors (or parts of Actors); in implementation, this is represented as a map of
+ * Actor to ActorNode.
+ * 
+ * @author Davin McCall
+ */
+public final class BSPNode
+{
+    private Map<Actor, ActorNode> actors;
+    
+    private BSPNode parent;
+    private Rect area;
+    private int splitAxis;  // which axis is split
+    private int splitPos;   // where it is split (absolute)
+    private BSPNode left;
+    private BSPNode right;
+    
+    private boolean areaRipple; // area has been set, need to ripple
+        // down to children at some stage
+    
+    public BSPNode(Rect area, int splitAxis, int splitPos)
+    {
+        this.area = area;
+        this.splitAxis = splitAxis;
+        this.splitPos = splitPos;
+        
+        // actorNodes = new LinkedList<ActorNode>();
+        actors = new HashMap<Actor, ActorNode>();
+    }
+    
+    /**
+     * Set the child on either side. The child's area must be set
+     * appropriately before calling this.
+     */
+    public void setChild(int side, BSPNode child)
+    {
+        if (side == IBSPColChecker.PARENT_LEFT) {
+            left = child;
+            if (child != null) {
+                child.parent = this;
+            }
+        }
+        else {
+            right = child;
+            if (child != null) {
+                child.parent = this;
+            }
+        }
+    }
+    
+    public void setArea(Rect area)
+    {
+        this.area = area;
+        areaRipple = true;
+    }
+    
+    public void setSplitAxis(int axis)
+    {
+        if (axis != splitAxis) {
+            splitAxis = axis;
+            areaRipple = true;
+        }
+    }
+    
+    public void setSplitPos(int pos)
+    {
+        if (pos != splitPos) {
+            splitPos = pos;
+            areaRipple = true;
+        }
+    }
+
+    public int getSplitAxis()
+    {
+        return splitAxis;
+    }
+    
+    public int getSplitPos()
+    {
+        return splitPos;
+    }
+
+    public Rect getLeftArea()
+    {
+        if (splitAxis == IBSPColChecker.X_AXIS) {
+            return new Rect(area.getX(), area.getY(), splitPos - area.getX(), area.getHeight());
+        }
+        else {
+            return new Rect(area.getX(), area.getY(), area.getWidth(), splitPos - area.getY());
+        }
+    }
+    
+    public Rect getRightArea()
+    {
+        if (splitAxis == IBSPColChecker.X_AXIS) {
+            return new Rect(splitPos, area.getY(), area.getRight() - splitPos, area.getHeight());
+        }
+        else {
+            return new Rect(area.getX(), splitPos, area.getWidth(), area.getTop() - splitPos);
+        }
+    }
+    
+    /**
+     * Returns the area of this node. Careful! Modifying the returned Rect will modify the
+     * node's area!
+     */
+    public Rect getArea()
+    {
+        return area;
+    }
+    
+    private void resizeChildren()
+    {
+        if (left != null) {
+            left.setArea(getLeftArea());
+        }
+        if (right != null) {
+            right.setArea(getRightArea());
+        }
+    }
+    
+    public BSPNode getLeft()
+    {
+        if (areaRipple) {
+            resizeChildren();
+            areaRipple = false;
+        }
+        return left;
+    }
+    
+    public BSPNode getRight()
+    {
+        if (areaRipple) {
+            resizeChildren();
+            areaRipple = false;
+        }
+        return right;
+    }
+    
+    public BSPNode getParent()
+    {
+        return parent;
+    }
+    
+    public void setParent(BSPNode parent)
+    {
+        this.parent = parent;
+    }
+    
+    public int getChildSide(BSPNode child)
+    {
+        if (left == child) {
+            return IBSPColChecker.PARENT_LEFT;
+        }
+        else {
+            return IBSPColChecker.PARENT_RIGHT;
+        }
+    }
+    
+    public String toString()
+    {
+        return "bsp" + hashCode();
+    }
+    
+    public void addActor(Actor actor)
+    {
+        actors.put(actor, new ActorNode(actor, this));
+    }
+    
+    /**
+     * Check whether the actor is already listed in this node, and
+     * mark the ActorNode if this is the case. 
+     */
+    public boolean containsActor(Actor actor)
+    {
+        ActorNode anode = actors.get(actor);
+        if (anode != null) {
+            anode.mark();
+            return true;
+        }
+        return false;
+    }
+    
+    public void actorRemoved(Actor actor)
+    {
+        actors.remove(actor);
+    }
+    
+    public int numberActors()
+    {
+        return actors.size();
+    }
+    
+    /**
+     * Check whether any actors are registered in this node.
+     */
+    public boolean isEmpty()
+    {
+        return actors.isEmpty();
+    }
+    
+    public Iterator<Map.Entry<Actor, ActorNode>> getEntriesIterator()
+    {
+        return actors.entrySet().iterator();
+    }
+    
+    public Iterator<Actor> getActorsIterator()
+    {
+        return actors.keySet().iterator();
+    }
+    
+    public List<Actor> getActorsList()
+    {
+        return new ArrayList<Actor>(actors.keySet());
+    }
+    
+    // Blanks the node.  Used by BSPNodeCache 
+    void blankNode()
+    {
+        actors.clear();
+    }
+    
+    public void areaChanged()
+    {
+        areaRipple = true;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/BSPNodeCache.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/BSPNodeCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f95f9e1361603e5403d27f40fff3a7a0943ae30
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/BSPNodeCache.java
@@ -0,0 +1,70 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision.ibsp;
+
+/**
+ * A cache for BSP nodes, allowing object re-use. Might help reduce garbage collection
+ * impact.
+ * 
+ * @author Davin McCall
+ */
+public class BSPNodeCache
+{
+    private static final int CACHE_SIZE = 1000;
+    
+    private static BSPNode [] cache = new BSPNode[CACHE_SIZE];
+    private static int tail = 0;
+    private static int size = 0;
+    
+    public static BSPNode getBSPNode()
+    {
+        if (size == 0) {
+            return new BSPNode(new Rect(0,0,0,0), 0, 0);
+        }
+        else {
+            int ppos = tail - size;
+            if (ppos < 0) {
+                ppos += CACHE_SIZE;
+            }
+
+            BSPNode node = cache[ppos];
+            node.setParent(null);
+            size--;
+            return node;
+        }
+    }
+    
+    public static void returnNode(BSPNode node)
+    {
+        node.blankNode();
+        cache[tail++] = node;
+        if (tail == CACHE_SIZE) {
+            tail = 0;
+        }
+        size = Math.min(size + 1, CACHE_SIZE);
+        
+        if (node.getLeft() != null || node.getRight() != null) {
+            throw new RuntimeException("HHHHH!");
+        }
+        
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/IBSPColChecker.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/IBSPColChecker.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9ecb335337907e606bc8b2cf120fe185275d6bb
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/IBSPColChecker.java
@@ -0,0 +1,881 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2012,2013  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision.ibsp;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+import greenfoot.collision.*;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.util.*;
+
+/**
+ * A collision checker using a Binary Space Partition tree.
+ * 
+ * <p>Each node of the tree represents a rectangular area, and potentially has
+ * two non-overlapping child nodes which together cover the same area as their
+ * parent.
+ * 
+ * @author Davin McCall
+ */
+public class IBSPColChecker implements CollisionChecker
+{
+    public static final int X_AXIS = 0;
+    public static final int Y_AXIS = 1;
+    
+    public static final int PARENT_LEFT = 0;
+    public static final int PARENT_RIGHT = 1;
+    public static final int PARENT_NONE = 3; // no particular side
+    
+    public static final int REBALANCE_THRESHOLD = 20;
+    
+    private GOCollisionQuery actorQuery = new GOCollisionQuery();
+    private NeighbourCollisionQuery neighbourQuery = new NeighbourCollisionQuery();
+    private PointCollisionQuery pointQuery = new PointCollisionQuery();
+    private InRangeQuery inRangeQuery = new InRangeQuery();
+    
+    private int cellSize;
+    
+    private BSPNode bspTree;
+    
+    public static boolean debugging = false;
+    
+    /* (non-Javadoc)
+     * @see greenfoot.collision.CollisionChecker#initialize(int, int, int, boolean)
+     */
+    public void initialize(int width, int height, int cellSize, boolean wrap)
+    {
+        this.cellSize = cellSize;
+    }
+
+    /*
+     * @see greenfoot.collision.CollisionChecker#addObject(greenfoot.Actor)
+     */
+    public void addObject(Actor actor)
+    {
+        // checkConsistency(true);
+        Rect bounds = getActorBounds(actor);
+        if (bspTree == null) {
+            // The tree is currently empty; just create a new node containing only the one actor
+            int splitAxis;
+            int splitPos;
+            if (bounds.getWidth() > bounds.getHeight()) {
+                splitAxis = X_AXIS;
+                splitPos = bounds.getMiddleX();
+            }
+            else {
+                splitAxis = Y_AXIS;
+                splitPos = bounds.getMiddleY();
+            }
+            bspTree = BSPNodeCache.getBSPNode();
+            bspTree.getArea().copyFrom(bounds);
+            bspTree.setSplitAxis(splitAxis);
+            bspTree.setSplitPos(splitPos);
+            bspTree.addActor(actor);
+        }
+        else {
+            Rect treeArea = bspTree.getArea();
+            while (! treeArea.contains(bounds)) {
+                // We increase the tree area in up to four directions:
+                if (bounds.getX() < treeArea.getX()) {
+                    // double the width out to the left
+                    int bx = treeArea.getX() - treeArea.getWidth();
+                    Rect newArea = new Rect(bx, treeArea.getY(),
+                            treeArea.getRight() - bx, treeArea.getHeight());
+                    BSPNode newTop = BSPNodeCache.getBSPNode();
+                    newTop.getArea().copyFrom(newArea);
+                    newTop.setSplitAxis(X_AXIS);
+                    newTop.setSplitPos(treeArea.getX());
+                    newTop.setChild(PARENT_RIGHT, bspTree);
+                    bspTree = newTop;
+                    treeArea = newArea;
+                }
+                if (bounds.getRight() > treeArea.getRight()) {
+                    // double the width out to the right
+                    int bx = treeArea.getRight() + treeArea.getWidth();
+                    Rect newArea = new Rect(treeArea.getX(), treeArea.getY(),
+                            bx - treeArea.getX(), treeArea.getHeight());
+                    BSPNode newTop = BSPNodeCache.getBSPNode();
+                    newTop.getArea().copyFrom(newArea);
+                    newTop.setSplitAxis(X_AXIS);
+                    newTop.setSplitPos(treeArea.getRight());
+                    newTop.setChild(PARENT_LEFT, bspTree);
+                    bspTree = newTop;
+                    treeArea = newArea;
+                }
+                if (bounds.getY() < treeArea.getY()) {
+                    // double the height out the top
+                    int by = treeArea.getY() - treeArea.getHeight();
+                    Rect newArea = new Rect(treeArea.getX(), by,
+                            treeArea.getWidth(), treeArea.getTop() - by);
+                    BSPNode newTop = BSPNodeCache.getBSPNode();
+                    newTop.getArea().copyFrom(newArea);
+                    newTop.setSplitAxis(Y_AXIS);
+                    newTop.setSplitPos(treeArea.getY());
+                    newTop.setChild(PARENT_RIGHT, bspTree);
+                    bspTree = newTop;
+                    treeArea = newArea;
+                }
+                if (bounds.getTop() > treeArea.getTop()) {
+                    // double the height out the bottom
+                    int by = treeArea.getTop() + treeArea.getHeight();
+                    Rect newArea = new Rect(treeArea.getX(), treeArea.getY(),
+                            treeArea.getWidth(), by - treeArea.getY());
+                    BSPNode newTop = BSPNodeCache.getBSPNode();
+                    newTop.getArea().copyFrom(newArea);
+                    newTop.setSplitAxis(Y_AXIS);
+                    newTop.setSplitPos(treeArea.getTop());
+                    newTop.setChild(PARENT_LEFT, bspTree);
+                    bspTree = newTop;
+                    treeArea = newArea;
+                }
+            }
+            
+            insertObject(actor, bounds, bounds, treeArea, bspTree);
+        }
+        // checkConsistency(true);
+    }
+    
+    /**
+     * Check the consistency of the tree, useful for debugging.
+     */
+    public void checkConsistency(boolean checkActorBounds)
+    {
+        if (! debugging) {
+            return;
+        }
+        
+        LinkedList<BSPNode> stack = new LinkedList<BSPNode>();
+        
+        stack.add(bspTree);
+        while(! stack.isEmpty()) {
+            BSPNode node = stack.removeLast();
+            if (node != null) {
+                Rect nodeArea = node.getArea();
+                List<Actor> actors = node.getActorsList();
+                
+                for (Actor actor : actors) {
+                    // The actor is really in this node
+                    Rect actorBounds = getActorBounds(actor);
+                    if (checkActorBounds && ! nodeArea.intersects(actorBounds)) {
+                        throw new IllegalStateException("Actor not contained within region bounds?");
+                    }
+                }
+                
+                // check the same actor doesn't occur further up tree // TODO
+                
+                if (node.getLeft() != null) {
+                    Rect leftArea = node.getLeft().getArea();
+                    if (! Rect.equals(leftArea, node.getLeftArea())) {
+                        throw new IllegalStateException("Areas wrong!");
+                    }
+                }
+                
+                if (node.getRight() != null) {
+                    Rect rightArea = node.getRight().getArea();
+                    if (! Rect.equals(rightArea, node.getRightArea())) {
+                        throw new IllegalStateException("Areas wrong!");
+                    }
+                }
+                
+                stack.add(node.getLeft());
+                stack.add(node.getRight());
+            }
+        }
+    }
+    
+    /**
+     * Insert an actor into the tree at the given position
+     * 
+     * @param actor   The actor to insert
+     * @param actorBounds  The total bounds of the actor
+     * @param bounds  The bounds of the actor (limited to the present area)
+     * @param area    The total area represented by the current search node
+     * @param node    The current search node (null, if the search has reached its end!)
+     */
+    private void insertObject(Actor actor, Rect actorBounds, Rect bounds, Rect area, BSPNode node)
+    {
+        // the current search node might already contain the
+        // actor...
+        if (node.containsActor(actor)) {
+            return;
+        }
+
+        // If there's no actor at all in the node yet, then we can stop here.
+        // Also, if the area is sufficiently small, there's no point subdividing it.
+        if (node.isEmpty() || (area.getWidth() <= actorBounds.getWidth()
+                && area.getHeight() <= actorBounds.getHeight())) {
+            node.addActor(actor);
+            return;
+        }
+
+        // The search continues...
+        Rect leftArea = node.getLeftArea();
+        Rect rightArea = node.getRightArea();
+
+        Rect leftIntersects = Rect.getIntersection(leftArea, bounds);
+        Rect rightIntersects = Rect.getIntersection(rightArea, bounds);
+
+        if (leftIntersects != null) {
+            if (node.getLeft() == null) {
+                BSPNode newLeft = createNewNode(leftArea);
+                newLeft.addActor(actor);
+                node.setChild(PARENT_LEFT, newLeft);
+            }
+            else {
+                insertObject(actor, actorBounds, leftIntersects, leftArea, node.getLeft());
+            }
+        }
+
+        if (rightIntersects != null) {
+            if (node.getRight() == null) {
+                BSPNode newRight = createNewNode(rightArea);
+                newRight.addActor(actor);
+                node.setChild(PARENT_RIGHT, newRight);
+            }
+            else {
+                insertObject(actor, actorBounds, rightIntersects, rightArea, node.getRight());
+            }
+        }
+    }
+    
+    /**
+     * Create a new node for the given area.
+     */
+    private BSPNode createNewNode(Rect area)
+    {
+        int splitAxis, splitPos;
+        if (area.getWidth() > area.getHeight()) {
+            splitAxis = X_AXIS;
+            splitPos = area.getMiddleX();
+        }
+        else {
+            splitAxis = Y_AXIS;
+            splitPos = area.getMiddleY();
+        }
+        BSPNode newNode = BSPNodeCache.getBSPNode();
+        newNode.setArea(area);
+        newNode.setSplitAxis(splitAxis);
+        newNode.setSplitPos(splitPos);
+        return newNode;
+    }
+    
+    public final Rect getActorBounds(Actor actor)
+    {
+        Rect r = ActorVisitor.getBoundingRect(actor);      
+        return r;
+    }
+    
+    public static void printTree(BSPNode node, String indent, String lead)
+    {
+        if (node == null) {
+            return;
+        }
+        
+        String xx = lead;
+        xx += node + ": ";
+        xx += node.getArea();
+        println(xx);
+        
+        BSPNode left = node.getLeft();
+        BSPNode right = node.getRight();
+        
+        if (left != null) {
+            String newIndent;
+            if (right != null) {
+                newIndent = indent + " |";
+            }
+            else {
+                newIndent = indent + "  ";
+            }
+            printTree(left, newIndent, indent + " \\L-");
+        }
+        
+        if (right != null) {
+            printTree(node.getRight(), indent + "  ", indent + " \\R-");
+        }
+    }
+    
+    public void printTree()
+    {
+        printTree(bspTree, "", "");
+    }
+    
+    public void removeObject(Actor object)
+    {
+        // checkConsistency(true);
+        ActorNode node = getNodeForActor(object);
+        
+        while (node != null) {
+            BSPNode bspNode = node.getBSPNode();
+            node.remove();
+            checkRemoveNode(bspNode);
+            node = getNodeForActor(object);
+        }
+        // checkConsistency(true);
+    }
+    
+    /**
+     * Check whether a node can be removed, and remove it if so, traversing up the
+     * tree and so on. Returns the highest node which wasn't removed.
+     */
+    private BSPNode checkRemoveNode(BSPNode node)
+    {
+        // checkConsistency(false); // may be due to actor moving
+        while (node != null && node.isEmpty()) {
+            BSPNode parent = node.getParent();
+            int side = (parent != null) ? parent.getChildSide(node) : PARENT_NONE;
+            BSPNode left = node.getLeft();
+            BSPNode right = node.getRight();
+            if (left == null) {
+                if (parent != null) {
+                    if (right != null) {
+                        right.getArea().copyFrom(node.getArea());
+                        right.areaChanged();
+                    }
+                    parent.setChild(side, right);
+                }
+                else {
+                    bspTree = right;
+                    if (right != null) {
+                        right.setParent(null);
+                    }
+                }
+                node.setChild(PARENT_RIGHT, null);
+                BSPNodeCache.returnNode(node);
+                node = parent;
+            }
+            else if (right == null) {
+                if (parent != null) {
+                    if (left != null) {
+                        left.getArea().copyFrom(node.getArea());
+                        left.areaChanged();
+                    }
+                    parent.setChild(side, left);
+                }
+                else {
+                    bspTree = left;
+                    if (left != null) {
+                        left.setParent(null);
+                    }
+                }
+                node.setChild(PARENT_LEFT, null);
+                BSPNodeCache.returnNode(node);
+                node = parent;
+            }
+            else {
+                break;
+            }
+        }
+        
+        // checkConsistency(false);
+        return node;
+    }
+    
+    private static int dbgCounter = 0;
+    
+    private static void println(String s)
+    {
+        if (dbgCounter < 3000) {
+            System.out.println(s);
+            // dbgCounter++;
+        }
+    }
+        
+    public static ActorNode getNodeForActor(Actor object)
+    {
+        return (ActorNode) ActorVisitor.getData(object);
+    }
+    
+    public static void setNodeForActor(Actor object, ActorNode node)
+    {
+        ActorVisitor.setData(object, node);
+    }
+    
+    /**
+     * An actors position or size has changed - update the tree.
+     */
+    private void updateObject(Actor object)
+    {
+        // checkConsistency(false); // can't check actor bounds - actor has moved, may be inconsistent
+        ActorNode node = getNodeForActor(object);
+        if (node == null) {
+            // It seems that this can get called before the actor is added to the
+            // checker...
+            return;
+        }
+        
+        Rect newBounds = getActorBounds(object);
+        if (! bspTree.getArea().contains(newBounds)) {
+            // The actor has moved out of the existing tree area
+            while (node != null) {
+                BSPNode rNode = node.getBSPNode();
+                node.remove();
+                checkRemoveNode(rNode);
+                node = node.getNext();
+            }
+            addObject(object);
+            return;
+        }
+        
+        // First process all existing actor nodes. We cull nodes which
+        // no longer contain any part of the actor; also, if we find a
+        // BSPNode which completely contains the actor, we just throw
+        // all the other actor nodes away.
+        while (node != null) {
+            //updateNodeForMovedObject(object, newBounds, bspNode);
+            BSPNode bspNode = node.getBSPNode();
+            Rect bspArea = bspNode.getArea();
+            if (bspArea.contains(newBounds)) {
+                // Ok, we found a BSPNode which completely contains the
+                // actor - we can throw all other actor nodes away
+                ActorNode iter = getNodeForActor(object);
+                while (iter != null) {
+                    if (iter != node) {
+                        BSPNode rNode = iter.getBSPNode();
+                        iter.remove();
+                        checkRemoveNode(rNode);
+                    }
+                    iter = iter.getNext();
+                }
+                return;
+            }
+            else if (! bspArea.intersects(newBounds)) {
+                // This actor node is no longer needed
+                BSPNode rNode = node.getBSPNode();
+                node.remove();
+                checkRemoveNode(rNode);
+            }
+            node.clearMark();
+            node = node.getNext();
+        }
+        
+        // If we got here, there was no single node which contained the whole
+        // actor (and we have culled any nodes which no longer contain any
+        // part of the actor). We now need to find a suitable BSPNode
+        // and do a re-insertion.
+        node = getNodeForActor(object);
+        BSPNode bspNode;
+        Rect bspArea;
+        if (node != null) {
+            bspNode = node.getBSPNode();
+            while (bspNode != null && ! bspNode.getArea().contains(newBounds)) {
+                bspNode = bspNode.getParent();
+            }
+            if (bspNode == null) {
+                // No node contains the whole actor; we need to expand the tree size
+                // First: remove old actor nodes
+                while (node != null) {
+                    bspNode = node.getBSPNode();
+                    node.remove();
+                    checkRemoveNode(bspNode);
+                    node = node.getNext();
+                }
+                // Now: expand the tree
+                addObject(object);
+                return;
+            }
+        }
+        else {
+            bspNode = bspTree;
+        }
+                
+        // Note, we can pass null as the parent because bspNode is guaranteed not to be null.
+        bspArea = bspNode.getArea();
+        insertObject(object, newBounds, newBounds, bspArea, bspNode);
+        
+        // Finally, it's possible the object changed size and therefore has been stored
+        // in higher nodes than previously. This means there are duplicate actor nodes.
+        // The insertObject call will mark all the nodes it touches, so we need remove
+        // any unmarked nodes.
+        node = getNodeForActor(object);
+        while (node != null) {
+            if (! node.checkMark()) {
+                bspNode = node.getBSPNode();
+                node.remove();
+                checkRemoveNode(bspNode);
+            }
+            node = node.getNext();
+        }
+        
+        // checkConsistency(true);
+    }
+    
+    public void updateObjectLocation(Actor object, int oldX, int oldY)
+    {
+        updateObject(object);
+    }
+
+    public void updateObjectSize(Actor object)
+    {
+        updateObject(object);
+    }
+
+    private List<Actor> getIntersectingObjects(Rect r, CollisionQuery query)
+    {
+        Set<Actor> set = new HashSet<Actor>();
+        getIntersectingObjects(r, query, set, bspTree);
+        List<Actor> l = new ArrayList<Actor>(set);
+        return l;
+    }
+    
+    private void getIntersectingObjects(Rect r, CollisionQuery query, Set<Actor> resultSet, BSPNode startNode)
+    {
+        LinkedList<BSPNode> nodeStack = new LinkedList<BSPNode>();
+        
+        if (startNode != null) {
+            nodeStack.add(startNode);
+        }
+        
+        while (! nodeStack.isEmpty()) {
+            BSPNode node = nodeStack.removeLast();
+            if (node.getArea().intersects(r)) {
+                Iterator<Actor> i = node.getActorsIterator();
+                while (i.hasNext()) {
+                    Actor actor = i.next();
+                    if (query.checkCollision(actor)) {
+                        if (! resultSet.contains(actor)) {
+                            resultSet.add(actor);
+                        }
+                    }
+                }
+                
+                BSPNode left = node.getLeft();
+                BSPNode right = node.getRight();
+                if (left != null) {
+                    nodeStack.add(left);
+                }
+                if (right != null) {
+                    nodeStack.add(right);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Check if there is at least one actor in the given BSPNode which matches
+     * the given collision query, and return it if so.
+     */
+    private Actor checkForOneCollision(Actor ignore, BSPNode node, CollisionQuery query)
+    {
+        Iterator<Actor> i = node.getActorsIterator();
+        
+        while (i.hasNext()) {
+            Actor candidate = i.next();
+            if (ignore != candidate && query.checkCollision(candidate)) {
+                return candidate;
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Search for a single object which matches the given collision
+     * query, starting from the given tree node and searching only
+     * down the tree.
+     * 
+     * @param ignore - do not return this actor
+     * @param r  Bounds - do not search nodes which don't intersect this
+     * @param query  The query to check objects against
+     * @param startNode  The node to begin the search from
+     * @return  The actor found, or null
+     */
+    private Actor getOneObjectDownTree(Actor ignore, Rect r, CollisionQuery query, BSPNode startNode)
+    {
+        if (startNode == null) {
+            return null;
+        }
+        
+        LinkedList<BSPNode> nodeStack = new LinkedList<BSPNode>();
+        nodeStack.add(startNode);
+        
+        while (! nodeStack.isEmpty()) {
+            BSPNode node = nodeStack.removeLast();
+            if (node.getArea().intersects(r)) {
+                Actor res = checkForOneCollision(ignore, node, query);
+                if (res != null) {
+                    return res;
+                }
+                
+                BSPNode left = node.getLeft();
+                BSPNode right = node.getRight();
+                if (left != null) {
+                    nodeStack.add(left);
+                }
+                if (right != null) {
+                    nodeStack.add(right);
+                }
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Search down the tree, but only so far as the last node which fully contains the area.
+     * @param r
+     * @param query
+     * @param actor
+     * @return
+     */
+    private Actor getOneIntersectingDown(Rect r, CollisionQuery query, Actor actor)
+    {
+        if (bspTree == null) {
+            return null;
+        }
+        
+        LinkedList<BSPNode> nodeStack = new LinkedList<BSPNode>();
+        nodeStack.add(bspTree);
+        
+        while (! nodeStack.isEmpty()) {
+            BSPNode node = nodeStack.removeLast();
+            if (node.getArea().contains(r)) {
+                Actor res = checkForOneCollision(actor, node, query);
+                if (res != null) {
+                    return res;
+                }
+                
+                BSPNode left = node.getLeft();
+                BSPNode right = node.getRight();
+                if (left != null) {
+                    nodeStack.add(left);
+                }
+                if (right != null) {
+                    nodeStack.add(right);
+                }
+            }
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Search up the tree, up to (not including) the node which fully contains the area.
+     * @param r
+     * @param query
+     * @param actor
+     * @param start
+     */
+    public Actor getOneIntersectingUp(Rect r, CollisionQuery query, Actor actor, BSPNode start)
+    {
+        while (start != null && ! start.getArea().contains(r)) {
+            Actor res = checkForOneCollision(actor, start, query);
+            if (res != null) {
+                return res;
+            }
+            start = start.getParent();
+        }
+        return null;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getObjectsAt(int x, int y, Class<T> cls)
+    {
+        synchronized (pointQuery) {
+            int px = x * cellSize + cellSize / 2;
+            int py = y * cellSize + cellSize / 2;
+            pointQuery.init(px, py, cls);
+            return (List<T>) getIntersectingObjects(new Rect(px, py, 1, 1), pointQuery);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getIntersectingObjects(Actor actor,
+            Class<T> cls)
+    {
+        Rect r = getActorBounds(actor);
+        
+        synchronized (actorQuery) {
+            actorQuery.init(cls, actor);
+            return (List<T>) getIntersectingObjects(r, actorQuery);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getObjectsInRange(int x, int y, int r,
+            Class<T> cls)
+    {
+        int halfCell = cellSize / 2;
+        int size = 2 * r * cellSize;
+        
+        Rect rect = new Rect((x - r) * cellSize + halfCell,
+                (y - r) * cellSize + halfCell,
+                size,
+                size);
+        
+        List<T> result;
+        synchronized (actorQuery) {
+            actorQuery.init(cls, null);
+            result = (List<T>) getIntersectingObjects(rect, actorQuery);
+        }
+        
+        Iterator<T> i = result.iterator();
+        synchronized (inRangeQuery) {
+            inRangeQuery.init(x * cellSize + halfCell , y * cellSize + halfCell, r * cellSize);
+            while (i.hasNext()) {
+                if (! inRangeQuery.checkCollision(i.next())) {
+                    i.remove();
+                }
+            }
+        }
+        
+        return result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getNeighbours(Actor actor, int distance,
+            boolean diag, Class<T> cls)
+    {
+        int x = ActorVisitor.getX(actor);
+        int y = ActorVisitor.getY(actor);
+        int xPixel = x * cellSize;
+        int yPixel = y * cellSize;
+        int dPixel = distance * cellSize;
+        
+        Rect r = new Rect(xPixel - dPixel, yPixel - dPixel, dPixel * 2 + 1, dPixel * 2 + 1);
+        
+        synchronized (neighbourQuery) {
+            neighbourQuery.init(x, y, distance, diag, cls);
+            List<T> res = (List<T>) getIntersectingObjects(r, neighbourQuery);
+            return res;
+        }
+    }
+
+    public <T extends Actor> List<T> getObjectsInDirection(int x, int y,
+            int angle, int length, Class<T> cls)
+    {
+        // non-functional
+        return new ArrayList<T>();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> List<T> getObjects(Class<T> cls)
+    {
+        Set<T> set = new HashSet<T>();
+        LinkedList<BSPNode> nodeStack = new LinkedList<BSPNode>();
+        
+        if (bspTree != null) {
+            nodeStack.add(bspTree);
+        }
+        
+        while (! nodeStack.isEmpty()) {
+            BSPNode node = nodeStack.removeLast();
+            Iterator<Actor> i = node.getActorsIterator();
+            while (i.hasNext()) {
+                Actor actor = i.next();
+                if (cls == null || cls.isInstance(actor)) {
+                    set.add((T) actor);
+                }
+            }
+            BSPNode left = node.getLeft();
+            BSPNode right = node.getRight();
+            if (left != null) {
+                nodeStack.add(left);
+            }
+            if (right != null) {
+                nodeStack.add(right);
+            }
+        }
+        
+        List<T> list = new ArrayList<T>(set);
+        return list;
+    }
+
+    public List<Actor> getObjectsList()
+    {
+        return getObjects(null);
+    }
+
+    public final void startSequence()
+    {
+        // Nothing necessary.
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> T getOneObjectAt(Actor object, int dx, int dy,
+            Class<T> cls)
+    {
+        synchronized (pointQuery) {
+            int px = dx * cellSize + cellSize / 2;
+            int py = dy * cellSize + cellSize / 2;
+            pointQuery.init(px, py, cls);
+            CollisionQuery query = pointQuery;
+            if (cls != null) {
+                query = new ClassQuery(cls, pointQuery);
+            }
+            // Use of getOneIntersectingDown is ok, because the area is only 1x1 pixel
+            // in size - it will be contained by all nodes.
+            return (T) getOneIntersectingDown(new Rect(px, py, 1, 1), query, object);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Actor> T getOneIntersectingObject(Actor actor, Class<T> cls)
+    {
+        Rect r = getActorBounds(actor);
+        synchronized (actorQuery) {
+            actorQuery.init(cls, actor);
+            
+            ActorNode node = getNodeForActor(actor);
+            do {
+                BSPNode bspNode = node.getBSPNode();
+                T ret = (T) getOneObjectDownTree(actor, r, actorQuery, bspNode);
+                if (ret != null) {
+                    return ret;
+                }
+                ret = (T) getOneIntersectingUp(r, actorQuery, actor, bspNode.getParent());
+                if (ret != null) {
+                    return ret;
+                }
+                node = node.getNext();
+            }
+            while (node != null);
+            return (T) getOneIntersectingDown(r, actorQuery, actor);
+        }
+    }
+
+    public void paintDebug(Graphics g)
+    {
+        LinkedList<BSPNode> nodeStack = new LinkedList<BSPNode>();
+        nodeStack.add(bspTree);
+        
+        Color oldColor = g.getColor();
+        //g.setColor(Color.YELLOW);
+        //g.setColor(Color.WHITE);
+        g.setColor(Color.RED);
+        
+        while (! nodeStack.isEmpty()) {
+            BSPNode node = nodeStack.removeLast();
+            if (node != null) {
+                Rect area = node.getArea();
+                g.drawRect(area.getX(), area.getY(), area.getWidth(), area.getHeight());
+                nodeStack.add(node.getLeft());
+                nodeStack.add(node.getRight());
+            }
+        }
+        
+        g.setColor(oldColor);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/Rect.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/Rect.java
new file mode 100644
index 0000000000000000000000000000000000000000..b27e109018ad61ad371b323e4a955a2b09e7f1a9
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/collision/ibsp/Rect.java
@@ -0,0 +1,162 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.collision.ibsp;
+
+final public class Rect
+{
+    private int x, y, width, height;
+    
+    public Rect(int x, int y, int width, int height)
+    {
+        this.x = x;
+        this.y = y;
+        this.width = width;
+        this.height = height;
+    }
+    
+    public void copyFrom(Rect other)
+    {
+        this.x = other.x;
+        this.y = other.y;
+        this.width = other.width;
+        this.height = other.height;
+    }
+    
+    public String toString()
+    {
+        return ("rect (" + x + "," + y + ")-(" + (x + width) + "," + (y + height) + ")");
+    }
+    
+    public int getX()
+    {
+        return x;
+    }
+    
+    public int getMiddleX()
+    {
+        return x + width / 2;
+    }
+    
+    public int getRight()
+    {
+        return x + width;
+    }
+    
+    public int getY()
+    {
+        return y;
+    }
+        
+    public int getMiddleY()
+    {
+        return y + height / 2;
+    }
+    
+    public int getTop()
+    {
+        return y + height;
+    }
+
+    public int getWidth()
+    {
+        return width;
+    }
+    
+    public int getHeight()
+    {
+        return height;
+    }
+    
+    public boolean contains(Rect other)
+    {
+        return (x <= other.x &&
+                y <= other.y &&
+                getTop() >= other.getTop() &&
+                getRight() >= other.getRight());
+    }
+
+    public static Rect getIntersection(Rect a, Rect b)
+    {
+        int a_x = a.getX();
+        int a_r = a.getRight();
+        int a_y = a.getY();
+        int a_t = a.getTop();
+        
+        int b_x = b.getX();
+        int b_r = b.getRight();
+        int b_y = b.getY();
+        int b_t = b.getTop();
+        
+        // Calculate intersection
+        int i_x = Math.max(a_x, b_x);
+        int i_r = Math.min(a_r, b_r);
+        int i_y = Math.max(a_y, b_y);
+        int i_t = Math.min(a_t, b_t);
+        if (i_x >= i_r || i_y >= i_t) {
+            return null;
+        }
+        else {
+            return new Rect(i_x, i_y, i_r - i_x, i_t - i_y);
+        }
+    }
+    
+    public static boolean equals(Rect a, Rect b)
+    {
+        return a.x == b.x && a.y == b.y &&
+            a.width == b.width && a.height == b.height;
+    }
+
+    public void setX(int x)
+    {
+        this.x = x;
+    }
+
+    public void setY(int y)
+    {
+        this.y = y;
+    }
+
+    public void setWidth(int width)
+    {
+        this.width = width;
+    }
+
+    public void setHeight(int height)
+    {
+        this.height = height;
+    }
+
+    public boolean intersects(Rect otherBounds)
+    {        
+        if (otherBounds.x >= getRight()) {
+            return false;
+        } else if (x >= otherBounds.getRight()) {
+            return false;
+        }         
+        if (otherBounds.y >= getTop()) {
+            return false;
+        } else if (y >= otherBounds.getTop()) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ActInterruptedException.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ActInterruptedException.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e75903466b2e854cfceb453c0204472d1ccdd51
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ActInterruptedException.java
@@ -0,0 +1,50 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+/**
+ * Exception that indicates an interruption of the user code.
+ * 
+ * @author Poul Henriksen
+ */
+public class ActInterruptedException extends RuntimeException
+{
+    public ActInterruptedException()
+    {
+        super();
+    }
+
+    public ActInterruptedException(String message)
+    {
+        super(message);
+    }
+
+    public ActInterruptedException(String message, Throwable cause)
+    {
+        super(message, cause);
+    }
+
+    public ActInterruptedException(Throwable cause)
+    {
+        super(cause);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ClassStateManager.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ClassStateManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae5a4cf807aac55b287d34822fda24210afd9b7b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ClassStateManager.java
@@ -0,0 +1,111 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import java.rmi.RemoteException;
+import java.util.LinkedList;
+import java.util.List;
+
+import rmiextension.wrappers.RClass;
+import rmiextension.wrappers.RProject;
+import rmiextension.wrappers.event.RClassEvent;
+import rmiextension.wrappers.event.RClassListenerImpl;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.extensions.event.ClassEvent;
+
+/**
+ * This is a class for keeping track of class state changes, and informing
+ * GClass objects when their compilation state changes. This avoids the need
+ * for each GClass to be a ClassListener.
+ * 
+ * @author Davin McCall
+ */
+public class ClassStateManager extends RClassListenerImpl
+{
+    private GProject project;
+    private List<CompiledStateListener> listeners = new LinkedList<CompiledStateListener>();
+    
+    /**
+     * Construct a ClassStateManager.
+     * @throws RemoteException
+     */
+    public ClassStateManager(GProject project) throws RemoteException
+    {
+        super();
+        this.project = project;
+    }
+    
+    /**
+     * Returns the current project of this class state manager.
+     * @return project  
+     */
+    public GProject getProject()
+    {
+        return project;
+    }
+    
+    /*
+     * @see rmiextension.wrappers.event.RClassListener#classStateChanged(rmiextension.wrappers.event.RClassEvent)
+     */
+    @Override
+    public void classStateChanged(RClassEvent event) throws RemoteException
+    {
+        RClass eventClass = event.getRClass();
+        int eventId = event.getEventId();
+        
+        try {
+            RProject eventProject = eventClass.getPackage().getProject();
+            if(! project.getRProject().equals(eventProject)) {
+                // BlueJ sends out events from all projects to all other projects
+                // For greenfoot we ignore events not belonging to this project.
+                return;
+            }            
+            
+            GPackage pkg = project.getPackage(eventClass.getPackage());
+            GClass gClass = pkg.getGClass(eventClass, true);
+            
+            if (eventId == ClassEvent.STATE_CHANGED) {
+                boolean compiled = event.isClassCompiled();
+                gClass.setCompiledState(compiled);
+                for (CompiledStateListener listener : listeners) {
+                    listener.compiledStateChanged(gClass, compiled);
+                }
+            }
+            else if (eventId == ClassEvent.CHANGED_NAME) {
+                gClass.nameChanged(event.getOldName());
+            }
+        }
+        catch (PackageNotFoundException pnfe) {}
+        catch (ProjectNotOpenException pnoe) {}
+    }
+    
+    public static interface CompiledStateListener
+    {
+        public void compiledStateChanged(GClass gclass, boolean compiled);
+    }
+    
+    public void addCompiledStateListener(CompiledStateListener listener)
+    {
+        listeners.add(listener);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GClass.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..b164bffab2931b58e3b60c3653b6025851e3563c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GClass.java
@@ -0,0 +1,675 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.EventQueue;
+import java.rmi.RemoteException;
+
+import rmiextension.wrappers.RClass;
+import bluej.extensions.ClassNotFoundException;
+import bluej.extensions.CompilationNotStartedException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.runtime.ExecServer;
+import bluej.utility.Debug;
+
+
+/**
+ * Represents a class in Greenfoot. This class wraps the RMI class and contains
+ * some extra functionality. The main reason for creating this class is to have
+ * a place to store information about inheritance relations between classes that
+ * have not been compiled.
+ * 
+ * @author Poul Henriksen
+ */
+public class GClass
+{
+    private static String simObj = "greenfoot.Actor";
+    private static String worldObj = "greenfoot.World";
+    
+    private RClass rmiClass;
+    private GPackage pkg;
+    private String superclassGuess;
+    private String className;
+    private boolean compiled;
+    
+    private ClassView classView;
+    private Class<?> realClass;
+
+    /**
+     * Constructor used by GCoreClass only
+     */
+    protected GClass() {
+        
+    }
+    
+    /**
+     * Constructor for GClass. You should generally not use this -
+     * GPackage maintains a class pool which needs to be updated. Use
+     * GPackage.getGClass().
+     * 
+     * If you use it, remember to call loadSavedSuperClass() afterwards.
+     */
+    public GClass(RClass cls, GPackage pkg, boolean inRemoteCallback)
+    {
+        this.rmiClass = cls;
+        this.pkg = pkg;
+        
+        try {
+            compiled = cls.isCompiled(inRemoteCallback);
+            if (compiled) {
+                loadRealClass();
+            }
+        }
+        catch (PackageNotFoundException e) {
+            Debug.reportError("Problem checking class compiled state", e);
+        }
+        catch (ProjectNotOpenException e) {
+            Debug.reportError("Problem checking class compiled state", e);
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Problem checking class compiled state", e);
+        }
+    }
+    
+    /**
+     * Load the super class from the saved property, or if it is not saved
+     * attempt to guess it.
+     * 
+     * @param inRemoteCallback   should be true iff the execution of this method is blocking the dispatch thread
+     *                           in the remote VM.
+     */
+    public void loadSavedSuperClass(boolean inRemoteCallback) 
+    {
+        String savedSuperclass = getClassProperty("superclass");
+        if(savedSuperclass == null) {
+            guessSuperclass(inRemoteCallback);
+        } else {
+            setSuperclassGuess(savedSuperclass);
+        }
+    }
+    
+    /**
+     * Set the view to be associated with this GClass. The view is
+     * notified when the compilation state changes.
+     */
+    public void setClassView(ClassView view)
+    {
+        classView = view;
+    }
+
+    /**
+     * Notify this class that its name has been changed.
+     */
+    public synchronized void nameChanged(final String oldName)
+    {
+        try {
+            className = null; // retrieve it lazily
+            
+            ProjectProperties props = pkg.getProject().getProjectProperties();
+            String superClass = props.removeProperty("class." + oldName + ".superclass");
+            String classImage = props.removeProperty("class." + oldName + ".image");
+            props.removeCachedImage(oldName);
+            
+            setClassProperty("superclass", superClass);
+            if(classImage != null ) {
+                setClassProperty("image", classImage);
+            }            
+        }
+        catch (Exception e) {
+            Debug.reportError("Remote error in GClass.nameChanged()", e);
+        }
+        
+        if(classView != null) {
+            EventQueue.invokeLater(new Runnable() {
+                public void run()
+                {
+                    classView.nameChanged(oldName);
+                }
+            });
+        }
+    }
+    
+    /**
+     * Get the value of a persistent property for this class
+     * 
+     * @param propertyName   The property name
+     * @return   The property value (a String)
+     */
+    public String getClassProperty(String propertyName)
+    {
+        return pkg.getProject().getProjectProperties().getString("class." + getName() + "." + propertyName);
+    }
+    
+    /**
+     * Set the value of a persistent property for this class
+     * 
+     * @param propertyName  The property name to set
+     * @param value         The value to set the property to
+     */
+    public void setClassProperty(String propertyName, String value)
+    {
+        try {
+            String key = "class." + getName() + "." + propertyName;
+            if (value != null) {
+                pkg.getProject().getProjectProperties().setString(key, value);
+            }
+            else {
+                pkg.getProject().getProjectProperties().removeProperty(key);
+            }
+        }
+        catch (Exception exc) {
+            Debug.reportError("Greenfoot: Could not set class property: " + getName() + "." + propertyName, exc);
+        }
+    }
+    
+    public void compile(boolean waitCompileEnd, boolean forceQuiet)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException, CompilationNotStartedException
+    {
+        rmiClass.compile(waitCompileEnd, forceQuiet);
+    }
+
+    /**
+     * Open the editor for this class.
+     */
+    public void edit()
+    {
+        try {
+            rmiClass.edit();
+        }
+        catch (ProjectNotOpenException e) {
+            Debug.reportError("Could not open editor", e);
+        }
+        catch (PackageNotFoundException e) {
+            Debug.reportError("Could not open editor", e);
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Could not open editor", e);
+        }
+    }
+    
+    /**
+     * Close the editor for this class.
+     */
+    public void closeEditor()
+    {
+        try {
+            rmiClass.closeEditor();
+        }
+        catch (ProjectNotOpenException e) {
+            Debug.reportError("Could not close editor", e);
+        }
+        catch (PackageNotFoundException e) {
+            Debug.reportError("Could not close editor", e);
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Could not close editor", e);
+        }
+    }
+    
+    public boolean hasSourceCode()
+    {
+        try {
+            return rmiClass.hasSourceCode();
+        }
+        catch (ProjectNotOpenException e) {
+            Debug.reportError("Could not close editor", e);
+            return false;
+        }
+        catch (PackageNotFoundException e) {
+            Debug.reportError("Could not close editor", e);
+            return false;
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Could not close editor", e);
+            return false;
+        }
+    }
+    
+    /**
+     * Used for adding code to a void method with no parameters -- creating it if necessary
+     * 
+     * <p>Comment should include the delimiters and be fully formed (and end in a newline).
+     * Method name should have no parameters, it should just be "foo" or similar.
+     * Method body should have no curly braces, it should just be
+     * "foo.bar();\n        if(true) return;\n" or similar, and should end in a newline
+     */
+    public void insertAppendMethod(String comment, String access, String methodName, String methodBody, boolean showEditorOnCreate, boolean showEditorOnAppend)
+    {
+        try {
+            rmiClass.insertAppendMethod(comment, access, methodName, methodBody, showEditorOnCreate, showEditorOnAppend);
+        }
+        catch (ProjectNotOpenException e) {
+            Debug.reportError("Could not insert code", e);
+        }
+        catch (PackageNotFoundException e) {
+            Debug.reportError("Could not insert code", e);
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Could not insert code", e);
+        }
+    }
+    
+    public void insertMethodCallInConstructor(String methodName, boolean showEditor)
+    {
+        try {
+            rmiClass.insertMethodCallInConstructor(methodName, showEditor);
+        }
+        catch (ProjectNotOpenException e) {
+            Debug.reportError("Could not insert code", e);
+        }
+        catch (PackageNotFoundException e) {
+            Debug.reportError("Could not insert code", e);
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Could not insert code", e);
+        }
+    }
+    
+    /**
+     * Display a message in the status area of the editor window for this class.
+     */
+    public void showMessage(String message)
+    {
+        try {
+            rmiClass.showMessage(message);
+        }
+        catch (ProjectNotOpenException e) {
+            Debug.reportError("Could not display editor message", e);
+        }
+        catch (PackageNotFoundException e) {
+            Debug.reportError("Could not display editor message", e);
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Could not display editor message", e);
+        }
+    }
+
+    public void remove()
+    {
+        ProjectProperties props = pkg.getProject().getProjectProperties();
+        props.removeProperty("class." + getName() + ".superclass");
+        props.removeProperty("class." + getName() + ".image");
+        props.removeCachedImage(getName());
+        try {
+            rmiClass.remove();
+        }
+        catch (ProjectNotOpenException e) {
+            Debug.reportError("Could not remove class", e);
+        }
+        catch (PackageNotFoundException e) {
+            Debug.reportError("Could not remove class", e);
+        }
+        catch (ClassNotFoundException e) {
+            Debug.reportError("Could not remove class", e);
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Could not remove class", e);
+        }
+    }
+    
+    /**
+     * Get the java.lang.Class object representing this class. Returns null if
+     * the class cannot be loaded (including if the class is not compiled).
+     */
+    public Class<?> getJavaClass()
+    {
+        return realClass;
+    }
+
+    public GPackage getPackage()
+    {
+        return pkg;
+    }
+
+    /**
+     * Gets the qualified name of this class (thread-safe).
+     */
+    public synchronized String getQualifiedName()
+    {
+        if (className == null) {
+            try {
+                className = rmiClass.getQualifiedName();
+            }
+            catch (Exception e) {
+                Debug.reportError("While trying to get class name", e);
+            }
+        }
+        return className;
+    }
+
+    /**
+     * Gets the name of this class. NOT the qualified name.
+     */
+    public String getName()
+    {
+        return GreenfootUtil.extractClassName(getQualifiedName());
+    }
+    /**
+     * Returns the superclass or null if no superclass can be found.
+     * 
+     * @return superclass, or null if the superclass is not part of this
+     *         project.
+     */
+    public GClass getSuperclass()
+    {
+        GClass superClass = getSuperclassWithoutCheck();
+        // Check if there are cyclic hierarchies, and return null if there is.
+        if(containsCyclicHierarchy()) {
+            return null;
+        }
+        return superClass;
+    }
+
+    /**
+     * Returns true if there is a cycle in the inheritance hierarchy.
+     * @return
+     */
+    private boolean containsCyclicHierarchy()
+    {
+        GClass superCls = getSuperclassWithoutCheck();
+        while (superCls != null) {
+            if (superCls == this) {
+                return true;
+            }
+            superCls = superCls.getSuperclassWithoutCheck();
+        }
+        return false;
+    }
+    
+    /**
+     * Get the GClass for the superclass guess without checking cycles.
+     * 
+     */
+    private GClass getSuperclassWithoutCheck()
+    {
+        String superclassName = getSuperclassGuess();
+        if (superclassName == null) {
+            return null;
+        }
+        superclassName = GreenfootUtil.extractClassName(superclassName);
+        GClass superClass = pkg.getClass(superclassName);
+        return superClass;
+    }
+
+    /**
+     * This method tries to guess which class is the superclass. This can be
+     * used for non compilable and non parseable classes. If the superclass
+     * guess is a class that is not in the default package, it will return the
+     * empty string, since it can otherwise result in problems because we only
+     * deal with the unqualified class name.
+     * <p>
+     * If the class is compiled, it will return the real superclass. <br>
+     * If the class is parseable this information will be used to extract the
+     * superclass. <br>
+     * If the class is not parseable it will use the last superclass that was
+     * known. <br>
+     * In general, we will try to remember the last known superclass, and report
+     * that back. It also saves the superclass between different runs of the
+     * greenfoot application.
+     * 
+     * @return Best guess of the fully qualified name of the superclass.
+     */
+    public String getSuperclassGuess()
+    {
+        return superclassGuess;
+    }
+
+    /**
+     * Sets the superclass guess that will be returned if it is not possible to
+     * find it in another way.
+     * 
+     * <p>If this guess results in a cyclic hierarchy, it will not be set.
+     * 
+     * @return True if it was a valid name. False if invalid and something else
+     *         should be tried (for instance if the guess is the same as the
+     *         name of this)
+     */
+    public boolean setSuperclassGuess(final String superclassName)
+    {
+        if (superclassName.equals(getQualifiedName())) {
+            return false;
+        }
+        
+        boolean isDefaultPkg = !superclassName.contains(".");
+        boolean isGreenfootClass = superclassName.startsWith("greenfoot.");
+        boolean isNewName = superclassGuess == null || !superclassGuess.equals(superclassName);
+
+    
+        if (isNewName && (isDefaultPkg || isGreenfootClass)) {
+            // If the superclass guess is a class that is not in the default
+            // package, it can result in problems because we only deal with the
+            // unqualified class name. Except if it is one of the Greenfoot classes
+
+            superclassGuess = superclassName;  
+            if(containsCyclicHierarchy()) {
+                superclassGuess = "";            
+            } 
+        } else if (!isDefaultPkg && !isGreenfootClass){
+            // We found a super class that is not interesting to greenfoot
+            superclassGuess = "";
+        }
+        setClassProperty("superclass", superclassGuess);
+        return true;
+    }
+    
+    /**
+     * This method tries to guess which class is the superclass. This can be used for non
+     * compilable and non parseable classes.
+     * 
+     * <p>If the class is compiled, it will return the real superclass.<br>
+     * If the class is parseable this information will be used to extract the superclass.<br>
+     * If the is not parseable it will use the last superclass that was known.<br>
+     * In general, we will try to remember the last known superclass, and report that back.
+     * 
+     * @param inRemoteCallback   should be true iff the execution of this method is blocking the dispatch thread
+     *                           in the remote VM.
+     * 
+     * @return Best guess of the name of the superclass (NOT the qualified name).
+     */
+    private synchronized void guessSuperclass(boolean inRemoteCallback)
+    {
+        // TODO This should be called each time the source file is saved. However,
+        // this is not possible at the moment, so we just do it when it is
+        // compiled.
+        String name = this.getQualifiedName();
+        if(name.equals("greenfoot.World") || name.equals("greenfoot.Actor")) {
+            //We do not want to waste time on guessing the name of the superclass for these two classes.
+            if(setSuperclassGuess("")) {
+                return;
+            }
+        }
+        
+        if (isCompiled()) {
+            Class<?> superclass = realClass.getSuperclass();
+            if (superclass == null || !setSuperclassGuess(superclass.getName())) {
+                setSuperclassGuess("");
+            }
+            return;
+        }
+        
+        try {
+            RClass sclass = rmiClass.getSuperclass(inRemoteCallback);
+            if (sclass != null) {
+                setSuperclassGuess(sclass.getQualifiedName());
+                return;
+            }
+        }
+        catch (ProjectNotOpenException e) {
+            Debug.reportError("Couldn't get superclass", e);
+        }
+        catch (PackageNotFoundException e) {
+            Debug.reportError("Couldn't get superclass", e);
+        }
+        catch (ClassNotFoundException e) {
+            Debug.reportError("Couldn't get superclass", e);
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Couldn't get superclass", e);
+        }
+        
+        //Ok, nothing more to do. We just let the superclassGuess be whatever it is.
+    }
+    
+    /**
+     * Check whether this class is compiled (thread-safe).
+     */
+    public boolean isCompiled()
+    {
+        return compiled;
+    }
+    
+    /**
+     * Set the compiled state of this class.
+     */
+    public synchronized void setCompiledState(boolean isCompiled)
+    {
+        compiled = isCompiled;
+        if (classView != null) {
+            // It's safe to call repaint off the event thread
+            classView.repaint();
+        }
+        
+        if (isCompiled) {
+            loadRealClass();
+        }
+        else {
+            realClass = null;
+        }
+    }
+
+    /**
+     * Returns true if this class is a subclass of the given class.
+     * 
+     * <p>A class is not considered a subclass of itself. So, if the two classes
+     * are same it returns false.
+     * 
+     * <p>It only looks at the name of class and not the fully qualified name.
+     */
+    public boolean isSubclassOf(String className)
+    {    
+        if (this.getQualifiedName().equals(className)) {
+            return false;
+        }
+        
+        //Recurse through superclasses
+        GClass currentClass = this;
+        do {
+            String superclassName = currentClass.getSuperclassGuess();
+            if (className.equals(superclassName)) {
+                return true;
+            }
+            currentClass = currentClass.getSuperclass();
+        } while (currentClass != null);
+        return false;
+    }   
+
+    /**
+     * Reload. Do not call from a remote callback.
+     */
+    public synchronized void reload()
+    {
+        loadRealClass();
+        guessSuperclass(false);
+        if(classView != null) {
+            EventQueue.invokeLater(new Runnable() {
+                public void run()
+                {
+                    classView.updateView();
+                }
+            });
+        }
+    }
+
+    /**
+     * Try and load the "real" (java.lang.Class) class represented by this
+     * GClass, using the current class loader.
+     * 
+     * <p>Must be called from a synchronized context!
+     * 
+     * @return The class, or null if unsuccessful
+     */
+    private void loadRealClass()
+    {
+        Class<?> cls = null;
+        if (! isCompiled()) {
+            realClass = null;
+            return;
+        }
+        try {
+            String className = getQualifiedName();
+            //it is important that we use the right classloader
+            ClassLoader classLdr = ExecServer.getCurrentClassLoader();
+            cls = Class.forName(className, false, classLdr);
+        }
+        catch (java.lang.ClassNotFoundException cnfe) {
+            // couldn't load: that's ok, we return null
+            // cnfe.printStackTrace();
+        }
+        catch (LinkageError e) {
+            // TODO log this properly? It can happen for various reasons, not
+            // necessarily a real error.
+            e.printStackTrace();
+        }
+        realClass = cls;
+    }
+
+    /**
+     * Returns true if this GClass represents the greenfoot.Actor class.
+     *
+     */
+    public boolean isActorClass()
+    {
+        return getQualifiedName().equals(simObj);
+    }
+    
+    /**
+     * Returns true if this GClass represents the greenfoot.World class.
+     *
+     */
+    public boolean isWorldClass()
+    {
+        return getQualifiedName().equals(worldObj);
+    }
+
+    /**
+     * Returns true if this GClass represents a class that is a subclass of the greenfoot.Actor class.
+     *
+     */
+    public boolean isActorSubclass()
+    {
+        return isSubclassOf(simObj);
+    }
+
+    /**
+     * Returns true if this GClass represents a class that is a subclass of the greenfoot.World class.
+     *
+     */
+    public boolean isWorldSubclass()
+    {        
+        return isSubclassOf(worldObj);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GCoreClass.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GCoreClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6815275916345874881b25c546d2b1c9a557e25
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GCoreClass.java
@@ -0,0 +1,179 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.Actor;
+import greenfoot.World;
+import greenfoot.util.GreenfootUtil;
+
+import java.io.IOException;
+import java.rmi.RemoteException;
+
+import bluej.Config;
+import bluej.extensions.CompilationNotStartedException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.utility.DialogManager;
+
+/**
+ * Specialisation of a GClass that represent one of the two core Greenfoot
+ * classes: Actor or World. Overrides most of the public methods of GClass to do
+ * nothing and return null, since they are not really valid for these two
+ * classes.
+ * 
+ * @author Poul Henriksen
+ */
+public class GCoreClass extends GClass
+{
+    private Class<?> cls;
+    private GPackage pkg;
+
+    public GCoreClass(Class<?> cls, GProject project)
+    {
+        super();
+        this.cls = cls;
+        this.pkg = new GPackage(project);
+    }
+
+    @Override
+    public void compile(boolean waitCompileEnd, boolean forceQuiet) throws ProjectNotOpenException,
+    PackageNotFoundException, RemoteException,
+    CompilationNotStartedException
+    {
+        return;
+    }
+
+    @Override
+    public void edit()
+    {
+        String page = isWorldClass() ? "greenfoot/World.html" : "greenfoot/Actor.html";
+        try {
+            GreenfootUtil.showApiDoc(page);
+        }
+        catch (IOException e) {
+            String errMsg = Config.getString("greenfoot.cannotFindAPIDocumentation");
+            DialogManager.showErrorText(GreenfootMain.getInstance().getFrame(), errMsg);
+        }    
+    }
+
+    @Override
+    public String getClassProperty(String propertyName)
+    {
+        return "";
+    }
+
+    @Override
+    public Class<?> getJavaClass()
+    {
+        return cls;
+    }
+
+    @Override
+    public String getName()
+    {
+        return cls.getSimpleName();
+    }
+
+    @Override
+    public GPackage getPackage()
+    {
+        return pkg;
+    }
+
+    @Override
+    public String getQualifiedName()
+    {
+        return cls.getName();
+    }
+
+    @Override
+    public GClass getSuperclass()
+    {
+        return null;
+    }
+
+    @Override
+    public boolean isActorClass()
+    {
+        return cls.equals(Actor.class);
+    }
+
+    @Override
+    public boolean isActorSubclass()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isCompiled()
+    {
+        return true;
+    }
+
+    @Override
+    public boolean isSubclassOf(String className)
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isWorldClass()
+    {
+        return cls.equals(World.class);
+    }
+
+    @Override
+    public boolean isWorldSubclass()
+    {
+        return false;
+    }
+
+    @Override
+    public void nameChanged(String oldName)
+    {
+        return;
+    }
+
+    @Override
+    public void reload()
+    {
+        return;
+    }
+
+    @Override
+    public void remove()
+    {
+        return;
+    }
+
+    @Override
+    public void setClassProperty(String propertyName, String value)
+    {
+        return;
+    }
+
+    @Override
+    public boolean setSuperclassGuess(String superclassName)
+    {
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GNamedValue.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GNamedValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..2463129417fcec1436b5a57ddad35671aa6a1bde
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GNamedValue.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the BlueJ program. 
+ Copyright (C) 2010  Michael Kolling and John Rosenberg 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import bluej.debugger.gentype.JavaType;
+import bluej.debugmgr.NamedValue;
+
+/**
+ * A class to represent a simple named value.
+ * 
+ * @author Davin McCall
+ */
+public class GNamedValue implements NamedValue
+{
+    private String name;
+    private JavaType type;
+    
+    public GNamedValue(String instanceName, JavaType type)
+    {
+        name = instanceName;
+        this.type = type;
+    }
+
+    public JavaType getGenType()
+    {
+        return type;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public boolean isFinal()
+    {
+        return true;
+    }
+
+    public boolean isInitialized()
+    {
+        return true;
+    }            
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GPackage.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GPackage.java
new file mode 100644
index 0000000000000000000000000000000000000000..06bb588a2db5b3ab287bc7ec3a3c6ebe2760dd15
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GPackage.java
@@ -0,0 +1,292 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.World;
+import greenfoot.util.GreenfootUtil;
+
+import java.io.File;
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import rmiextension.wrappers.RClass;
+import rmiextension.wrappers.RJobQueue;
+import rmiextension.wrappers.RPackage;
+import bluej.compiler.CompileObserver;
+import bluej.debugmgr.InvokerCompiler;
+import bluej.extensions.CompilationNotStartedException;
+import bluej.extensions.MissingJavaFileException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.utility.Debug;
+
+/**
+ * Represents a package in Greenfoot.
+ * 
+ * <p>A GPackage is essentially a reference to a remote package (RPackage), together
+ * with a pool of GClass objects representing the classes in the package. 
+ * 
+ * @author Poul Henriksen
+ */
+public class GPackage
+{
+    private RPackage pkg;
+    private GProject project; 
+    
+    private Map<RClass,GClass> classPool = new HashMap<RClass,GClass>();
+    
+    /**
+     * Contructor for an unspecified package, but for which a project is known.
+     * Used to allow a class to not be part of a package, but still being able
+     * to get the project the class is part of.
+     */
+    GPackage(GProject project) 
+    {
+        if(project == null) {
+            throw new NullPointerException("Project must not be null.");
+        }
+        this.project = project;
+    }
+    
+    /**
+     * Construct a new GPackage; this should generally only be called by
+     * GProject.
+     * 
+     * @param pkg  The reference to the remote package
+     * @param project  The project
+     */
+    public GPackage(RPackage pkg, GProject project)
+    {
+        if(pkg == null) {
+            throw new NullPointerException("Pkg must not be null.");
+        }
+        if(project == null) {
+            throw new NullPointerException("Project must not be null.");
+        }
+        this.pkg = pkg;
+        this.project = project;
+    }
+    
+    /**
+     * Get the GClass wrapper for a remote class in this package.
+     */
+    public GClass getGClass(RClass remoteClass, boolean inRemoteCallback)
+    {
+        if (remoteClass == null) {
+            return null;
+        }
+        
+        GClass gClass;
+        synchronized (classPool) {
+            gClass = classPool.get(remoteClass);
+            if (gClass == null) {
+                gClass = new GClass(remoteClass, this, inRemoteCallback);
+                classPool.put(remoteClass, gClass);
+                gClass.loadSavedSuperClass(inRemoteCallback);
+            }
+        }
+        return gClass;
+    }
+
+    public void compileAll()
+    {
+        try {
+            pkg.compileAll();
+        }
+        catch (ProjectNotOpenException pnoe) {
+            Debug.reportError("Could not start compilation", pnoe);
+        }
+        catch (CompilationNotStartedException cnse) {
+            Debug.reportError("Could not start compilation", cnse);
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Could not start compilation", re);
+        }
+        catch (PackageNotFoundException pnfe) {
+            Debug.reportError("Could not start compilation", pnfe);
+        }
+    }
+
+    public File getDir()
+    {
+        try {
+            return pkg.getDir();
+        }
+        catch (ProjectNotOpenException pnoe) {
+            Debug.reportError("Could not get package directory", pnoe);
+            throw new InternalGreenfootError(pnoe);
+        }
+        catch (PackageNotFoundException pnfe) {
+            Debug.reportError("Could not get package directory", pnfe);
+            throw new InternalGreenfootError(pnfe);
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Could not get package directory", re);
+            throw new InternalGreenfootError(re);
+        }
+    }
+
+    public GProject getProject()
+    {
+        return project;
+    }
+
+    public GClass[] getClasses(boolean inRemoteCallback)
+    {
+        try {
+            RClass[] rClasses = pkg.getRClasses();
+            GClass[] gClasses = new GClass[rClasses.length];
+            for (int i = 0; i < rClasses.length; i++) {
+                RClass rClass = rClasses[i];
+                gClasses[i] = getGClass(rClass, inRemoteCallback);
+            }
+            return gClasses;
+        }
+        catch (ProjectNotOpenException e) {
+            Debug.reportError("Could not get package classes", e);
+            throw new InternalGreenfootError(e);
+        }
+        catch (PackageNotFoundException e) {
+            Debug.reportError("Could not get package classes", e);
+            throw new InternalGreenfootError(e);
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Could not get package classes", e);
+            throw new InternalGreenfootError(e);
+        }
+    }
+
+    public GClass newClass(String className, boolean inRemoteCallback)
+    {
+        GClass newClass = null;
+        try {
+            RClass newRClass = pkg.newClass(className);
+            newClass = new GClass(newRClass, this, inRemoteCallback);
+            synchronized (classPool) {
+                classPool.put(newRClass, newClass);
+            }
+            newClass.loadSavedSuperClass(false);
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Creating new class", re);
+        }
+        catch (ProjectNotOpenException pnoe) {
+            Debug.reportError("Creating new class", pnoe);
+        }
+        catch (PackageNotFoundException pnfe) {
+            Debug.reportError("Creating new class", pnfe);
+        }
+        catch (MissingJavaFileException mjfe) {
+            Debug.reportError("Creating new class", mjfe);
+        }
+        return newClass;
+    }
+    
+    /**
+     * Get the named class (null if it cannot be found).
+     * Do not call from a remote callback.
+     */
+    public GClass getClass(String className)
+    {
+        try {
+            RClass rClass = pkg.getRClass(className);
+            return getGClass(rClass, false);
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Getting class", re);
+        }
+        catch (ProjectNotOpenException pnoe) {
+            Debug.reportError("Creating new class", pnoe);
+        }
+        catch (PackageNotFoundException pnfe) {
+            Debug.reportError("Creating new class", pnfe);
+        }
+        
+        return null;
+    }
+
+    /** 
+     * Returns all the world sub-classes in this package that can be instantiated.
+     * Do not call from a remote callback.
+     */
+    @SuppressWarnings("unchecked")
+    public List<Class<? extends World>> getWorldClasses()
+    {
+        List<Class<? extends World>> worldClasses= new LinkedList<Class<? extends World>>();
+        GClass[] classes = getClasses(false);
+        for (int i = 0; i < classes.length; i++) {
+            GClass cls = classes[i];
+            if(cls.isWorldSubclass()) {
+                Class<? extends World> realClass = (Class<? extends World>) cls.getJavaClass();   
+                if (GreenfootUtil.canBeInstantiated(realClass)) {                  
+                    worldClasses.add(realClass);
+                }                    
+            }
+        }
+        return worldClasses;
+    }
+
+    /**
+     * Get access to the remote compiler queue.
+     */
+    public InvokerCompiler getCompiler()
+    {
+        try {
+            final RJobQueue rqueue = pkg.getCompiler();
+            return new InvokerCompiler() {
+                @Override
+                public void compile(File[] files, CompileObserver observer)
+                {
+                    try {
+                        rqueue.compile(files, new LocalCompileObserverWrapper(observer));
+                    }
+                    catch (RemoteException re) {
+                        Debug.reportError("Error trying to compile on remote queue", re);
+                    }
+                }
+            };
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Error getting remote compiler queue", re);
+            return null;
+        }
+    }
+    
+    public void reload()
+    {
+        try {
+            pkg.reload();
+        }
+        catch (ProjectNotOpenException e) {
+            e.printStackTrace();
+        }
+        catch (PackageNotFoundException e) {
+            e.printStackTrace();
+        }
+        catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GProject.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GProject.java
new file mode 100644
index 0000000000000000000000000000000000000000..872efa7148675ad009d5a0da75741b710203a6cc
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GProject.java
@@ -0,0 +1,465 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.event.CompileListener;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import rmiextension.wrappers.RPackage;
+import rmiextension.wrappers.RProject;
+import rmiextension.wrappers.event.RCompileEvent;
+import rmiextension.wrappers.event.RProjectListenerImpl;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.extensions.event.CompileEvent;
+import bluej.utility.Debug;
+
+/**
+ * Represents a project in greenfoot.
+ * 
+ * <p>Most methods are thread-safe.
+ * 
+ * @author Poul Henriksen
+ */
+public class GProject extends RProjectListenerImpl
+    implements CompileListener
+{    
+    private Map<RPackage,GPackage> packagePool = new HashMap<RPackage,GPackage>();
+    
+    private RProject rProject;
+
+    private ProjectProperties projectProperties;
+    
+    private List<CompileListener> compileListeners = new LinkedList<CompileListener>();
+    
+    /**
+     * Factor method for creating GProjects. The caller is responsible for
+     * setting up the returned project as a compile listener.
+     */
+    public static GProject newGProject(RProject rmiProject)
+    {
+        try {
+            return new GProject(rmiProject);
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Error constructing Greenfoot Project", re);
+            throw new InternalGreenfootError(re);
+        }
+    }
+    
+    /**
+     * Create a G(reenfoot)Project object. This is a singleton for every
+     * running Greenfoot project (for every VM).
+     * 
+     * <p>The creator is responsible for setting up the GProject as a compile listener.
+     */
+    private GProject(RProject rmiProject) throws RemoteException
+    {
+        this.rProject = rmiProject;
+        try {
+            rmiProject.addListener(this);
+            projectProperties = new ProjectProperties(getDir());
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Could not instantiate Greenfoot project", re);
+            throw new InternalGreenfootError(re);
+        }
+    }
+    
+    /**
+     * Close the project (thread-safe). This causes the VM to terminate.
+     * @throws RemoteException
+     */
+    public void close()
+        throws RemoteException
+    {
+        rProject.close();
+    }
+
+    /**
+     * Request a save of all open files in the project (thread-safe).
+     * @throws ProjectNotOpenException
+     * @throws RemoteException
+     */
+    public void save()
+        throws ProjectNotOpenException, RemoteException
+    {
+        rProject.save();
+    }
+    
+    /**
+     * Returns the default package. This method is thread-safe.
+     */
+    public GPackage getDefaultPackage()
+    {
+        return getPackage("");
+    }
+    
+    /**
+     * Returns the named package. This method is thread-safe.
+     */
+    public GPackage getPackage(String packageName)
+    {
+        try {
+            RPackage rPkg = rProject.getPackage(packageName);
+            if (rPkg == null) {
+                return null;
+            }
+            else {
+                return getPackage(rPkg);
+            }
+        }
+        catch (ProjectNotOpenException pnoe) {
+            Debug.reportError("Error retrieving remote package", pnoe);
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Error retrieving remote package", re);
+        }
+        return null;
+    }
+
+    /**
+     * Get a GPackage wrapper for an RPackage object.
+     * This method is thread-safe.
+     */
+    public GPackage getPackage(RPackage pkg)
+    {
+        synchronized (packagePool) {
+            GPackage ret = packagePool.get(pkg);
+            if (ret == null) {
+                ret = new GPackage(pkg, this);
+                packagePool.put(pkg, ret);
+            }
+            return ret;
+        }
+    }
+
+    public File getDir()
+    {
+        try { 
+            return rProject.getDir();
+        }
+        catch (ProjectNotOpenException pnoe) {
+            Debug.reportError("Couldn't get project directory", pnoe);
+            throw new InternalGreenfootError(pnoe);
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Couldn't get project directory", re);
+            throw new InternalGreenfootError(re);
+        }
+    }
+    
+    /**
+     * Get the project name (the name of the directory containing it).
+     * Thread-safe.
+     */
+    public String getName()
+    {
+        try {
+            return rProject.getName();
+        }
+        catch (ProjectNotOpenException pnoe) {
+            // this exception should never happen
+            Debug.reportError("Getting project name", pnoe);
+        }
+        catch (RemoteException re) {
+            // this should also not happen
+            Debug.reportError("Getting project name", re);
+        }
+        return null;
+    }
+        
+    /**
+     * Retrieve the properties for a package. Loads the properties if necessary.
+     */
+    public ProjectProperties getProjectProperties()
+    {
+        return projectProperties;
+    }
+    
+    /**
+     * Show the readme file for this project in an editor window.
+     */
+    public void openReadme()
+    {
+        try {
+            rProject.openReadmeEditor();
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Opening Readme", re);
+            throw new InternalGreenfootError(re);
+        }
+        catch (ProjectNotOpenException pnoe) {
+            Debug.reportError("Opening Readme", pnoe);
+            throw new InternalGreenfootError(pnoe);
+        }
+    }
+    
+    /**
+     * Get the remote project reference which this GProject wraps.
+     */
+    public RProject getRProject()
+    {
+        return rProject;
+    }
+    
+    /*
+     * @see rmiextension.wrappers.event.RProjectListener#projectClosing()
+     */
+    @Override
+    public void projectClosing()
+    {
+        GreenfootMain.getInstance().projectClosing();
+    }
+    
+    /**
+     * Get the project character set's name
+     */
+    public String getCharsetName()
+    {
+        String charsetName = projectProperties.getString("project.charset");
+        if (charsetName == null) {
+            charsetName = Charset.defaultCharset().name();
+        }
+        return charsetName;
+    }
+    
+    /**
+     * Get the name of the last world class which was instantiated in
+     * this project. May return null. This method is thread-safe.
+     */
+    public String getLastWorldClassName()
+    {
+        return projectProperties.getString("world.lastInstantiated");
+    }
+    
+    /**
+     * Set the name of the last world class which was instantiated in
+     * this project.
+     */
+    public void setLastWorldClassName(String name)
+    {
+        projectProperties.setString("world.lastInstantiated", name);
+    }
+    
+    /**
+     * Checks whether every class in this project is compiled.
+     * Do not call from a remote callback (except for a compilation event callback).
+     * 
+     * @return True is all classes are compiled, false otherwise
+     */
+    public boolean isCompiled()
+    {
+        try {
+            GClass[] classes = getDefaultPackage().getClasses(false);
+            for (int i = 0; i < classes.length; i++) {
+                GClass cls = classes[i];
+                if(!cls.isCompiled())  {
+                    return false;
+                }
+            }
+        }
+        catch (Exception e) {
+            Debug.reportError("Checking class compiled state", e);
+            throw new InternalGreenfootError(e);
+        }
+        return true;
+    }
+    
+    
+    /**
+     * Closes classes in this project
+     */
+    public void closeEditors()
+    {
+        try {
+            GClass[] classes = getDefaultPackage().getClasses(false);
+            for (int i = 0; i < classes.length; i++) {
+                GClass cls = classes[i];
+                cls.closeEditor();
+            }
+        }
+        catch (Exception e) {
+            Debug.reportError("Closing all editors", e);
+        }
+    }
+    
+    public void addCompileListener(CompileListener listener)
+    {
+        synchronized (compileListeners) {
+            compileListeners.add(listener);
+        }
+    }
+    
+    public void removeCompileListener(CompileListener listener)
+    {
+        synchronized (compileListeners) {
+            compileListeners.remove(listener);
+        }
+    }
+    
+    // ----------- CompileListener interface -------------
+    
+    @Override
+    public void compileError(RCompileEvent event)
+    {
+        delegateCompileEvent(event);
+    }
+    
+    @Override
+    public void compileFailed(RCompileEvent event)
+    {
+        reloadClasses();
+        
+        delegateCompileEvent(event);
+    }
+    
+    @Override
+    public void compileStarted(RCompileEvent event)
+    {
+        delegateCompileEvent(event);
+    }
+    
+    @Override
+    public void compileSucceeded(RCompileEvent event)
+    {
+        reloadClasses();
+        
+        delegateCompileEvent(event);
+    }
+    
+    @Override
+    public void compileWarning(RCompileEvent event)
+    {
+        delegateCompileEvent(event);
+    }
+    
+    // ----------- End of CompileListener interface ------
+    
+    /**
+     * Reload all classes. Do not call from a remote callback.
+     * (Note that this is called from compile events, which technically are remote callbacks,
+     *  but they are executed asynchronously).
+     */
+    private void reloadClasses()
+    {
+        GPackage pkg = getDefaultPackage();  
+        GClass[] classes = pkg.getClasses(true);
+        for (GClass cls : classes) {
+            cls.reload();
+        }
+    }
+    
+    private void delegateCompileEvent(RCompileEvent event)
+    {
+        synchronized (compileListeners) {
+            List<CompileListener> listeners = new ArrayList<CompileListener>(compileListeners);
+            Iterator<CompileListener> i = listeners.iterator();
+            while (i.hasNext()) {
+                CompileListener listener = i.next();
+                try {
+                    switch (event.getEvent()) {
+                    case CompileEvent.COMPILE_START_EVENT:
+                        listener.compileStarted(event);
+                        break;
+                    case CompileEvent.COMPILE_DONE_EVENT:
+                        listener.compileSucceeded(event);
+                        break;
+                    case CompileEvent.COMPILE_FAILED_EVENT:
+                        listener.compileFailed(event);
+                        break;
+                    case CompileEvent.COMPILE_ERROR_EVENT:
+                        listener.compileError(event);
+                        break;
+                    case CompileEvent.COMPILE_WARNING_EVENT:
+                        listener.compileWarning(event);
+                        break;
+                    default:
+                    }
+                }
+                catch (RemoteException re) {
+                    Debug.reportError("Determining compilation event type", re);
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the image library for this project. If the directory does not
+     * exist, it is created.
+     */
+    public File getImageDir()
+    {
+        File projDir = getDir().getAbsoluteFile();
+        File projImagesDir = new File(projDir, "images");
+        projImagesDir.mkdir();
+        return projImagesDir;
+    }
+
+    /**
+     * Gets the sound library for this project. If the directory does not
+     * exist, it is created.
+     */
+    public File getSoundDir()
+    {
+        File projDir = getDir().getAbsoluteFile();
+        File projSoundsDir = new File(projDir, "sounds");
+        projSoundsDir.mkdir();
+        return projSoundsDir;
+    }
+
+    /**
+     * Tries to toggle the debugger window to either set it to
+     * visible or not.
+     */
+    public void toggleExecControls()
+    {
+        try {
+            rProject.toggleExecControls();
+        } catch (RemoteException ex) {
+            Debug.reportError("RemoteException showing debugger", ex);
+        }
+    }
+
+    /**
+     * @return Whether or not the debugger window is currently visible.
+     */
+    public boolean isExecControlVisible() 
+    {
+        try {
+            return rProject.isExecControlVisible();
+        } catch (RemoteException ex) {
+            Debug.reportError("RemoteException checking ExecControl state", ex);
+        } catch (ProjectNotOpenException ex) {
+            Debug.reportError("ProjectNotOpenException checking ExecControl state", ex);
+        }
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GreenfootLauncherBlueJVM.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GreenfootLauncherBlueJVM.java
new file mode 100644
index 0000000000000000000000000000000000000000..3789f824551bc6d3c5a53eb78cca3af3e769d86d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GreenfootLauncherBlueJVM.java
@@ -0,0 +1,273 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.gui.FirstStartupDialog;
+import greenfoot.gui.FirstStartupDialog.Result;
+import greenfoot.util.FileChoosers;
+import greenfoot.util.GreenfootUtil;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import rmiextension.RMIExtension;
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.Debug;
+import bluej.utility.FileUtility;
+import bluej.utility.Utility;
+
+/**
+ * This singleton is responsible for starting up Greenfoot from the BlueJ VM.
+ * 
+ * @author Poul Henriksen
+ */
+public class GreenfootLauncherBlueJVM
+{
+    /** Singleton instance */
+    private static GreenfootLauncherBlueJVM instance;
+
+    /** Hook into BlueJ*/
+    private RMIExtension extension;
+
+    /** The project to start up if no other project is opened. */
+    private final static String STARTUP_PROJECT = "greenfoot/startupProject";
+
+    /** The tutorial project. */
+    private final static String TUTORIAL_SCENARIO = "wombats";
+
+    /** The HTML tutorial. Relative to the top level Greenfoot directory. */
+    private static final String TUTORIAL_FILE = "tutorial/tutorial.html";
+
+    /**
+     * Returns the instance of this singleton.
+     */
+    public static GreenfootLauncherBlueJVM getInstance()
+    {
+        if (instance == null) {
+            instance = new GreenfootLauncherBlueJVM();
+        }
+        return instance;
+    }
+
+    /**
+     * Launch greenfoot on the BlueJVM side.
+     * 
+     * @param extension The extension instance
+     */
+    public void launch(RMIExtension extension)
+    {
+        this.extension = extension;
+
+        // First, we check if this is the first run of greenfoot ever for this user
+        if (Utility.firstTimeEver("greenfoot.run")) {
+            handleFirstTime();
+            return;
+        }
+        else {
+            openNormally();
+        }
+    }
+    
+    /**
+     * Displays a dialog to the first time user of Greenfoot.
+     */
+    private void handleFirstTime()
+    {
+        FirstStartupDialog dialog = new FirstStartupDialog();
+        dialog.setLocationRelativeTo(null); // centers dialog
+        dialog.setVisible(true);
+
+        Result result = dialog.getResult();
+        switch(result) {
+            case TUTORIAL :
+                openTutorial();
+                break;
+            case OPEN :
+                openScenario();
+                break;
+            case CREATE :
+                createScenario();
+                break;
+            case WITHOUT :
+                openNormally();
+                break;
+        }
+    }
+    
+
+    /**
+     * Opens the tutorial and the tutorial scenario.
+     */
+    private void openTutorial()
+    {
+        // So that when they can easily open other scenarios once they finish
+        // with the tutorial.
+        setScenariosAsDefaultDir();
+        File scenarioDir = null;
+        try {
+            String scenarioName = Config.getPropString("greenfoot.tutorial.scenario", null);
+            if (scenarioName == null) {
+                scenarioName = TUTORIAL_SCENARIO;
+            }
+            scenarioDir = getScenarioDir(scenarioName);
+        }
+        catch (FileNotFoundException e) {
+            Debug.reportError("Error when attempting to open tutorial scenario on first startup", e);
+        }
+        catch (IOException e) {
+            Debug.reportError("Error when attempting to open tutorial scenario on first startup", e);
+        }
+
+        if (scenarioDir != null) {
+            extension.openProject(scenarioDir);
+        }
+
+        File greenfootDir = null;
+        try {
+            greenfootDir = GreenfootUtil.getGreenfootDir();
+        }
+        catch (IOException e) {
+            Debug.reportError("Error when attempting to open tutorial on first startup", e);
+            return;
+        }
+
+        String alternativeTutorial = Config.getPropString("greenfoot.tutorial", null);
+
+        if (alternativeTutorial == null) {
+            File tutorial = new File(greenfootDir, TUTORIAL_FILE);
+            if (tutorial.canRead()) {
+                Utility.openWebBrowser(tutorial);
+            }
+            else {
+                Debug.reportError("Error when attempting to open tutorial on first startup", new IOException());
+            }
+        }
+        else {
+            try {
+                URL tutorial = new URL(alternativeTutorial);
+                Utility.openWebBrowser(tutorial);
+            }
+            catch (MalformedURLException e) {
+                Debug.reportError("Error when trying to open tutorial in alternative location: " + alternativeTutorial,
+                        e);
+            }
+        }
+    }
+
+    /**
+     * Opens a new scenario selected by the user. 
+     */
+    private void openScenario()
+    {
+        setScenariosAsDefaultDir();
+        File scenario = FileChoosers.getScenario(null);
+        if (scenario != null) {
+            extension.openProject(scenario);
+        }
+        else {
+            // User didn't choose a scenario, lets exit.
+            System.exit(0);
+        }
+    }
+
+    /**
+     * Lets the user create a new scenario.
+     */    
+    private void createScenario()
+    {
+        File newDir = FileUtility.getDirName(null, "New Scenario", Config.getString("pkgmgr.newPkg.buttonLabel"), false, true);
+        extension.newProject(newDir);
+    }
+
+    /**
+     * Starts up Greenfoot by either letting BlueJ launch previously opened
+     * scenarios or opening the empty startup project.
+     */
+    public void openNormally()
+    {
+        // If no project is open now, we might want to open the startup project
+        File blueJLibDir = Config.getBlueJLibDir();
+        File startupProject = new File(blueJLibDir, STARTUP_PROJECT);
+        extension.maybeOpenProject(startupProject);
+    }
+    
+    /**
+     * Sets the directory containing the scenarios to be the directory that the
+     * file browser will open up in.
+     */
+    private void setScenariosAsDefaultDir()
+    {
+        // Attempt to set scenarios dir as default.
+        try {
+            File startupDir = getScenariosDir();
+            PrefMgr.setProjectDirectory(startupDir.getAbsolutePath());
+        }
+        catch (IOException e) {
+            // Not a problem, we use default dir
+        }
+    }
+    
+    /**
+     * Returns the location of the scenarios.
+     * 
+     * @throws IOException If it can't read the Greenfoot directory.
+     */
+    private File getScenariosDir()
+        throws IOException
+    {
+        // The scenarios might be in a different location.
+        // This is useful when running greenfoot from an IDE.
+        String alternativeScenarios = Config.getPropString("greenfoot.scenarios", null);
+        if (alternativeScenarios == null) {
+            File greenfootDir = GreenfootUtil.getGreenfootDir();
+            return new File(greenfootDir, "scenarios");
+        }
+        else {
+            return new File(alternativeScenarios);
+        }
+    }
+
+    /**
+     * Try to find the specific scenario in the Greenfoot scenario dir.
+     * 
+     * @throws FileNotFoundException If it could not find the scenario.
+     * @throws IOException If it can't read the Greenfoot dir.
+     */
+    private File getScenarioDir(String scenario)
+        throws FileNotFoundException, IOException
+    {
+        File scenariosDir = getScenariosDir();
+        File specificScenarioDir = new File(scenariosDir, scenario);
+        if (specificScenarioDir.isDirectory()) {
+            return specificScenarioDir;
+        }
+        else {
+            throw new FileNotFoundException("Scenario not found: " + scenario + ". Tried to find it at: "
+                    + specificScenarioDir);
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GreenfootLauncherDebugVM.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GreenfootLauncherDebugVM.java
new file mode 100644
index 0000000000000000000000000000000000000000..6aa227431161ecc84eb64f175d6906e1381a4c25
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GreenfootLauncherDebugVM.java
@@ -0,0 +1,130 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.platforms.ide.GreenfootUtilDelegateIDE;
+import greenfoot.util.GreenfootUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Writer;
+import java.rmi.RemoteException;
+
+import rmiextension.BlueJRMIClient;
+import rmiextension.wrappers.RBlueJ;
+import rmiextension.wrappers.RPrintStream;
+import bluej.Config;
+import bluej.utility.Debug;
+
+/**
+ * An object of GreenfootLauncherDebugVM is the first object that is created in the
+ * Debug-VM. The launcher object is created from the BlueJ-VM in the Debug-VM.
+ * When a new object of the launcher is created, the constructor looks up the
+ * BlueJService in the RMI registry and starts the initialisation of Greenfoot.
+ * 
+ * @author Poul Henriksen
+ */
+public class GreenfootLauncherDebugVM
+{
+    private static GreenfootLauncherDebugVM instance;
+    
+    @SuppressWarnings("unused")
+    private Object transportField;
+    
+    /**
+     * Constructor for the Greenfoot Launcher. This connects to the RMI service on the
+     * primary VM, and starts the Greenfoot UI.
+     * 
+     * @param prjDir         The project directory
+     * @param rmiServiceName  The name of the RMI service to connect to
+     */
+    public GreenfootLauncherDebugVM(String prjDir, String rmiServiceName)
+    {
+        instance = this;
+        if (BlueJRMIClient.instance() != null) {
+            // Already launched.
+            return;
+        }
+        
+        final BlueJRMIClient client = new BlueJRMIClient(prjDir, rmiServiceName);
+        
+        final RBlueJ blueJ = client.getBlueJ();
+        if (blueJ == null) {
+            System.exit(1);
+        }
+        
+        // This constructor is called on BlueJ's "server" thread, so we do the rest in
+        // another thread to avoid holding the server thread lock:
+        new Thread() {
+            public void run() {
+                try {           
+                    client.initialise();
+                    File libdir = blueJ.getSystemLibDir();
+                    Config.initializeVMside(libdir, blueJ.getInitialCommandLineProperties(), true, client);
+                    final RPrintStream rprintStream = blueJ.getDebugPrinter();
+                    Debug.setDebugStream(new Writer() {
+                        @Override
+                        public void write(char[] cbuf, int off, int len)
+                                throws IOException
+                        {
+                            String s = new String(cbuf, off, len);
+                            rprintStream.print(s);
+                        }
+                        
+                        @Override
+                        public void flush() throws IOException
+                        {
+                        }
+                        
+                        @Override
+                        public void close() throws IOException
+                        {
+                        }
+                    });
+                    
+                    GreenfootUtil.initialise(GreenfootUtilDelegateIDE.getInstance());
+                    GreenfootMain.initialize(blueJ, client.getPackage());
+                }
+                catch (RemoteException re) {
+                    re.printStackTrace();
+                }
+            };
+        }.start();
+    }
+    
+    /**
+     * Get the GreenfootLauncherDebugVM instance.
+     */
+    public static GreenfootLauncherDebugVM getInstance()
+    {
+        return instance;
+    }
+    
+    /**
+     * Set the transport field to some object. It is then possible to obtain a remote
+     * reference to the object, via RProject.getRemoteObject().
+     */
+    public void setTransportField(Object transportField)
+    {
+        this.transportField = transportField;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GreenfootMain.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GreenfootMain.java
new file mode 100644
index 0000000000000000000000000000000000000000..08a6ea3275096457d37feac46a7e33f809f648ea
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/GreenfootMain.java
@@ -0,0 +1,827 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.ObjectTracker;
+import greenfoot.event.ActorInstantiationListener;
+import greenfoot.event.CompileListener;
+import greenfoot.event.CompileListenerForwarder;
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.MessageDialog;
+import greenfoot.importer.scratch.ScratchImport;
+import greenfoot.platforms.ide.ActorDelegateIDE;
+import greenfoot.util.FileChoosers;
+import greenfoot.util.Version;
+
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Point;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.lang.reflect.Field;
+import java.rmi.RemoteException;
+import java.rmi.ServerError;
+import java.rmi.ServerException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+
+import rmiextension.wrappers.RBlueJ;
+import rmiextension.wrappers.RClass;
+import rmiextension.wrappers.RPackage;
+import rmiextension.wrappers.RProject;
+import rmiextension.wrappers.event.RCompileEvent;
+import rmiextension.wrappers.event.RInvocationListener;
+import rmiextension.wrappers.event.RProjectListener;
+import bluej.Config;
+import bluej.debugmgr.CallHistory;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.pkgmgr.GreenfootProjectFile;
+import bluej.pkgmgr.Project;
+import bluej.runtime.ExecServer;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.FileUtility;
+import bluej.utility.Utility;
+import bluej.views.View;
+
+/**
+ * The main class for greenfoot. This is a singelton (in the JVM). Since each
+ * project is opened in its own JVM there can be several Greenfoot instances,
+ * but each will be in its own JVM so it is effectively a singleton.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: GreenfootMain.java 9926 2012-09-24 15:01:52Z davmac $
+ */
+public class GreenfootMain extends Thread implements CompileListener, RProjectListener
+{
+    /* Constants for return from updateApi method */
+    /** The project API version matches the greenfoot API version */
+    public static final int VERSION_OK = 0;
+    /** The project API version was different, and has been updated */
+    public static final int VERSION_UPDATED = 1;
+    /** The project was not a greenfoot project, or the user chose to cancel the open */
+    public static final int VERSION_BAD = 2;
+
+    /** Version of the API for this Greenfoot release. */
+    private static Version version = null;
+
+    /** Greenfoot is a singleton - this is the instance. */
+    private static GreenfootMain instance;
+
+    /** The connection to BlueJ via RMI */
+    private RBlueJ rBlueJ;
+
+    /** The main frame of greenfoot. */
+    private GreenfootFrame frame;
+
+    /** The project this Greenfoot singelton refers to. */
+    private GProject project;
+
+    /** The package this Greenfoot singelton refers to. */
+    private GPackage pkg;
+
+    /** The path to the dummy startup project */
+    private File startupProject;
+
+    /**
+     * Forwards compile events to all the compileListeners that has registered
+     * to reccieve compile events.
+     */
+    private CompileListenerForwarder compileListenerForwarder;
+    private List<CompileListener> compileListeners = new LinkedList<CompileListener>();
+
+    /** The class state manager notifies GClass objects when their compilation state changes */
+    private ClassStateManager classStateManager;
+
+    /** Listens for instantiations of Actor objects. */
+    private ActorInstantiationListener instantiationListener;
+
+    /** List of invocation listeners that has been registered. */
+    private List<RInvocationListener> invocationListeners = new ArrayList<RInvocationListener>();
+
+    /** History of parameters passed to methods. */
+    private CallHistory callHistory = new CallHistory();
+
+    /** Filter that matches class files */
+    private static FilenameFilter classFilter = new FilenameFilter() {
+        public boolean accept(File dir, String name)
+        {
+            return name.toLowerCase().endsWith(".class");
+        }
+    };
+
+    private ClassLoader currentLoader;
+
+    // ----------- static methods ------------
+
+    /**
+     * Initializes the singleton. This can only be done once - subsequent calls
+     * will have no effect.
+     */
+    public static void initialize(RBlueJ rBlueJ, RPackage pkg)
+    {
+        System.setProperty("apple.laf.useScreenMenuBar", "true");
+        if (instance == null) {
+            try {
+                instance = new GreenfootMain(rBlueJ, pkg.getProject());
+            }
+            catch (ProjectNotOpenException pnoe) {
+                // can't happen
+                Debug.reportError("Getting remote project", pnoe);
+            }
+            catch (RemoteException re) {
+                // shouldn't happen
+                Debug.reportError("Getting remote project", re);
+            }
+        }
+    }
+
+    /**
+     * Gets the singleton.
+     */
+    public static GreenfootMain getInstance()
+    {
+        return instance;
+    }
+
+    // ----------- instance methods ------------
+
+    /**
+     * Contructor is private. This class is initialised via the 'initialize'
+     * method (above).
+     */
+    private GreenfootMain(final RBlueJ rBlueJ, final RProject proj)
+    {
+        instance = this;
+        this.rBlueJ = rBlueJ;
+        currentLoader = ExecServer.getCurrentClassLoader();
+        addCompileListener(this);
+        try {
+            // determine the path of the startup project
+            File startupProj = rBlueJ.getSystemLibDir();
+            startupProj = new File(startupProj, "greenfoot");
+            startupProject = new File(startupProj, "startupProject");
+
+            this.project = GProject.newGProject(proj);
+            addCompileListener(project);
+            this.pkg = project.getDefaultPackage();
+            ActorDelegateIDE.setupAsActorDelegate(project);
+
+            EventQueue.invokeLater(new Runnable() {
+                public void run() {
+                    if (!isStartupProject()) {
+                        try {
+                            classStateManager = new ClassStateManager(project);
+                        } catch (RemoteException exc) {
+                            Debug.reportError("Error when opening scenario", exc);
+                        }
+                    }
+                    
+                    frame = GreenfootFrame.getGreenfootFrame(rBlueJ, classStateManager);
+
+                    // Config is initialized in GreenfootLauncherDebugVM
+
+                    if (!isStartupProject()) {
+                        try {
+                            instantiationListener = new ActorInstantiationListener(WorldHandler.getInstance());
+
+                            frame.openProject(project);
+                            // bringToFront is done automatically by BlueJ
+                            // Utility.bringToFront(frame);
+
+                            compileListenerForwarder = new CompileListenerForwarder(compileListeners);
+                            GreenfootMain.this.rBlueJ.addCompileListener(compileListenerForwarder, pkg.getProject().getDir());
+
+                            
+                            rBlueJ.addClassListener(classStateManager);
+                        }
+                        catch (Exception exc) {
+                            Debug.reportError("Error when opening scenario", exc);
+                        }
+                    }
+                    
+                    frame.setVisible(true);
+                    Utility.bringToFront(frame);
+                }
+            });
+        }
+        catch (Exception exc) {
+            Debug.reportError("could not create greenfoot main", exc);
+        }
+    }
+
+    /**
+     * Check whether this instance of greenfoot is running the dummy
+     * startup project.
+     * @return true if this is the startup project
+     */
+    private boolean isStartupProject()
+    {
+        return project.getDir().equals(startupProject);
+    }
+
+    /**
+     * Opens the project in the given directory. The project launches in a
+     * new VM.
+     */
+    public void openProject(String projectDir)
+        throws RemoteException
+    {
+        File projectDirFile = new File(projectDir);
+
+        // Display msg dialog of project does not exist.
+        if (!projectDirFile.exists()) {
+            JOptionPane.showMessageDialog(frame, 
+                    Config.getString("noproject.dialog.msg") + System.getProperty("line.separator") + projectDir,
+                    Config.getString("noproject.dialog.title"), JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+
+        // It's possible that the user re-opened a project which they previously closed,
+        // resulting in an empty frame (because no other open projects). In that case the
+        // project is actually still running, behind the scenes; so just re-display it.
+        if (project.getDir().equals(projectDirFile)) {
+            frame.openProject(project);
+            return;
+        }
+        
+        // Used for some imports:
+        boolean autoIndentAllFiles = false;
+
+        if (!projectDirFile.isDirectory() && !Project.isProject(projectDirFile.toString())) {
+            if (projectDirFile.getName().endsWith(".sb")) {
+                projectDirFile = ScratchImport.convert(projectDirFile);
+                autoIndentAllFiles = true;
+            } else {
+                projectDirFile = Utility.maybeExtractArchive(projectDirFile, frame);
+                if (projectDirFile == null) {
+                    return;
+                }
+                if (! GreenfootProjectFile.exists(projectDirFile)) {
+                    // Archive doesn't appear to be a Greenfoot project
+                    DialogManager.showError(frame, "archive-not-greenfoot-project");
+                    FileUtility.deleteDir(projectDirFile);
+                    return;
+                }
+            }
+        }
+                
+        int versionStatus = GreenfootMain.updateApi(projectDirFile, frame, getAPIVersion().toString());
+        boolean doOpen = versionStatus != VERSION_BAD;
+        if (doOpen) {
+            RProject proj = rBlueJ.openProject(projectDirFile);
+
+            if (autoIndentAllFiles) {
+                try {
+                    for (RPackage pkg : proj.getPackages()) {
+                        for (RClass cls : pkg.getRClasses()) {
+                            cls.autoIndent();
+                        }
+                    }
+                // If there any problems, never mind about it:
+                } catch(ProjectNotOpenException e) { }
+                catch (PackageNotFoundException e) { }
+            }
+
+            // if this is the dummy startup project and there is a valid project to open, close it now
+            if (proj != null && frame.getProject() == null) {
+                project.close();
+            }
+        }
+    }
+
+    /**
+     * Opens a file browser to find a greenfoot project
+     */
+    public void openProjectBrowser()
+    {
+        File dirName = FileChoosers.getScenario(frame);
+
+        if (dirName != null) {
+            try {
+                openProject(dirName.getAbsolutePath());
+            }
+            catch (Exception exc) {
+                Debug.reportError("Could not open scenario", exc);
+            }
+        }
+    }
+
+    /**
+     * Get the project for this greenfoot instance.
+     * @return
+     */
+    public GProject getProject()
+    {
+        return project;
+    }
+
+    /**
+     * Closes this greenfoot frame, or handle it closing.
+     * 
+     * <p>If this is called with the windowClosing parameter false, and there is only one project open,
+     * then the frame won't be closed but will instead be turned into an empty frame.
+     */
+    private void closeThisInstance(boolean windowClosing)
+    {
+        try {
+            if (rBlueJ.getOpenProjects().length <= 1) {
+                if (windowClosing) {
+                    // This happens to be the only way the startup project can be closed
+                    rBlueJ.exit();
+                } else {
+                    frame.closeProject();
+                }
+            } else {
+                project.close();
+            }
+        } catch (RemoteException re) {
+            Debug.reportError("Error while closing", re);
+        }
+    }
+
+    /**
+     * Close the project in the given frame. This will also close the frame, or (if
+     * the windowClosing parameter is false, and no other projects are open) make it
+     * empty.
+     */
+    public static void closeProject(GreenfootFrame frame, boolean windowClosing)
+    {
+        instance.closeThisInstance(windowClosing);
+    }
+
+    /*
+     * @see rmiextension.wrappers.event.RProjectListener#projectClosing()
+     */
+    public void projectClosing()
+    {
+        try {
+            if (!isStartupProject()) {
+                rBlueJ.removeCompileListener(compileListenerForwarder);
+                rBlueJ.removeClassListener(classStateManager);
+                storeFrameState();
+                for (RInvocationListener element : invocationListeners) {
+                    rBlueJ.removeInvocationListener(element);
+                }
+            }
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Closing project", re);
+        }
+    }
+
+    /**
+     * Close all open Greenfoot project instances, i.e. exit the application.
+     */
+    public static void closeAll()
+    {
+        try {
+            getInstance().rBlueJ.exit();
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Closing all projects", re);
+        }
+    }
+
+    /**
+     * Store the current main window size to the project properties.
+     */
+    private void storeFrameState()
+    {
+        ProjectProperties projectProperties = project.getProjectProperties();
+
+        projectProperties.setInt("mainWindow.width", frame.getWidth());
+        projectProperties.setInt("mainWindow.height", frame.getHeight());
+        Point loc = frame.getLocation();
+        projectProperties.setInt("mainWindow.x", loc.x);
+        projectProperties.setInt("mainWindow.y", loc.y);
+
+        projectProperties.save();
+    }
+
+    /**
+     * Adds a listener for compile events
+     * 
+     * @param listener
+     */
+    private void addCompileListener(CompileListener listener)
+    {
+        synchronized (compileListeners) {
+            compileListeners.add(0, listener);
+        }
+    }
+
+    /**
+     * Adds a listener for invocation events
+     * 
+     * @param listener
+     */
+    public void addInvocationListener(RInvocationListener listener)
+        throws RemoteException
+    {
+        invocationListeners.add(listener);
+        rBlueJ.addInvocationListener(listener);
+    }
+
+    /**
+     * Creates a new project
+     */
+    public RProject newProject()
+    {
+        File newFile = FileUtility.getDirName(frame,
+                Config.getString("greenfoot.utilDelegate.newScenario"),
+                Config.getString("pkgmgr.newPkg.buttonLabel"),
+                false, true);
+        if (newFile != null) {
+            if (newFile.exists()) {
+                DialogManager.showError(frame, "project-already-exists");
+                return null;
+            }
+            try {
+                RProject rproj = rBlueJ.newProject(newFile);
+                if (rproj != null) {
+                    // The rest of the project preparation will be done by the
+                    // ProjectManager on the BlueJ VM.
+
+                    // if the project that is already open is the dummy startup project
+                    // or if there is an empty project, close it now
+                    if (isStartupProject()|| frame.isClosedProject()) {
+                        project.close();
+                    }
+                    
+                    return rproj;
+                }
+                else {
+                    DialogManager.showError(frame, "cannot-create-project");
+                }
+            }
+            catch (ServerError se) {
+                Debug.reportError("Problems when trying to create new scenario", se);
+            }
+            catch (ServerException se) {
+                Debug.reportError("Problems when trying to create new scenario", se);
+            }
+            catch (RemoteException re) {
+                Debug.reportError("Problems when trying to create new scenario", re);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get a reference to the CallHistory instance.
+     */
+    public CallHistory getCallHistory()
+    {
+        return callHistory;
+    }
+
+    /**
+     * Get a reference to the invocation listener.
+     */
+    public ActorInstantiationListener getInvocationListener()
+    {
+        return instantiationListener;
+    }
+
+    /**
+     * Get a reference to the greenfoot frame.
+     */
+    public GreenfootFrame getFrame()
+    {
+        return frame;
+    }
+
+    /**
+     * Makes a project a greenfoot project. It cleans up the project directory
+     * and makes sure everything that needs to be there is there.
+     * 
+     * @param deleteClassFiles whether the class files in the destination should
+     *            be deleted. If true, they will be deleted and appear as
+     *            needing a recompile in the Greenfoot class browser.
+     */
+    private static void prepareGreenfootProject(File greenfootLibDir, File projectDir,
+            ProjectProperties p, boolean deleteClassFiles, String greenfootApiVersion)
+    {
+        if (isStartupProject(greenfootLibDir, projectDir)) {
+            return;
+        }
+        File dst = projectDir;
+
+        File greenfootDir = new File(dst, "greenfoot");
+        
+        // Since Greenfoot 1.5.2 we no longer require the greenfoot directory,
+        // so we delete everything that we might have had in there previously,
+        // and delete the dir if it is empty after that.
+        deleteGreenfootDir(greenfootDir);        
+        
+        if(deleteClassFiles) {
+            deleteAllClassFiles(dst);
+        }
+        
+        // Since Greenfoot 1.3.0 we no longer use the bluej.pkg file, so if it
+        // exists it should now be deleted.
+        try {
+            File pkgFile = new File(dst, "bluej.pkg");
+            if (pkgFile.exists()) {
+                pkgFile.delete();
+            }   
+            File pkhFile = new File(dst, "bluej.pkh");
+            if (pkhFile.exists()) {
+                pkhFile.delete();
+            }
+        }
+        catch (SecurityException e) {
+            // If we don't have permission to delete, just leave them there.
+        }   
+        
+        try {
+            File images = new File(dst, "images");
+            images.mkdir();
+            File sounds = new File(dst, "sounds");
+            sounds.mkdir();
+        }
+        catch (SecurityException e) {
+            Debug.reportError("SecurityException when trying to create images/sounds directories", e);
+        }   
+        
+        p.setApiVersion(greenfootApiVersion);
+        p.save();
+    }
+
+    private static void deleteGreenfootDir(File greenfootDir) 
+    {
+        if (greenfootDir.exists()) {
+            try {
+                File actorJava = new File(greenfootDir, "Actor.java");
+                if (actorJava.exists()) {
+                    actorJava.delete();
+                }
+            } catch (SecurityException e) {
+                // If we don't have permission to delete, just leave them there.
+            }
+            try {
+                File worldJava = new File(greenfootDir, "World.java");
+                if (worldJava.exists()) {
+                    worldJava.delete();
+                }
+            } catch (SecurityException e) {
+                // If we don't have permission to delete, just leave them there.
+            }
+            try {
+                File actorJava = new File(greenfootDir, "Actor.class");
+                if (actorJava.exists()) {
+                    actorJava.delete();
+                }
+            } catch (SecurityException e) {
+                // If we don't have permission to delete, just leave them there.
+            }
+            try {
+                File worldJava = new File(greenfootDir, "World.class");
+                if (worldJava.exists()) {
+                    worldJava.delete();
+                }
+            } catch (SecurityException e) {
+                // If we don't have permission to delete, just leave them there.
+            }
+            try {
+                File worldJava = new File(greenfootDir, "project.greenfoot");
+                if (worldJava.exists()) {
+                    worldJava.delete();
+                }
+            } catch (SecurityException e) {
+                // If we don't have permission to delete, just leave them there.
+            }
+            try {
+                greenfootDir.delete();
+            } catch (SecurityException e) {
+                // If we don't have permission to delete, just leave them there.
+            }
+        }
+    }
+
+    /**
+     * Checks whether the API version this project was created with is
+     * compatible with the current API version. If it is not, it will attempt to
+     * update the project to the current version of the API and present the user
+     * with a dialog with instructions on what to do if there are changes in API
+     * version that requires manual modifications of the API.
+     * <p>
+     * If is considered safe to open this project with the current API version
+     * the method will return true.
+     * 
+     * @param project The project in question.
+     * @param parent Frame that should be used to place dialogs.
+     * @return One of VERSION_OK, VERSION_UPDATED or VERSION_BAD
+     */
+    public static int updateApi(File projectDir, Frame parent, String greenfootApiVersion)
+    {
+        File greenfootLibDir = Config.getGreenfootLibDir();
+        ProjectProperties newProperties = new ProjectProperties(projectDir);
+        Version projectVersion = newProperties.getAPIVersion();
+
+        Version apiVersion = GreenfootMain.getAPIVersion();
+
+        if (projectVersion.isBad()) {
+            String message = projectVersion.getBadMessage();
+            JButton continueButton = new JButton(Config.getString("greenfoot.continue"));
+            MessageDialog dialog = new MessageDialog(parent, message, Config.getString("project.version.mismatch"), 50,
+                    new JButton[]{continueButton});
+            dialog.displayModal();
+            Debug.message("Bad version number in project: " + greenfootLibDir);
+            GreenfootMain.prepareGreenfootProject(greenfootLibDir, projectDir,
+                    newProperties, true, greenfootApiVersion);
+            return VERSION_UPDATED;
+        }
+        else if (projectVersion.isOlderAndBreaking(apiVersion)) {
+            String message = projectVersion.getChangesMessage(apiVersion);
+            JButton continueButton = new JButton(Config.getString("greenfoot.continue"));
+            MessageDialog dialog = new MessageDialog(parent, message, Config.getString("project.version.mismatch"), 80,
+                    new JButton[]{continueButton});
+            dialog.displayModal();
+            GreenfootMain.prepareGreenfootProject(greenfootLibDir, projectDir,
+                    newProperties, true, greenfootApiVersion);
+
+            return VERSION_UPDATED;
+        }
+        else if (apiVersion.isOlderAndBreaking(projectVersion)) {
+            String message = projectVersion.getNewerMessage();
+
+            JButton cancelButton = new JButton(Config.getString("greenfoot.cancel"));
+            JButton continueButton = new JButton(Config.getString("greenfoot.continue"));
+            MessageDialog dialog = new MessageDialog(parent, message, Config.getString("project.version.mismatch"), 50,
+                    new JButton[]{continueButton, cancelButton});
+            JButton pressed = dialog.displayModal();
+
+            if (pressed == cancelButton) {
+                return VERSION_BAD;
+            }
+            else {
+                prepareGreenfootProject(greenfootLibDir, projectDir,
+                        newProperties, true, greenfootApiVersion);
+                return VERSION_UPDATED;
+            }
+        }
+        else if (projectVersion.isNonBreaking(apiVersion) ) {
+            prepareGreenfootProject(greenfootLibDir, projectDir,
+                    newProperties, true, greenfootApiVersion);
+            return VERSION_UPDATED;
+        }
+        else if (projectVersion.isInternal(apiVersion)) {
+            prepareGreenfootProject(greenfootLibDir, projectDir,
+                    newProperties, false, greenfootApiVersion);
+            return VERSION_UPDATED;
+        }
+        else {       
+            prepareGreenfootProject(greenfootLibDir, projectDir,
+                    newProperties, false, greenfootApiVersion);
+            return VERSION_OK;            
+        }
+    }
+
+    /**
+     * Deletes all class files in the directory, including the greenfoot subdirectory,
+     * only if they have a .java file related to them.
+     */
+    public static void deleteAllClassFiles(File dir)
+    {
+        String[] classFiles = dir.list(classFilter);
+        if(classFiles == null) return;
+
+        for (int i = 0; i < classFiles.length; i++) {
+            String fileName = classFiles[i];
+            int index = fileName.lastIndexOf('.');
+            String javaFileName = fileName.substring(0, index) + ".java";
+            File file = new File(dir, fileName);
+            File javaFile = new File(dir, javaFileName);
+            if (javaFile.exists()) {
+                file.delete();
+            }
+        }
+    }
+
+    /**
+     * Checks if the project is the default startup project that is used when no
+     * other project is open. It is necessary to have this dummy project,
+     * becuase we must have a project in order to launch the DebugVM.
+     * 
+     */
+    public static boolean isStartupProject(File blueJLibDir, File projectDir)
+    {
+        File startupProject = new File(blueJLibDir, "startupProject");
+        if (startupProject.equals(projectDir)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Gets the version number of the Greenfoot API for this Greenfoot release.
+     */
+    public static Version getAPIVersion()
+    {
+        if (version == null) {
+            try {
+                Class<?> bootCls = Class.forName("bluej.Boot");
+                Field field = bootCls.getField("GREENFOOT_API_VERSION");
+                String versionStr = (String) field.get(null);
+                version = new Version(versionStr);
+            }
+            catch (ClassNotFoundException e) {
+                Debug.reportError("Could not get Greenfoot API version", e);
+                throw new InternalGreenfootError(e);
+            }
+            catch (SecurityException e) {
+                Debug.reportError("Could not get Greenfoot API version", e);
+                throw new InternalGreenfootError(e);
+            }
+            catch (NoSuchFieldException e) {
+                Debug.reportError("Could not get Greenfoot API version", e);
+                throw new InternalGreenfootError(e);
+            }
+            catch (IllegalArgumentException e) {
+                Debug.reportError("Could not get Greenfoot API version", e);
+                throw new InternalGreenfootError(e);
+            }
+            catch (IllegalAccessException e) {
+                Debug.reportError("Could not get Greenfoot API version", e);
+                throw new InternalGreenfootError(e);
+            }
+        }
+
+        return version;
+    }
+
+    /**
+     * See if there is a new class loader in place. If so, we want to
+     * clear all views (BlueJ views) which refer to classes loaded by the previous
+     * loader.
+     */
+    private void checkClassLoader()
+    {
+        ClassLoader newLoader = ExecServer.getCurrentClassLoader();
+        if (newLoader != currentLoader) {
+            View.removeAll(currentLoader);
+            currentLoader = newLoader;
+            ObjectTracker.clearRObjectCache();
+        }
+    }
+
+    // ------------ CompileListener interface -------------
+
+    public void compileStarted(RCompileEvent event)
+    {
+        checkClassLoader();
+    }
+
+    public void compileSucceeded(RCompileEvent event)
+    {
+        checkClassLoader();
+
+    }
+
+    public void compileFailed(RCompileEvent event)
+    {
+        checkClassLoader();
+    }
+
+    public void compileError(RCompileEvent event) {}
+
+    public void compileWarning(RCompileEvent event){}
+
+    public void showPreferences()
+    {
+        try {
+            rBlueJ.showPreferences();
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Problem showing preferences dialog", e);
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ImageCache.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ImageCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ec9c168ef7183c33d878e1e89ca77807f1373a8
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ImageCache.java
@@ -0,0 +1,157 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.GreenfootImage;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An image cache, which uses soft references to avoid holding images when heap space becomes exhausted.
+ * 
+ * @author Davin McCall
+ */
+public class ImageCache
+{
+    private static ImageCache instance = new ImageCache();
+    
+    /** A soft reference to a cached image */
+    private class CachedImageRef extends SoftReference<GreenfootImage>
+    {
+        String imgName;
+        
+        public CachedImageRef(String imgName, GreenfootImage image, ReferenceQueue<GreenfootImage> queue)
+        {
+            super(image, queue);
+            this.imgName = imgName;
+        }
+    }
+    
+    private Map<String,CachedImageRef> imageCache = new HashMap<String,CachedImageRef>();
+    private ReferenceQueue<GreenfootImage> imgCacheRefQueue = new ReferenceQueue<GreenfootImage>();
+    
+    /**
+     * Retrieve the image cache instance.
+     */
+    public static ImageCache getInstance()
+    {
+        return instance;
+    }
+
+    /**
+     * Requests that an image with associated name be added into the cache. The image may be null,
+     * in which case the null response will be cached. Thread-safe.
+     * 
+     * @return  whether the image was cached.
+     */
+    public boolean addCachedImage(String fileName, GreenfootImage image) 
+    {
+        synchronized (imageCache) {
+            if (image != null) {
+                CachedImageRef cr = new CachedImageRef(fileName, image, imgCacheRefQueue);
+                imageCache.put(fileName, cr);
+            }
+            else {
+                imageCache.put(fileName, null);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Gets the cached image of the requested fileName. Thread-safe.
+     *
+     * @param name   name of the image file
+     * @return The cached image (should not be modified), or null if the image
+     *         is not cached.
+     */
+    public GreenfootImage getCachedImage(String fileName)
+    { 
+        synchronized (imageCache) {
+            flushImgCacheRefQueue();
+            CachedImageRef sr = imageCache.get(fileName);
+            if (sr != null) {
+                return sr.get();
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Remove the cached version of an image for a particular class. This should be
+     * called when the image for the class is changed. Thread-safe.
+     */
+    public void removeCachedImage(String fileName)
+    {
+        synchronized (imageCache) {
+            CachedImageRef cr = imageCache.remove(fileName);
+            if (cr != null) {
+                cr.clear();
+            }
+        }
+    }
+
+    /**
+     * Returns true if the fileName exists in the map and the image is cached as being null; 
+     * returns false if it exists and is not null or if it does not exist in the map
+     */
+    public boolean isNullCachedImage(String fileName)
+    {
+        synchronized (imageCache) {
+            return imageCache.containsKey(fileName) && imageCache.get(fileName) == null;
+        }
+    }
+
+    /**
+     * Clear the image cache.
+     */
+    public void clearImageCache()
+    {
+        synchronized (imageCache) {
+            imageCache.clear();
+            imgCacheRefQueue = new ReferenceQueue<GreenfootImage>();
+        }
+    }
+
+    /**
+     * Flush the image cache reference queue.
+     * <p>
+     * Because the images are cached via soft references, the references may be cleared, but the
+     * key will still map to the (cleared) reference. Calling this method occasionally removes such
+     * dead keys.
+     */
+    private void flushImgCacheRefQueue()
+    {
+        Reference<? extends GreenfootImage> ref = imgCacheRefQueue.poll();
+        while (ref != null) {
+            if (ref instanceof CachedImageRef) {
+                CachedImageRef cr = (CachedImageRef) ref;
+                imageCache.remove(cr.imgName);
+            }
+            ref = imgCacheRefQueue.poll();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/InternalGreenfootError.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/InternalGreenfootError.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae56b572c2e805a8a8603a881ea5a3e23561c717
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/InternalGreenfootError.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+/**
+ * An error for internal greenfoot problems that shouldn't happen,
+ * such as remote exceptions.
+ * 
+ * @author Davin McCall
+ */
+public class InternalGreenfootError extends Error
+{
+    public InternalGreenfootError()
+    {
+        
+    }
+    
+    public InternalGreenfootError(Throwable cause)
+    {
+        super(cause);
+    }
+    
+    public InternalGreenfootError(String message, Throwable cause)
+    {
+        super(message, cause);
+    }
+    
+    public InternalGreenfootError(String message)
+    {
+        super(message);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/LocalCompileObserverWrapper.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/LocalCompileObserverWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..57f1a8552ceab8b5bc0942d4c43c2994b97e16d4
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/LocalCompileObserverWrapper.java
@@ -0,0 +1,63 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import java.io.File;
+import java.rmi.RemoteException;
+
+import rmiextension.wrappers.RCompileObserver;
+import bluej.compiler.CompileObserver;
+import bluej.compiler.Diagnostic;
+
+/**
+ * Wraps a local compile as a remote compile observer.
+ * 
+ * @author Davin McCall
+ */
+public class LocalCompileObserverWrapper extends java.rmi.server.UnicastRemoteObject
+        implements RCompileObserver
+{
+    private CompileObserver observer;
+    
+    public LocalCompileObserverWrapper(CompileObserver observer) throws RemoteException
+    {
+        this.observer = observer;
+    }
+    
+    @Override
+    public void startCompile(File[] sources)
+    {
+        observer.startCompile(sources);
+    }
+    
+    @Override
+    public void endCompile(File[] sources, boolean succesful)
+    {
+        observer.endCompile(sources, succesful);
+    }
+    
+    @Override
+    public void compilerMessage(Diagnostic diagnostic) throws RemoteException
+    {
+        observer.compilerMessage(diagnostic);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ObjectDragProxy.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ObjectDragProxy.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e28f8d3cc9833edd9ee597e7c173b3396d75fc7
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ObjectDragProxy.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.GreenfootImage;
+import greenfoot.Actor;
+
+import javax.swing.Action;
+
+/**
+ * This object is used when dragging greenfoot objects around. Because we do not
+ * want objects ot be constructed until they are actually added into the world,
+ * we need a temporary object to be dragged around , which represents the real
+ * class that will be instantiated.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class ObjectDragProxy extends Actor
+{
+    private Action realAction;
+
+    public ObjectDragProxy(GreenfootImage dragImage, Action realAction)
+    {
+        setImage(dragImage);
+        this.realAction = realAction;
+    }
+
+    /**
+     * Create the real object
+     * 
+     */
+    public void createRealObject()
+    {
+        realAction.actionPerformed(null);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ProjectProperties.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ProjectProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..5365c726fe76ec1f0dbdd72af6de57aa05bf68e3
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/ProjectProperties.java
@@ -0,0 +1,281 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009, 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.GreenfootImage;
+import greenfoot.util.GreenfootUtil;
+import greenfoot.util.Version;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.Properties;
+
+
+/**
+ * Represents the persistent properties associated with a greenfoot project. It
+ * represents both the file that holds the properties and the actual properties.
+ * 
+ * @author Poul Henriksen
+ */
+public class ProjectProperties
+{
+    /** String printed in the top of the properties file. */
+    private static final String FILE_HEADER = "Greenfoot properties";
+
+    /**
+     * Name of the greenfoot package file that holds information specific to a
+     * package/project
+     */
+    public static final String GREENFOOT_PKG_NAME = "project.greenfoot";
+
+    /** Holds the actual properties */
+    private Properties properties;
+
+    /** Reference to the file that holds the properties */
+    private File propsFile;
+
+    /**
+     * Creates a new properties instance for the project in the given directory.
+     * The directory has to exist.
+     * 
+     * @param projectDir
+     */
+    public ProjectProperties(File projectDir)
+    {
+        properties = new Properties();
+        load(projectDir);
+    }
+    
+    /**
+     * Creates a new properties instance with the file loaded from the root of this class loader.
+     * 
+     * @param projectDir
+     */
+    public ProjectProperties()
+    {
+        properties = new Properties();
+        load();
+    }
+
+    /**
+     * Tries to load the project-file with the default class loader.
+     */
+    private void load()
+    {
+        URL probsFile = this.getClass().getResource("/" + GREENFOOT_PKG_NAME);
+        InputStream is = null;
+        try {
+            is = probsFile.openStream();
+            properties.load(is);
+        }
+        catch (IOException ioe) {
+            // if it does not exist, we will create it later if something needs
+            // to be written to it. This makes it work with scenarios created
+            // with earlier versions of greenfoot that does not contain a
+            // greenfoot project properties file.
+        }
+        finally {
+            if (is != null) {
+                try {
+                    is.close();
+                }
+                catch (IOException e) {}
+            }
+        }
+    }
+
+    /**
+     * Loads the properties from the greenfoot properties file in the given
+     * directory.
+     * 
+     * @param projectDir The project dir.
+     * @throws IllegalArgumentException If directory can't be read or written.
+     */
+    private void load(File projectDir)
+    {
+        propsFile = new File(projectDir, GREENFOOT_PKG_NAME);
+
+        InputStream is = null;
+        try {
+            is = new FileInputStream(propsFile);
+            properties.load(is);
+        }
+        catch (IOException ioe) {
+            // if it does not exist, we will create it later if something needs
+            // to be written to it. This makes it work with scenarios created
+            // with earlier versions of greenfoot that does not contain a
+            // greenfoot project properties file.
+        }
+        finally {
+            if (is != null) {
+                try {
+                    is.close();
+                }
+                catch (IOException e) {}
+            }
+        }
+    }
+    
+    
+    /**
+     * Stores these properties to the file.
+     * 
+     * @throws IOException If the properties can't be written to the properties
+     *             file.
+     */
+    public synchronized void save()
+    {
+        OutputStream os = null;
+        try {
+            os = new FileOutputStream(propsFile);
+            properties.store(os, FILE_HEADER);
+        }
+        catch (FileNotFoundException e) {}
+        catch (IOException e) {}
+        finally {
+            if (os != null) {
+                try {
+                    os.close();
+                }
+                catch (IOException e) {}
+            }
+        }
+    }
+
+
+    /**
+     * Sets a property as in Java's Properties class. Thread-safe. 
+     */
+    public synchronized void setString(String key, String value)
+    {
+        properties.setProperty(key, value);
+    }
+
+
+    /**
+     * Gets a property as in Java's Properties class. Thread-safe.
+     */
+    public synchronized String getString(String key)
+    {
+        return properties.getProperty(key);
+    }
+
+
+    /**
+     * Sets an int property as in Java's Properties class. Thread-safe.
+     */
+    public synchronized void setInt(String key, int value)
+    {
+        properties.setProperty(key, Integer.toString(value));
+    }
+
+
+    /**
+     * Gets an int property as in Java's Properties class. Thread-safe.
+     */
+    public synchronized int getInt(String key) throws NumberFormatException
+    {
+        String number = properties.getProperty(key);
+        return Integer.parseInt(number);
+    }
+    
+    /**
+     * Sets a boolean property as in Java's Properties class. Thread-safe. 
+     */
+    public synchronized void setBoolean(String key, boolean value)
+    {
+        properties.setProperty(key, Boolean.toString(value));        
+    }
+    
+    /**
+     * Gets a boolean property as in Java's Properties class. 
+     * Allows the specification of a default value. Thread-safe.
+     */
+    public synchronized boolean getBoolean(String key, String defaultValue)
+    {
+        String bool = properties.getProperty(key, defaultValue);
+        return Boolean.parseBoolean(bool);
+    }
+    
+    /**
+     * Remove a property; return its old value. Thread-safe.
+     * @param key  The property name
+     */
+    public synchronized String removeProperty(String key)
+    {
+        return (String) properties.remove(key);
+    }
+
+
+    /**
+     * Stores the API version. Thread-safe.
+     */
+    public void setApiVersion(String version)
+    {
+        properties.setProperty("version", version);
+    }
+
+
+    /**
+     * Attempts to find the version number the greenfoot API that a greenfoot
+     * project was created with. If it can not find a version number, it will
+     * return Version.NO_VERSION. Thread-safe.
+     * 
+     * @return API version
+     */
+    public Version getAPIVersion()
+    {
+        String versionString = properties.getProperty("version");
+        Version version = new Version(versionString);
+        return version;
+    }
+    
+    /**
+     * Gets an image for the given class. The images are cached to avoid loading
+     * images several times. This method is thread-safe.
+     * 
+     * @param className If it is a qualified name, the package is ignored.
+     *            Returns null, if there is no entry for this class in the
+     *            properties.
+     * @return The image.
+     */
+    public GreenfootImage getImage(String className)
+    {
+        return GreenfootUtil.getGreenfootImage(className, getString("class." + className + ".image"));
+    }
+    
+    /**
+     * Remove the cached version of an image for a particular class. This should be
+     * called when the image for the class is changed. Thread-safe.
+     */
+    public void removeCachedImage(String className)
+    {
+       GreenfootUtil.removeCachedImage(className);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/Simulation.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/Simulation.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc6d5669dcabfc9615e24be75468916f18afa1ef
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/Simulation.java
@@ -0,0 +1,1046 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+import greenfoot.World;
+import greenfoot.WorldVisitor;
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+import greenfoot.event.WorldEvent;
+import greenfoot.event.WorldListener;
+import greenfoot.platforms.SimulationDelegate;
+import greenfoot.util.HDTimer;
+
+import java.awt.EventQueue;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import javax.swing.JComponent;
+import javax.swing.event.EventListenerList;
+
+/**
+ * The main class of the simulation. It drives the simulation and calls act()
+ * on the objects in the world and then paints them.
+ * 
+ * @author Poul Henriksen
+ */
+public class Simulation extends Thread
+    implements WorldListener
+{
+    // Most of the fields require synchronized access. Some of them do not because they are only
+    // accessed from the simulation thread itself. "repaintLock" protects paintPending and
+    // lastRepaintTime.
+    
+    // All user code should generally be run on the simulation thread. The simulation monitor
+    // should not be held while executing user code (though the world lock should be held).
+    
+    // The following two constants control repainting of the world while the simulation is
+    // running. We skip repaints if the simulation is running faster than the MAX_FRAME_RATE.
+    // This makes the high speeds run faster, since we avoid repaints that can't be seen
+    // anyway. Once requested, the repaint may take some time to occur; if the effective
+    // repaint rate falls below MIN_FRAME_RATE, then we temporarily suspend the simulation
+    // and wait for the repaint to occur.
+    
+    /** Repaints will be requested at this rate (at most) */
+    private static int MAX_FRAME_RATE = 65;
+    /** Simulation will wait for repaints if the repaint rate falls below this */
+    private static int MIN_FRAME_RATE = 35;
+    
+    private WorldHandler worldHandler;
+    
+    /** Whether the simulation is (to be) paused */
+    private boolean paused;
+
+    /** Whether the simulation is enabled (world installed) */
+    private volatile boolean enabled;
+
+    /** Whether to run one loop when paused */
+    private boolean runOnce;
+    
+    /** Tasks that are queued to run on the simulation thread */
+    private Queue<Runnable> queuedTasks = new LinkedList<Runnable>();
+
+    private EventListenerList listenerList = new EventListenerList();
+
+    /* Various simulation events */
+    private SimulationEvent startedEvent;
+    private SimulationEvent stoppedEvent;
+    private SimulationEvent disabledEvent;
+    private SimulationEvent speedChangeEvent;
+    private SimulationEvent debuggerPausedEvent;
+    private SimulationEvent debuggerResumedEvent;
+    
+    private static Simulation instance;
+
+    /** for timing the animation */
+    public static final int MAX_SIMULATION_SPEED = 100;
+    private int speed; // the simulation speed in range (1..100)
+
+    private long lastDelayTime;
+    private long delay; // the speed translated into delay (nanoseconds)
+
+    // private long updates; // used for debugging to calculate update rate
+    //private long lastUpdate; // used for debugging to calculate update rate
+    
+    /** Protects "paintPending" and "lastRepaintTime" */
+    private Object repaintLock = new Object();
+    /** The last time that a repaint of the World was issued. */
+    private long lastRepaintTime;
+    /** true if a repaint has been issued and not yet processed. */
+    private boolean paintPending;
+    
+    private SimulationDelegate delegate;
+
+    /**
+     * Lock to synchronize access to the two fields: delaying and interruptDelay
+     */
+    private Object interruptLock = new Object();
+    /** Whether we are currently delaying between act-loops. */
+    private boolean delaying;
+    /** Whether a delay between act-loops should be interrupted. */
+    private boolean interruptDelay;
+
+    
+    /**
+     * Used to figure out when we are transitioning from running to paused state and vice versa.
+     * Only modify this from the simulation thread.
+     */
+    private boolean isRunning = false;
+    
+    /** flag to indicate that we want to abort the simulation and never start it again. */
+    private volatile boolean abort;
+    
+    /**
+     * Create new simulation. Leaves the simulation in paused state
+     * 
+     * @param worldHandler
+     *            The handler for the world that is simulated
+     */
+    private Simulation(SimulationDelegate simulationDelegate)
+    {
+        this.setName("SimulationThread");
+        this.delegate = simulationDelegate;
+        startedEvent = new SimulationEvent(this, SimulationEvent.STARTED);
+        stoppedEvent = new SimulationEvent(this, SimulationEvent.STOPPED);
+        speedChangeEvent = new SimulationEvent(this, SimulationEvent.CHANGED_SPEED);
+        disabledEvent = new SimulationEvent(this, SimulationEvent.DISABLED);
+        debuggerPausedEvent = new SimulationEvent(this, SimulationEvent.DEBUGGER_PAUSED);
+        debuggerResumedEvent = new SimulationEvent(this, SimulationEvent.DEBUGGER_RESUMED);
+        setPriority(Thread.MIN_PRIORITY);
+        paused = true;
+        speed = 50;
+        delay = calculateDelay(speed);
+        HDTimer.init();
+    }
+    
+    /**
+     * Initialize the (singleton) simulation instance.
+     * The simulation thread will not actually be started until the WorldHandler
+     * is attached.
+     */
+    public static void initialize(SimulationDelegate simulationDelegate)
+    {
+        instance = new Simulation(simulationDelegate);
+    }
+
+    /**
+     * Returns the simulation if it is initialised. If not, it will return null.
+     */
+    public static Simulation getInstance()
+    {
+        return instance;
+    }
+
+    /**
+     * Attach this simulation to the world handler (and vice versa).
+     */
+    public void attachWorldHandler(WorldHandler worldHandler)
+    {
+        this.worldHandler = worldHandler;
+        worldHandler.addWorldListener(this);
+        addSimulationListener(worldHandler);
+        start();
+    }
+    
+    // The following methods should run only on the simulation thread itself!
+
+    /**
+     * Runs the simulation from the current state.
+     */
+    @Override
+    public void run()
+    {
+        /* It is important this redirects to another method.
+         * The debugger sets a breakpoint on the first line of this method, and if
+         * that is a loop (as is the case for the first line of runContent at the time of writing)
+         * then it hits the breakpoint every time.  By putting it all in a separate
+         * method, we avoid that happening:
+         */
+        runContent();
+    }
+    
+    private void runContent()
+    {
+        while (!abort) {
+            try {
+                maybePause();
+                                
+                if (worldHandler.hasWorld()) {
+                    runOneLoop(worldHandler.getWorld());
+                }
+
+                delay();
+            }
+            catch (ActInterruptedException e) {
+                // Someone interrupted the user code. We ignore it and let
+                // maybePause() handle whatever needs to be done.
+            }
+            catch (InterruptedException e) {
+                // maybePause was interrupted. Do nothing, will be handled the next time we get to maybePause.
+            }
+            catch (Throwable t) {
+                // If any other exceptions occur, halt the simulation
+                synchronized (this) {
+                    paused = true;
+                }
+                t.printStackTrace();
+            }
+        }
+
+        // The simulations has been aborted. But, we might still have to notify the world.
+        synchronized (this) {
+            if(isRunning) {
+                World world = worldHandler.getWorld();
+                if (world != null) {
+                    world.stopped();
+                }
+                isRunning = false;
+            } 
+        }
+    }   
+
+    /**
+     * Schedule some task to run on the simulation thread.
+     */
+    public synchronized void runLater(Runnable r)
+    {
+        queuedTasks.add(r);
+        if (paused) {
+            notify();
+        }
+    }
+    
+    public final static String PAUSED = "simulationWait";
+    /**
+     * A special method recognised by the debugger as indicating that the simulation
+     * is pausing.
+     */
+    private void simulationWait() throws InterruptedException
+    {
+        this.wait();
+    }
+    
+    /**
+     * Block if the simulation is paused. This will block until the simulation
+     * is resumed (is both enabled and unpaused). It should only be called on the
+     * simulation thread.
+     * 
+     * @throws InterruptedException If it couldn't acquire the world lock when
+     *             signalling started()/stopped() to the world.
+     */
+    private void maybePause()
+        throws InterruptedException
+    {
+        while (!abort) {
+            runQueuedTasks();
+
+            // Wait loop that waits until such time that at least one simulation
+            // loop can be run.
+
+            World world;
+            boolean checkStop;
+            
+            synchronized (this) {
+                checkStop = (paused || !enabled) && isRunning;
+                world = worldHandler.getWorld();
+                
+                if (checkStop) {
+                    isRunning = false; // if we start again, we'll need to signal it.
+                }
+                else if (isRunning) {
+                    return; // We're running and don't need to stop
+                }
+            }
+            
+            // We are either not running, or running and need to stop.
+            
+            if (checkStop) {
+                try {
+                    signalStopping(world);
+                }
+                catch (InterruptedException ie) {
+                    continue;
+                }
+                    
+                synchronized (this) {
+                    runOnce = false;
+
+                    if (! paused) {
+                        isRunning = enabled; // Never signalled a stop, so don't signal a start
+                    }
+                }
+            }
+            
+            // We're not running; we may need to resume running.
+            
+            boolean doResumeRunning;
+            
+            synchronized (this) {
+                doResumeRunning = !paused && enabled && !abort && !isRunning;
+                if (! isRunning && ! doResumeRunning && ! runOnce) {
+                    // Still paused, so notify listeners, and actually pause
+                    if (enabled) {
+                        fireSimulationEvent(stoppedEvent);
+                    }
+                    if (worldHandler != null) {
+                        worldHandler.repaint();
+                    }
+                    
+                    if (! queuedTasks.isEmpty()) {
+                        continue; // Must run queued tasks before wait
+                    }
+                    
+                    System.gc();
+                    try {
+                        simulationWait();
+                        lastDelayTime = System.nanoTime();
+                    }
+                    catch (InterruptedException e1) {
+                        // Swallow the interrupt
+                    }
+                    
+                    continue; // take it from the top
+                }
+            }
+            
+            if (doResumeRunning) {
+                resumeRunning();
+            }
+            
+            synchronized (this) {
+                if (runOnce || isRunning) {
+                    // Run the simulation
+                    runOnce = false;
+                    return;
+                }
+            }
+        }
+    
+        runQueuedTasks();
+    }
+    
+    /**
+     * Send a started event and notify the world that it is now running.
+     * 
+     * @throws InterruptedException
+     */
+    private void resumeRunning() throws InterruptedException
+    {
+        isRunning = true;
+        lastDelayTime = System.nanoTime();
+        fireSimulationEvent(startedEvent);
+        World world = worldHandler.getWorld();
+        if (world != null) {
+            // We need to sync to avoid ConcurrentModificationException
+            ReentrantReadWriteLock lock = worldHandler.getWorldLock();
+            try {
+                lock.writeLock().lockInterruptibly();
+            }
+            catch (InterruptedException ie) {
+                isRunning = false; // need to notify again
+                throw ie;
+            }
+                
+            try {
+                world.started(); // may cause us to pause
+            }
+            catch (Throwable t) {
+                isRunning = false;
+                setPaused(true);
+                t.printStackTrace();
+                return;
+            }
+            finally {
+                lock.writeLock().unlock();
+            }
+        }
+    }
+    
+    /**
+     * Tell the world that the simulation is stopping. The world might resume
+     * the simulation when this happens.
+     */
+    private void signalStopping(World world) throws InterruptedException
+    {
+        // This code will be executed when:
+        //  runOnce is over  or
+        //  setPaused(true)   or
+        //  setEnabled(false)  or
+        //  abort() (sometimes, depending on timing)
+        if (world != null) {
+            // We need to sync to avoid ConcurrentModificationException
+            ReentrantReadWriteLock lock = worldHandler.getWorldLock();
+            lock.writeLock().lockInterruptibly();
+            try {
+                world.stopped(); // may un-pause
+            }
+            catch (ActInterruptedException aie) {
+                synchronized (this) {
+                    paused = true;
+                }
+                throw aie;
+            }
+            catch (Throwable t) {
+                // If any exceptions occur, halt the simulation
+                synchronized (this) {
+                    paused = true;
+                }
+                t.printStackTrace();
+            }
+            finally {
+                lock.writeLock().unlock();
+            }
+        }
+    }
+
+    /** This must match the method name below! */
+    public static String RUN_QUEUED_TASKS = "runQueuedTasks";
+    
+    /**
+     * Run all tasks that have been schedule to run on the simulation thread.
+     * Of course, this should only be called from the simulation thread...
+     * (and from an unsynchronized context).
+     */
+    private void runQueuedTasks()
+    {
+        Runnable r;
+        synchronized (this) {
+            r = queuedTasks.poll();
+        }
+        
+        while (r != null) {
+            World world = WorldHandler.getInstance().getWorld();
+            try {
+                ReentrantReadWriteLock lock  = null;
+                if (world != null) {
+                    lock = worldHandler.getWorldLock();
+                    lock.writeLock().lock();
+                }
+                
+                try {
+                    // This may run user code, which might throw an exception.
+                    r.run();
+                }
+                catch (Throwable t) {
+                    t.printStackTrace();
+                }
+                
+                if (world != null) {
+                    lock.writeLock().unlock();
+                }
+            }
+            finally {
+                
+            }
+            synchronized (this) {
+                r = queuedTasks.poll();
+            }
+        }
+    }
+    
+    /**
+     * Performs one step in the simulation. Calls act() on all actors.
+     * 
+     * @throws ActInterruptedException  if an act() call was interrupted.
+     */
+    private void runOneLoop(World world)
+    {
+        worldHandler.startSequence();
+
+        // We don't want to be interrupted in the middle of an act-loop
+        // so we remember the first interrupted exception and throw it
+        // when all the actors have acted.
+        ActInterruptedException interruptedException = null;
+        
+        List<? extends Actor> objects = null;
+
+        // We need to sync to avoid ConcurrentModificationException
+        try {
+            ReentrantReadWriteLock lock = worldHandler.getWorldLock();
+            lock.writeLock().lockInterruptibly();
+            try {
+                try {
+                    actWorld(world);
+                    if (world != worldHandler.getWorld()) {
+                        return; // New world was set
+                    }
+                }
+                catch (ActInterruptedException e) {
+                    interruptedException = e;
+                }
+                // We need to make a copy so that the original collection can be
+                // modified by the actors' act() methods.
+                objects = new ArrayList<Actor>(WorldVisitor.getObjectsListInActOrder(world));
+                for (Actor actor : objects) {
+                    if (!enabled) {
+                        return;
+                    }
+                    if (ActorVisitor.getWorld(actor) != null) {
+                        try {
+                            actActor(actor);
+                            if (world != worldHandler.getWorld()) {
+                                return; // New world was set
+                            }
+                        }
+                        catch (ActInterruptedException e) {
+                            if (interruptedException == null) {
+                                interruptedException = e;
+                            }
+                        }
+                    }
+
+                }
+                
+                worldHandler.getKeyboardManager().clearLatchedKeys();
+            }
+            finally {
+                lock.writeLock().unlock();
+            }
+        }
+        catch (InterruptedException e) {
+            // Interrupted while trying to acquire lock
+            throw new ActInterruptedException(e);
+        }
+
+        // We were interrupted while running through the act-loop. Throw now.
+        if(interruptedException != null) {
+            throw interruptedException;
+        }
+        
+        // printUpdateRate(System.nanoTime());
+
+        repaintIfNeeded();
+    }
+    
+    // The actActor, actWorld and newInstance methods exist as a tagging mechanism
+    // that allows them to be found easily in the debugger when we
+    // are attempting to reach the next call to user code
+    
+    public static final String ACT_ACTOR = "actActor";
+    private static void actActor(Actor actor)
+    {
+        actor.act();
+    }
+    
+    public static final String ACT_WORLD = "actWorld";
+    private static void actWorld(World world)
+    {
+        world.act();
+    }
+    
+    public static final String NEW_INSTANCE = "newInstance";
+    public static Object newInstance(Constructor<?> constructor)
+        throws InvocationTargetException, IllegalArgumentException, InstantiationException, IllegalAccessException
+    {
+        return constructor.newInstance((Object[])null);
+    }
+    
+    /**
+     * Repaints the world if needed to obtain the desired frame rate.
+     */
+    private void repaintIfNeeded()
+    {
+        long currentTime = System.currentTimeMillis();
+        long timeSinceLast = Math.max(1, currentTime - lastRepaintTime);
+        
+        if ((1000 / timeSinceLast) <= MAX_FRAME_RATE) {
+            try {
+                synchronized(repaintLock) {
+                    
+                    // Current frame rate is less than maximum, so we'll at least request
+                    // a repaint at this time.
+                    if (! paintPending) {
+                        lastRepaintTime = currentTime;
+                        worldHandler.repaint();
+                        paintPending = true;
+                    }
+                    
+                    if ((1000 / timeSinceLast) <= MIN_FRAME_RATE) {
+                        // Waiting here makes sure the WorldCanvas gets a chance to
+                        // repaint. It also lets the rest of the UI be responsive, even if
+                        // we are running at maximum speed, by making sure events on the
+                        // event queue are processed.
+
+                        // Schedule a forced repaint, so that we don't deadlock while
+                        // waiting for a repaint if something stops the repaint from
+                        // occurring (no world for instance).
+                        EventQueue.invokeLater(new Runnable() {
+                            @Override
+                            public void run()
+                            {
+                                forcedRepaint();
+                            }
+                        });
+                        
+                        while (paintPending) {
+                            repaintLock.wait();
+                        }
+                    }
+                }
+            }
+            catch (InterruptedException ie) {}
+        }
+    }
+    
+    private void forcedRepaint()
+    {
+        JComponent wcanvas = WorldHandler.getInstance().getWorldCanvas();
+        synchronized (repaintLock) {
+            if (WorldHandler.getInstance().hasWorld()) {
+                wcanvas.paintImmediately(wcanvas.getBounds());
+            }
+            
+            if (paintPending) {
+                paintPending = false;
+                repaintLock.notify();
+            }
+        }
+    }
+
+    /**
+     * Inform the simulation that the world has been repainted successfully.
+     */
+    public void worldRepainted()
+    {
+        synchronized (repaintLock) {
+            paintPending = false;
+            //long response = System.currentTimeMillis() - lastRepaintTime;
+            //if (response > 250) {
+            //    System.out.println("Repaint response time: " + response);
+            //}
+            repaintLock.notify();
+        }
+    }
+
+    /**
+     * Debug output to print the rate at which updates are performed
+     * (acts/second).
+     */
+    /*
+    private void printUpdateRate(long currentTime)
+    {
+        //updates++;
+
+        long timeSinceUpdate = currentTime - lastUpdate;
+        if (timeSinceUpdate > 3000000000L) {
+            lastUpdate = currentTime;
+            //updates = 0;
+        }
+    }
+    */
+
+    // Public methods etc.
+
+    /**
+     * Run one step of the simulation. Each actor in the world acts once.
+     */
+    public synchronized void runOnce()
+    {
+        // Don't call runOneLoop directly as that executes user code
+        // and might hang.
+        runOnce = true;
+        notifyAll();
+    }
+
+    /**
+     * Pauses and unpauses the simulation.
+     */
+    public synchronized void setPaused(boolean b)
+    {
+        if(paused == b) {
+            //Nothing to do for us.
+            return;
+        }
+        paused = b;
+        if (enabled) {
+            if(!paused) 
+            {
+                synchronized (interruptLock) {
+                    interruptDelay = false;
+                }
+            }
+            
+            notifyAll();
+
+            // If we are currently in the delay loop, interrupt it so that
+            // the pause takes effect immediately.
+            if (paused) {
+                interruptDelay();                
+            }
+        }
+    }
+
+    /**
+     * Interrupt if we are currently delaying between act-loops or the user is
+     * using the Greenfoot.delay() method. This will basically jump to the next
+     * act-loop as fast as possible while still executing the rest of actors in
+     * the current loop. Used by setPaused() and setSpeed() to interrupt current
+     * delays.
+     */
+    private void interruptDelay()
+    {
+        synchronized (interruptLock) {
+            if (delaying) {
+                interrupt();
+            }
+            else {
+                // Called outside the delaying, so make sure it doesn't go into
+                // the delay by signalling with this flag
+                interruptDelay = true;
+            }
+        }
+    }
+
+    /**
+     * Enable or disable the simulation.
+     */
+    public synchronized void setEnabled(boolean b)
+    {
+        if (b == enabled) {
+            return;
+        }
+
+        enabled = b;
+        
+        if (b) {
+            notifyAll();
+            // fire a paused event to let listeners know we are
+            // enabled again
+            if (paused) {
+                fireSimulationEvent(stoppedEvent);
+            }
+        }
+        else {
+            paused = true;
+            // isRunning = false; // cause a started event if necessary, when the simulation is enabled again
+            interruptDelay();
+            fireSimulationEvent(disabledEvent);
+        }
+    }
+
+    private void fireSimulationEvent(SimulationEvent event)
+    {
+        // Guaranteed to return a non-null array
+        Object[] listeners;
+        synchronized (listenerList) {
+            listeners = listenerList.getListenerList();
+
+            // Process the listeners last to first, notifying
+            // those that are interested in this event
+            for (int i = listeners.length - 2; i >= 0; i -= 2) {
+                if (listeners[i] == SimulationListener.class) {
+                    ((SimulationListener) listeners[i + 1]).simulationChanged(event);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Notify that the simulation thread has been halted or resumed by the debugger.
+     */
+    public void notifyThreadStatus(boolean halted)
+    {
+        if (halted) {
+            fireSimulationEvent(debuggerPausedEvent);
+        }
+        else {
+            // resumed
+            fireSimulationEvent(debuggerResumedEvent);
+        }
+    }
+
+    /**
+     * Add a simulationListener to listen for changes.
+     * 
+     * @param l
+     *            Listener to add
+     */
+    public void addSimulationListener(SimulationListener l)
+    {
+        synchronized (listenerList) {
+            listenerList.add(SimulationListener.class, l);
+        }
+    }
+
+    /**
+     * Remove a simulationListener to listen for changes.
+     * 
+     * @param l
+     *            Listener to remove
+     */
+    public void removeSimulationListener(SimulationListener l)
+    {
+        synchronized (listenerList) {
+            listenerList.remove(SimulationListener.class, l);
+        }
+    }
+
+    /**
+     * Set the speed of the simulation.
+     * 
+     * @param speed
+     *            The speed in the range (0..100)
+     */
+    public void setSpeed(int speed)
+    {
+        if (speed < 0) {
+            speed = 0;
+        }
+        else if (speed > MAX_SIMULATION_SPEED) {
+            speed = MAX_SIMULATION_SPEED;
+        }
+
+        boolean speedChanged;
+        synchronized (this) {
+            speedChanged = this.speed != speed;
+            if (speedChanged) {
+                this.speed = speed;
+                
+                delegate.setSpeed(speed);
+                
+                this.delay = calculateDelay(speed);
+
+                // If simulation is running we should interrupt any waiting or
+                // sleeping that is currently happening.
+                
+                if(!paused) {
+                    synchronized (interruptLock) {
+                        if (delaying) {
+                            interrupt();
+                        }
+                    }
+                }    
+            }
+        }
+        
+        if (speedChanged) {
+            fireSimulationEvent(speedChangeEvent);
+        }
+    }
+
+    /**
+     * Returns the delay as a function of the speed.
+     * 
+     * @return The delay in nanoseconds.
+     */
+    private long calculateDelay(int speed)
+    {
+        // Make the speed into a delay
+        long rawDelay = MAX_SIMULATION_SPEED - speed;
+
+        long min = 30 * 1000L; // Delay at MAX_SIMULATION_SPEED - 1
+        long max = 10000 * 1000L * 1000L; // Delay at slowest speed
+
+        double a = Math.pow(max / (double) min, 1D / (MAX_SIMULATION_SPEED - 1));
+        long delay = 0;
+        if (rawDelay > 0) {
+            delay = (long) (Math.pow(a, rawDelay - 1) * min);
+        }
+        return delay;
+    }
+
+    /**
+     * Get the current simulation speed.
+     * 
+     * @return The speed in the range (1..100)
+     */
+    public synchronized int getSpeed()
+    {
+        return speed;
+    }
+
+    /**
+     * Sleep an amount of time according to the current speed setting for this
+     * simulation. This will wait without considering previous waits, as opposed
+     * to delay(). It should be called only from the simulation thread, in an
+     * unsynchronized context.
+     */
+    public void sleep()
+    {
+        World world = worldHandler.getWorld();
+
+        synchronized (this) {
+            if (paused && isRunning && !runOnce) {
+                // If it should be paused but is still running, it means that we
+                // should try to end as quickly as possible and hence should NOT
+                // delay.
+                // If the user is interactively invoking a method that calls this
+                // method, it will not be caught here, which is the correct
+                // behaviour. Otherwise the call to sleep() will have no visible
+                // effect at all.
+                return;
+            }
+        }
+        
+        try {
+            synchronized (interruptLock) {
+                if (interruptDelay) {
+                    // If interrupted, we just want to return now. We do not
+                    // want to abort by throwing an exception, because that will
+                    // leave the user code execution in an inconsistent state.
+                    return;
+                }
+                delaying = true;
+            }
+            if (world != null) {
+                // The WorldCanvas may be trying to synchronize on the world in
+                // order to do a repaint. So, we use wait() here in order
+                // to release the world lock temporarily.
+                HDTimer.wait(delay, worldHandler.getWorldLock());
+            }
+            else {
+                // shouldn't really happen
+                HDTimer.sleep(delay);
+            }
+        }
+        catch (InterruptedException e) {
+            // If interrupted, we just want to return now. We do not
+            // want to abort by throwing an exception, because that will
+            // leave the user code execution in an inconsistent state.            
+        }
+        finally {
+            synchronized (interruptLock) {
+                delaying = false;
+            }
+        }
+    }
+
+    /**
+     * Cause a delay (wait) according to the current speed setting for this
+     * simulation. It will take the time spend in this simulation loop into
+     * consideration and only pause the remaining time.
+     * 
+     * <p>This method is used for controlling the speed of the animation.
+     * 
+     * <p>The world lock should not be held when this method is called, so
+     * that repaints can occur.
+     */
+    private void delay()
+    {
+        long currentTime = System.nanoTime();
+        long timeElapsed = currentTime - lastDelayTime;
+        long actualDelay = Math.max(delay - timeElapsed, 0L);
+        
+        synchronized (this) {
+            synchronized (interruptLock) {
+                if(interruptDelay) {
+                    // interruptDelay was issued before entering this sync, so interrupt now.
+                    interruptDelay = false;
+                    if (paused || abort) {
+                        lastDelayTime = currentTime;
+                        return; // return... without delay
+                    }
+                }
+                delaying = true;
+            }
+        }
+
+        while (actualDelay > 0) {
+
+            try {
+                HDTimer.sleep(actualDelay);
+            }
+            catch (InterruptedException ie) {
+                // We get interrupted either due to a pause, abort, being disabled or
+                // a speed change. If it's a speed change, we can continue to delay, up
+                // to the new time; otherwise we should finish up now.
+                synchronized (this) {
+                    if (!enabled || paused || abort) {
+                        break;
+                    }
+                }
+            }
+
+            currentTime = System.nanoTime();
+            timeElapsed = currentTime - lastDelayTime;
+            actualDelay = delay - timeElapsed;
+        }
+
+        lastDelayTime = currentTime;
+        synchronized (interruptLock) {
+            Thread.interrupted(); // clear interrupt, in case we were interrupted just after the delay
+            delaying = false;
+        }
+    }
+
+    /**
+     * Abort the simulation. It abruptly stops what is running and ends the
+     * simulation thread, and it is not possible to start it again.
+     */
+    public void abort()
+    {
+        abort = true;
+        setEnabled(false);
+    }
+
+
+    // ---------- WorldListener interface -----------
+
+    /**
+     * A new world was created - we're ready to go. Enable the simulation
+     * functions.
+     */
+    @Override
+    public void worldCreated(WorldEvent e)
+    {
+        setEnabled(true);
+    }
+
+    /**
+     * The world was removed - disable the simulation functions.
+     */
+    @Override
+    public void worldRemoved(WorldEvent e)
+    {
+        setEnabled(false);
+    }
+
+    // ----------- End of WorldListener interface -------------
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/SimulationDebugMonitor.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/SimulationDebugMonitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..41cd64c10b6eb620350464263d5d6dc398035926
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/SimulationDebugMonitor.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010 Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+/**
+ * A dummy class that adjusts the details of the Run/Act/Pause actions when constructed.
+ * It is solely designed for use by the GreenfootDebugHandler class,
+ * which will construct an instance from the BlueJ VM when it wants
+ * to enable/disable the actions.  Hence all the state is static, because a new
+ * instance will be constructed each time.
+ *
+ */
+public class SimulationDebugMonitor
+{
+    public final static Object RUNNING = new Object();
+    public final static Object NOT_RUNNING = new Object();
+    
+    private static boolean isRunning = true;
+
+    public SimulationDebugMonitor(Object running)
+    {
+        synchronized (RUNNING) {
+            if (running == RUNNING && !isRunning) {
+                Simulation.getInstance().notifyThreadStatus(false);
+                isRunning = true;
+            } else if (running == NOT_RUNNING && isRunning) {
+                Simulation.getInstance().notifyThreadStatus(true);
+                isRunning = false;
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/WorldHandler.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/WorldHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..427bccbd3290a29dd485dcedfc2c52eee5a83c8c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/WorldHandler.java
@@ -0,0 +1,1023 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+import greenfoot.World;
+import greenfoot.WorldVisitor;
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+import greenfoot.event.TriggeredKeyListener;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.event.WorldEvent;
+import greenfoot.event.WorldListener;
+import greenfoot.gui.DragListener;
+import greenfoot.gui.DropTarget;
+import greenfoot.gui.WorldCanvas;
+import greenfoot.gui.input.InputManager;
+import greenfoot.gui.input.KeyboardManager;
+import greenfoot.gui.input.mouse.LocationTracker;
+import greenfoot.gui.input.mouse.MousePollingManager;
+import greenfoot.gui.input.mouse.WorldLocator;
+import greenfoot.platforms.WorldHandlerDelegate;
+import greenfoot.util.GraphicsUtilities;
+
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.EventQueue;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.image.BufferedImage;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+
+import javax.swing.SwingUtilities;
+import javax.swing.event.EventListenerList;
+
+import bluej.debugmgr.objectbench.ObjectBenchInterface;
+
+/**
+ * The worldhandler handles the connection between the World and the
+ * WorldCanvas.
+ * 
+ * @author Poul Henriksen
+ */
+public class WorldHandler
+    implements TriggeredMouseListener, TriggeredMouseMotionListener, TriggeredKeyListener, DropTarget, DragListener, SimulationListener
+{
+    /** A flag to check whether a world has been set. Can be tested/cleared by callers. */
+    private boolean worldIsSet;
+
+    private World initialisingWorld;
+    private volatile World world;
+    private WorldCanvas worldCanvas;
+
+    // where did the the drag/drop operation begin? In pixels
+    private int dragBeginX;
+    private int dragBeginY;
+
+    /**
+     * Whether the object was dropped, or more specifically, whether it does not
+     * need to be replaced if the drop is cancelled.
+     */
+    private boolean objectDropped = true; // true if the object was dropped
+
+    private KeyboardManager keyboardManager;
+    private static WorldHandler instance;
+    private EventListenerList listenerList = new EventListenerList();
+    private WorldHandlerDelegate handlerDelegate;
+    private MousePollingManager mousePollingManager;
+    private InputManager inputManager;
+
+    // Offset from the middle of the actor when initiating a drag on an actor.
+    private int dragOffsetX;
+    private int dragOffsetY;
+    // The actor being dragged
+    private Actor dragActor;
+    private boolean dragActorMoved;
+    private Cursor defaultCursor;
+    
+    /** Lock used for world manipulation */
+    private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+    /** Timeout used for readers attempting to acquire lock */
+    public static final int READ_LOCK_TIMEOUT = 500;
+    
+    /** Condition used to wait for repaint */
+    private Object repaintLock = new Object();
+    private boolean isRepaintPending = false;
+    
+    public static synchronized void initialise(WorldCanvas worldCanvas, WorldHandlerDelegate helper)
+    {
+        instance = new WorldHandler(worldCanvas, helper);
+    }
+    
+    /**
+     * Initialiser for unit testing.
+     */
+    public static synchronized void initialise()
+    {
+        instance = new WorldHandler();
+    }
+    
+    /**
+     * Return the singleton instance.
+     */
+    public synchronized static WorldHandler getInstance()
+    {
+        return instance;
+    }
+
+    /**
+     * Constructor used for unit testing.
+     */
+    private WorldHandler() 
+    {
+        instance = this;
+        mousePollingManager = new MousePollingManager(null);
+        handlerDelegate = new WorldHandlerDelegate() {
+
+            @Override
+            public void discardWorld(World world)
+            {                
+            }
+
+            @Override
+            public InputManager getInputManager()
+            {
+                return null;
+            }
+
+            @Override
+            public void instantiateNewWorld()
+            {
+            }
+
+            @Override
+            public boolean maybeShowPopup(MouseEvent e)
+            {
+                return false;
+            }
+
+            @Override
+            public void mouseClicked(MouseEvent e)
+            {
+            }
+            
+            @Override
+            public void mouseMoved(MouseEvent e)
+            {
+            }
+
+            @Override
+            public void setWorld(World oldWorld, World newWorld)
+            {
+            }
+
+            @Override
+            public void setWorldHandler(WorldHandler handler)
+            {
+            }
+            
+            @Override
+            public void addActor(Actor actor, int x, int y)
+            {
+            }
+
+            @Override
+            public void actorDragged(Actor actor, int xCell, int yCell)
+            {
+            }
+            
+            @Override
+            public void objectAddedToWorld(Actor actor)
+            {
+            }
+        };
+    }
+        
+    /**
+     * Creates a new worldHandler and sets up the connection between worldCanvas
+     * and world.
+     * 
+     * @param handlerDelegate
+     */
+    private WorldHandler(final WorldCanvas worldCanvas, WorldHandlerDelegate handlerDelegate)
+    {
+        instance = this;
+        this.handlerDelegate = handlerDelegate;
+        this.handlerDelegate.setWorldHandler(this);
+
+        this.worldCanvas = worldCanvas;
+        
+        mousePollingManager = new MousePollingManager(null);
+
+        worldCanvas.setDropTargetListener(this);
+
+        LocationTracker.instance().setSourceComponent(worldCanvas);
+        keyboardManager = new KeyboardManager();
+        worldCanvas.addFocusListener(keyboardManager);
+
+        inputManager = handlerDelegate.getInputManager();
+        addWorldListener(inputManager);
+        inputManager.setRunningListeners(getKeyboardManager(), mousePollingManager, mousePollingManager);
+        worldCanvas.addMouseListener(inputManager);
+        worldCanvas.addMouseMotionListener(inputManager);
+        worldCanvas.addKeyListener(inputManager);
+        inputManager.init();
+
+        defaultCursor = worldCanvas.getCursor();
+    }
+
+    /**
+     * Get the keyboard manager.
+     */
+    public KeyboardManager getKeyboardManager()
+    {
+        return keyboardManager;
+    }
+
+    /**
+     * Get the mouse manager.
+     */
+    public MousePollingManager getMouseManager()
+    {
+        return mousePollingManager;
+    }
+
+    /*
+     * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
+     */
+    public void mouseClicked(MouseEvent e)
+    {
+        handlerDelegate.mouseClicked(e);
+    }
+
+    @Override
+    public void mousePressed(MouseEvent e)
+    {
+        World world = this.world;
+        boolean isPopUp = handlerDelegate.maybeShowPopup(e);
+        if (world != null && SwingUtilities.isLeftMouseButton(e) && !isPopUp) {
+            Actor actor = getObject(e.getX(), e.getY());
+            if (actor != null) {
+                Point p = e.getPoint();
+                startDrag(actor, p, world);
+            }
+        }
+    }
+
+    /**
+     * Drag operation starting. Called on the Swing event dispatch thread.
+     */
+    private void startDrag(Actor actor, Point p, World world)
+    {
+        dragActor = actor;
+        dragActorMoved = false;
+        dragBeginX = ActorVisitor.getX(actor) * world.getCellSize() + world.getCellSize() / 2;
+        dragBeginY = ActorVisitor.getY(actor) * world.getCellSize() + world.getCellSize() / 2;
+        dragOffsetX = dragBeginX - p.x;
+        dragOffsetY = dragBeginY - p.y;
+        objectDropped = false;
+        SwingUtilities.getWindowAncestor(worldCanvas).toFront();
+        worldCanvas.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+        drag(actor, p);
+    }
+    
+    public boolean isDragging()
+    {
+        return dragActor != null;
+    }
+
+    /*
+     * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+        handlerDelegate.maybeShowPopup(e);
+        if (SwingUtilities.isLeftMouseButton(e)) {
+            if (dragActor != null && dragActorMoved) {
+                // This makes sure that a single (final) setLocation
+                // call is received by the actor when dragging ends.
+                // This matters if the actor has overridden setLocation
+                Simulation.getInstance().runLater(new Runnable() {
+                    private Actor dragActor = WorldHandler.this.dragActor;
+                    @Override
+                    public void run()
+                    {
+                        int ax = ActorVisitor.getX(dragActor);
+                        int ay = ActorVisitor.getY(dragActor);
+                        // First we set the position to be the pre-drag position.
+                        // This means that if the user overrides setLocation and 
+                        // chooses not to call the inherited setLocation, the position
+                        // will be as if the drag never happened:
+                        ActorVisitor.setLocationInPixels(dragActor, dragBeginX, dragBeginY);
+                        dragActor.setLocation(ax, ay);
+                        handlerDelegate.actorDragged(dragActor, ax, ay);
+                    }
+                });
+            }
+            dragActor = null;
+            worldCanvas.setCursor(defaultCursor);
+        };
+    }
+
+    /**
+     * Returns an object at the given pixel location. If multiple objects exist
+     * at the one location, this method returns the top-most one according to
+     * paint order.
+     * 
+     * @param x
+     *            The x-coordinate
+     * @param y
+     *            The y-coordinate
+     */
+    public Actor getObject(int x, int y)
+    {
+        return getObject(this.world, x, y);
+    }
+    
+    /**
+     * Returns an object from the given world at the given pixel location. If multiple objects
+     * exist at the one location, this method returns the top-most one according to
+     * paint order.
+     * 
+     * @param x
+     *            The x-coordinate
+     * @param y
+     *            The y-coordinate
+     */
+    private static Actor getObject(World world, int x, int y)
+    {
+        if (world == null) {
+            return null;
+        }
+        
+        int timeout = READ_LOCK_TIMEOUT;
+        try {
+            if (lock.readLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {
+
+                Collection<?> objectsThere = WorldVisitor.getObjectsAtPixel(world, x, y);
+                if (objectsThere.isEmpty()) {
+                    lock.readLock().unlock();
+                    return null;
+                }
+
+                Iterator<?> iter = objectsThere.iterator();
+                Actor topmostActor = (Actor) iter.next();
+                int seq = ActorVisitor.getLastPaintSeqNum(topmostActor);
+
+                while (iter.hasNext()) {
+                    Actor actor = (Actor) iter.next();
+                    int actorSeq = ActorVisitor.getLastPaintSeqNum(actor);
+                    if (actorSeq > seq) {
+                        topmostActor = actor;
+                        seq = actorSeq;
+                    }
+                }
+                
+                lock.readLock().unlock();
+                return topmostActor;
+            }
+        }
+        catch (InterruptedException ie) {}
+
+        return null;
+    }
+
+    /*
+     * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
+     */
+    public void mouseEntered(MouseEvent e)
+    {
+        worldCanvas.requestFocusInWindow();
+    }
+
+    /*
+     * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
+     */
+    public void mouseExited(MouseEvent e)
+    {
+        if (dragActor != null) {
+            dragActorMoved = false;
+            Simulation.getInstance().runLater(new Runnable() {
+                private Actor dragActor = WorldHandler.this.dragActor;
+                private int dragBeginX = WorldHandler.this.dragBeginX;
+                private int dragBeginY = WorldHandler.this.dragBeginY;
+                @Override
+                public void run()
+                {
+                    ActorVisitor.setLocationInPixels(dragActor, dragBeginX, dragBeginY);
+                    repaint();
+                }
+            });
+        }
+    }
+
+    /**
+     * Request a repaints of world
+     */
+    public void repaint()
+    {
+        worldCanvas.repaint();
+    }
+    
+    /**
+     * Request a repaint of the world, and wait (with a timeout) until the repaint actually occurs.
+     */
+    public void repaintAndWait()
+    {
+        worldCanvas.repaint();
+
+        boolean isWorldLocked = lock.isWriteLockedByCurrentThread();
+        
+        synchronized (repaintLock) {
+            // If the world lock is held, as it should be unless this method is called from
+            // a user-created thread, we should unlock it to allow the repaint to occur.
+            if (isWorldLocked) {
+                lock.writeLock().unlock();
+            }
+            
+            // When the repaint actually happens, repainted() will be called, which
+            // sets isRepaintPending false and signals repaintLock.
+            isRepaintPending = true;
+            try {
+                do {
+                    repaintLock.wait(100);
+                } while (isRepaintPending);
+            }
+            catch (InterruptedException ie) {
+                throw new ActInterruptedException();
+            }
+            finally {
+                isRepaintPending = false; // in case our wait interrupted/timed out
+                if (isWorldLocked) {
+                    lock.writeLock().lock();
+                }
+            }
+        }
+    }
+
+    /**
+     * The world has been painted.
+     */
+    public void repainted()
+    {
+        synchronized (repaintLock) {
+            if (isRepaintPending) {
+                isRepaintPending = false;
+                repaintLock.notify();
+            }
+        }
+        Simulation.getInstance().worldRepainted();
+    }
+
+    @Override
+    public void keyTyped(KeyEvent e) {}
+
+    @Override
+    public void keyPressed(KeyEvent e) {}
+
+    @Override
+    public void keyReleased(KeyEvent e)
+    {
+        //TODO: is this really necessary?
+        worldCanvas.requestFocus();
+    }
+
+    /**
+     * Get the world lock, used to control access to the world.
+     */
+    public ReentrantReadWriteLock getWorldLock()
+    {
+        return lock;
+    }
+    
+    /**
+     * Instantiate a new world and do any initialisation needed to activate that
+     * world.
+     * 
+     * @return The new World or null if an error occured
+     */
+    public void instantiateNewWorld()
+    {
+        handlerDelegate.instantiateNewWorld();
+    }
+
+    /**
+     * Notify that construction of a new world has started.
+     * @see #setWorld(World)
+     */
+    public void setInitialisingWorld(World world)
+    {
+        this.initialisingWorld = world;
+    }
+
+    /** 
+     * Removes the current world.
+     */
+    public synchronized void discardWorld()
+    {
+        if(world == null) return;
+        handlerDelegate.discardWorld(world); 
+        final World discardedWorld = world;
+        world = null;
+
+        EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                worldCanvas.setWorld(null);
+                fireWorldRemovedEvent(discardedWorld);
+            }
+        });
+    }
+
+    /**
+     * Check whether a world has been set (via {@link #setWorld()}) since the "world is set" flag was last cleared.
+     */
+    public synchronized boolean checkWorldSet()
+    {
+        return worldIsSet;
+    }
+
+    /**
+     * Clear the "world is set" flag.
+     */
+    public synchronized void clearWorldSet()
+    {
+        worldIsSet = false;
+    }
+
+    /**
+     * Sets a new world.
+     * 
+     * @param world  The new world. Must not be null.
+     */
+    public synchronized void setWorld(final World world)
+    {
+        worldIsSet = true;
+        
+        handlerDelegate.setWorld(this.world, world);
+        mousePollingManager.setWorldLocator(new WorldLocator() {
+            @Override
+            public Actor getTopMostActorAt(MouseEvent e)
+            {
+                Point p = SwingUtilities.convertPoint(e.getComponent(), e.getX(), e.getY(), worldCanvas);
+                return getObject(world, p.x, p.y);
+            }
+
+            @Override
+            public int getTranslatedX(MouseEvent e)
+            {
+                Point p = SwingUtilities.convertPoint(e.getComponent(), e.getX(), e.getY(), worldCanvas);
+                return WorldVisitor.toCellFloor(world, p.x);
+            }
+
+            @Override
+            public int getTranslatedY(MouseEvent e)
+            {
+                Point p = SwingUtilities.convertPoint(e.getComponent(), e.getX(), e.getY(), worldCanvas);
+                return WorldVisitor.toCellFloor(world, p.y);
+            }
+        });
+        this.world = world;
+        
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                if(worldCanvas != null) {
+                    worldCanvas.setWorld(world);
+                }
+                fireWorldCreatedEvent(world);
+            }
+        });
+    }
+
+    /**
+     * Return the currently active world.
+     */
+    public synchronized World getWorld()
+    {
+        if (world == null) {
+            return initialisingWorld;
+        }
+        else {
+            return world;
+        }
+    }
+    
+    /**
+     * Checks if there is a world set.
+     * 
+     * This is not the same as checking if getWorld() is null, because getWorld()
+     * can return a world being initialised.  This method checks if a world has
+     * actually been set.
+     */
+    public synchronized boolean hasWorld()
+    {
+        return world != null;
+    }
+
+    /**
+     * Handle drop of actors. Handles QuickAdd
+     * 
+     * When existing actors are dragged around in the world, that uses drag -- drop is *not* called for those
+     */
+    public boolean drop(Object o, Point p)
+    {
+        final World world = this.world;
+        
+        int maxHeight = WorldVisitor.getHeightInPixels(world);
+        int maxWidth = WorldVisitor.getWidthInPixels(world);
+        final int x = (int) p.getX();
+        final int y = (int) p.getY();
+
+        if (x >= maxWidth || y >= maxHeight || x < 0 || y < 0) {
+            return false;
+        }
+        else if (o instanceof ObjectDragProxy) {
+            // create the real object
+            final ObjectDragProxy to = (ObjectDragProxy) o;
+            to.createRealObject();
+            Simulation.getInstance().runLater(new Runnable() {
+                @Override
+                public void run()
+                {
+                    world.removeObject(to);
+                }
+            });
+            objectDropped = true;
+            return true;
+        }
+        else if (o instanceof Actor && ActorVisitor.getWorld((Actor) o) == null) {
+            // object received from the inspector via the Get button.
+            Actor actor = (Actor) o;
+            addActorAtPixel(actor, x, y);
+            objectDropped = true;
+            return true;
+        }
+        else if (o instanceof Actor) {
+            final Actor actor = (Actor) o;
+            if (ActorVisitor.getWorld(actor) == null) {
+                // Under some strange circumstances the world can be null here.
+                // This can happen in the GridWorld scenario because it
+                // overrides World.addObject().
+                return false;
+            }
+            Simulation.getInstance().runLater(new Runnable() {
+                @Override
+                public void run()
+                {
+                    ActorVisitor.setLocationInPixels(actor, x, y);
+                }
+            });
+            dragActorMoved = true;
+            objectDropped = true;
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+
+    /**
+     * Handle drag on actors that are already in the world.
+     * 
+     * <p>This is called on the Swing event dispatch thread.
+     */
+    public boolean drag(Object o, Point p)
+    {
+        World world = this.world;
+        if (o instanceof Actor && world != null) {
+            int x = WorldVisitor.toCellFloor(world, (int) p.getX() + dragOffsetX);
+            int y = WorldVisitor.toCellFloor(world, (int) p.getY() + dragOffsetY);
+            final Actor actor = (Actor) o;
+            try {
+                int oldX = ActorVisitor.getX(actor);
+                int oldY = ActorVisitor.getY(actor);
+
+                if (oldX != x || oldY != y) {
+                    if (x < WorldVisitor.getWidthInCells(world) && y < WorldVisitor.getHeightInCells(world)
+                            && x >= 0 && y >= 0) {
+                        WriteLock writeLock = lock.writeLock();
+                        // The only reason we would fail to obtain the lock is if a repaint
+                        // is happening at this very instant. That shouldn't be too much of
+                        // a problem; it will mean a slight glitch in the drag, probably not
+                        // noticeable.
+                        if (writeLock.tryLock()) {
+                            ActorVisitor.setLocationInPixels(actor,
+                                    (int) p.getX() + dragOffsetX,
+                                    (int) p.getY() + dragOffsetY);
+                            writeLock.unlock();
+                            dragActorMoved = true;
+                            repaint();
+                        }
+                    }
+                    else {
+                        WriteLock writeLock = lock.writeLock();
+                        if (writeLock.tryLock()) {
+                            ActorVisitor.setLocationInPixels(actor, dragBeginX, dragBeginY);
+                            x = WorldVisitor.toCellFloor(getWorld(), dragBeginX);
+                            y = WorldVisitor.toCellFloor(getWorld(), dragBeginY);
+                            handlerDelegate.actorDragged(actor, x, y);
+                            writeLock.unlock();
+                            
+                            dragActorMoved = false; // Pinged back to where it was
+
+                            repaint();
+                        }
+                        return false;
+                    }
+                }
+            }
+            catch (IndexOutOfBoundsException e) {}
+            catch (IllegalStateException e) {
+                // If World.addObject() has been overridden the actor might not
+                // have been added to the world and we will get this exception
+            }
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+
+    /**
+     * Adds the object where the mouse event occurred.
+     * 
+     * @return true if successful, or false if the mouse event was outside the world bounds.
+     */
+    public synchronized boolean addObjectAtEvent(Actor actor, MouseEvent e)
+    {
+        Component source = (Component) e.getSource();
+        if (source != worldCanvas) {
+            e = SwingUtilities.convertMouseEvent(source, e, worldCanvas);
+        }
+        int xPixel = e.getX();
+        int yPixel = e.getY();
+        return addActorAtPixel(actor, xPixel, yPixel);
+    }
+
+    /**
+     * Add an actor at the given pixel co-ordinates. The co-ordinates are translated
+     * into cell co-ordinates, and the actor is added at those cell co-ordinates, if they
+     * are within the world.
+     * 
+     * @return  true if the Actor was added into the world; false if the co-ordinates were
+     *          outside the world.
+     */
+    private boolean addActorAtPixel(final Actor actor, int xPixel, int yPixel)
+    {
+        final World world = this.world;
+        final int x = WorldVisitor.toCellFloor(world, xPixel);
+        final int y = WorldVisitor.toCellFloor(world, yPixel);
+        if (x < WorldVisitor.getWidthInCells(world) && y < WorldVisitor.getHeightInCells(world)
+                && x >= 0 && y >= 0) {
+            Simulation.getInstance().runLater(new Runnable() {
+                @Override
+                public void run()
+                {
+                    world.addObject(actor, x, y);
+                }
+            });
+            handlerDelegate.addActor(actor, x, y);
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+
+    public void dragEnded(Object o)
+    {
+        if (o instanceof Actor && world != null) {
+            final Actor actor = (Actor) o;
+            Simulation.getInstance().runLater(new Runnable() {
+                @Override
+                public void run()
+                {
+                    world.removeObject(actor);
+                }
+            });
+        }
+    }
+
+    public void dragFinished(Object o)
+    {
+        finishDrag(o);
+    }
+
+    protected void fireWorldCreatedEvent(World newWorld)
+    {
+        // Guaranteed to return a non-null array
+        Object[] listeners = listenerList.getListenerList();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        WorldEvent worldEvent = new WorldEvent(newWorld);
+        for (int i = listeners.length - 2; i >= 0; i -= 2) {
+            if (listeners[i] == WorldListener.class) {
+                ((WorldListener) listeners[i + 1]).worldCreated(worldEvent);
+            }
+        }
+    }
+
+    public void fireWorldRemovedEvent(World discardedWorld)
+    {
+        // Guaranteed to return a non-null array
+        Object[] listeners = listenerList.getListenerList();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        WorldEvent worldEvent = new WorldEvent(discardedWorld);
+        for (int i = listeners.length - 2; i >= 0; i -= 2) {
+            if (listeners[i] == WorldListener.class) {
+                ((WorldListener) listeners[i + 1]).worldRemoved(worldEvent);
+            }
+        }
+    }
+
+    /**
+     * Add a worldListener to listen for when a worlds are created and removed.
+     * Events will be delivered on the GUI event thread.
+     * 
+     * @param l
+     *            Listener to add
+     */
+    public void addWorldListener(WorldListener l)
+    {
+        listenerList.add(WorldListener.class, l);
+    }
+
+    /**
+     * Removes a worldListener.
+     * 
+     * @param l
+     *            Listener to remove
+     */
+    public void removeWorldListener(WorldListener l)
+    {
+        listenerList.remove(WorldListener.class, l);
+    }
+
+    /**
+     * Used to indicate the start of a simulation round. For use in the
+     * collision checker. Called from the simulation thread.
+     * 
+     * @see greenfoot.collision.CollisionChecker#startSequence()
+     */
+    public void startSequence()
+    {
+        // Guard against world getting nulled concurrently:
+        World world = this.world;
+        if (world != null) {
+            WorldVisitor.startSequence(world);
+            mousePollingManager.newActStarted();
+        }
+    }
+
+    public WorldCanvas getWorldCanvas()
+    {
+        return worldCanvas;
+    }
+
+    public EventListenerList getListenerList()
+    {
+        return listenerList;
+    }
+
+    /**
+     * Method that cleans up after a drag, and re-enables the worldhandler to
+     * receive events. It also puts the object back in its original place if it
+     * was not dropped.
+     */
+    public void finishDrag(Object o)
+    {
+        // if the operation was cancelled, add the object back into the
+        // world at its original position
+        if (!objectDropped && o instanceof Actor) {
+            final Actor actor = (Actor) o;
+            objectDropped = true;
+            dragActorMoved = false;
+            Simulation.getInstance().runLater(new Runnable() {
+                @Override
+                public void run()
+                {
+                    ActorVisitor.setLocationInPixels(actor, dragBeginX, dragBeginY);
+                }
+            });
+        }
+    }
+
+    public void simulationChanged(SimulationEvent e)
+    {
+        inputManager.simulationChanged(e);
+    }
+
+    /**
+     * Get the object bench if it exists. Otherwise return null.
+     */
+    public ObjectBenchInterface getObjectBench()
+    {
+        if(handlerDelegate instanceof ObjectBenchInterface) {
+            return (ObjectBenchInterface) handlerDelegate;
+        }
+        else {
+            return null;
+        }
+    }
+    
+    public InputManager getInputManager()
+    {
+        return inputManager;
+    }
+
+    @Override
+    public void mouseDragged(MouseEvent e)
+    {
+        if (SwingUtilities.isLeftMouseButton(e)) {
+            objectDropped = false;
+            drag(dragActor, e.getPoint());
+        }
+    }
+
+    @Override
+    public void mouseMoved(MouseEvent e)
+    {
+        objectDropped = false;
+        if (dragActor != null) {
+            drag(dragActor, e.getPoint());
+        }
+        handlerDelegate.mouseMoved(e);
+    }
+
+    /**
+     * Get a snapshot of the currently instantiated world or null if no world is
+     * instantiated.
+     * 
+     * Must be called on the EDT.
+     */
+    public BufferedImage getSnapShot()
+    {
+        if (world == null) {
+            return null;
+        }
+
+        WorldCanvas canvas = getWorldCanvas();
+        BufferedImage img = GraphicsUtilities.createCompatibleImage(WorldVisitor.getWidthInPixels(world), WorldVisitor
+                .getHeightInPixels(world));
+        Graphics2D g = img.createGraphics();
+        g.setColor(canvas.getBackground());
+        g.fillRect(0, 0, img.getWidth(), img.getHeight());
+        canvas.paintBackground(g);
+
+        int timeout = READ_LOCK_TIMEOUT;
+        // We need to sync when calling the paintObjects
+        try {
+            if (lock.readLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {
+                try {
+                    canvas.paintObjects(g);
+                }
+                finally {
+                    lock.readLock().unlock();
+                }
+            }
+        }
+        catch (InterruptedException e) {
+        }
+        return img;
+    }
+
+    @Override
+    public void listeningEnded()
+    {
+    }
+
+    @Override
+    public void listeningStarted(Object obj)
+    {
+        World world = this.world;
+        
+        // If the obj is not null, it means we have to activate the dragging of that object.
+        if (world != null && obj != null && obj != dragActor && obj instanceof Actor) {
+            Actor actor = (Actor) obj;
+            int ax = ActorVisitor.getX(actor);
+            int ay = ActorVisitor.getY(actor);
+            int x = (int) Math.floor(WorldVisitor.getCellCenter(world, ax));
+            int y = (int) Math.floor(WorldVisitor.getCellCenter(world, ay));
+            Point p = new Point(x, y);
+            startDrag(actor, p, world);
+        }
+    }
+    
+    /**
+     * This is a hook called by the World whenever an actor gets added to it. When running in the IDE,
+     * this allows names to be assigned to the actors for interaction recording purposes.
+     */
+    public void objectAddedToWorld(Actor object)
+    {
+        handlerDelegate.objectAddedToWorld(object);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/WorldInvokeListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/WorldInvokeListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..8934ce00ac4699819a63201f5fece1c3ee72eebf
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/core/WorldInvokeListener.java
@@ -0,0 +1,271 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.core;
+
+import greenfoot.Actor;
+import greenfoot.ObjectTracker;
+import greenfoot.World;
+import greenfoot.gui.input.mouse.LocationTracker;
+import greenfoot.localdebugger.LocalDebugger;
+import greenfoot.localdebugger.LocalObject;
+import greenfoot.record.InteractionListener;
+
+import java.awt.event.MouseEvent;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.rmi.RemoteException;
+
+import javax.swing.JFrame;
+
+import rmiextension.wrappers.RObject;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugmgr.CallHistory;
+import bluej.debugmgr.ExpressionInformation;
+import bluej.debugmgr.Invoker;
+import bluej.debugmgr.InvokerCompiler;
+import bluej.debugmgr.ResultWatcher;
+import bluej.debugmgr.ValueCollection;
+import bluej.debugmgr.inspector.InspectorManager;
+import bluej.debugmgr.inspector.ResultInspector;
+import bluej.debugmgr.objectbench.InvokeListener;
+import bluej.debugmgr.objectbench.ObjectBenchInterface;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.Debug;
+import bluej.views.CallableView;
+import bluej.views.ConstructorView;
+import bluej.views.MethodView;
+
+/**
+ * A listener for interactive method/constructor invocations.
+ * 
+ * <p>Invocations occur on either an object (instance methods) or a class
+ * (static methods and constructors).
+ * 
+ * <p>A method call dialog is displayed, if necessary, to ask for parameters, and 
+ * an inspector window for the result (method call). For constructed objects,
+ * the greenfoot object instantiation listener is notified.
+ * 
+ * <p>When a method call has been executed the world is repainted.
+ * 
+ * @author Davin McCall
+ */
+public class WorldInvokeListener
+    implements InvokeListener
+{
+    /** The object on which we are listening. Null if we are listening on a class. */
+    private Object obj;
+    private RObject rObj;
+    private Class<?> cl;
+    private InspectorManager inspectorManager;
+    private ObjectBenchInterface objectBench;
+    private GProject project;
+    private JFrame frame;
+    private InteractionListener interactionListener;
+    
+    /**
+     * Create a WorldInvokeListener for listening to method invocations on an object.
+     */
+    public WorldInvokeListener(JFrame frame, Object obj, ObjectBenchInterface bench,
+            InspectorManager inspectorManager, InteractionListener interactionListener, GProject project)
+    {
+        this.objectBench = bench;
+        this.obj = obj;
+        this.inspectorManager = inspectorManager;
+        this.interactionListener = interactionListener;
+        this.project = project;
+        this.frame = frame;
+    }
+    
+    /**
+     * Create a WorldInvokeListener for listening to static method and constructor
+     * invocations.
+     */
+    public WorldInvokeListener(JFrame frame, Class<?> cl, ObjectBenchInterface bench,
+            InspectorManager inspectorManager, InteractionListener interactionListener, GProject project)
+    {
+        this.objectBench = bench;
+        this.cl = cl;
+        this.project = project;
+        this.inspectorManager = inspectorManager;
+        this.interactionListener = interactionListener;
+        this.frame = frame;
+    }
+    
+    /**
+     * Get an invoker instance to deal with invocation of the given method or
+     * constructor.
+     */
+    private Invoker getInvokerInstance(final CallableView callable)
+    {
+        if (obj != null) {
+            try {
+                rObj = ObjectTracker.getRObject(obj);
+            }
+            catch (RemoteException e) {
+                Debug.reportError("Error getting remote object", e);
+                return null;
+            }
+        }
+
+        ValueCollection objectBenchVars = ObjectTracker.getObjects();
+        Debugger debugger = new LocalDebugger();
+        CallHistory ch = GreenfootMain.getInstance().getCallHistory();
+        final MouseEvent event = LocationTracker.instance().getMouseButtonEvent();
+        try {
+            final String instanceName = rObj != null ? rObj.getInstanceName() : cl.getName();
+            ResultWatcher watcher = new ResultWatcher() {
+                @Override
+                public void beginCompile()
+                {
+                }
+                
+                @Override
+                public void beginExecution(InvokerRecord ir)
+                {
+                    interactionListener.beginCallExecution(callable);
+                    WorldHandler.getInstance().clearWorldSet();
+                }
+                
+                @Override
+                public void putError(String message, InvokerRecord ir)
+                {
+                }
+                
+                @Override
+                public void putException(ExceptionDescription exception,
+                        InvokerRecord ir)
+                {
+                }
+                
+                @Override
+                public void putResult(DebuggerObject result, String name,
+                        InvokerRecord ir)
+                {
+                    JavaType[] paramTypes = callable.getParamTypes(false);
+                    if (result instanceof LocalObject) {
+                        Object o = ((LocalObject) result).getObject();
+
+                        if (callable instanceof MethodView) {
+                            MethodView mv = (MethodView) callable;
+                            if (! mv.isVoid()) {
+                                // Display a result inspector for the method result
+                                ExpressionInformation ei = new ExpressionInformation((MethodView) callable, instanceName);
+                                ei.setArgumentValues(ir.getArgumentValues());
+                                ResultInspector ri = inspectorManager.getResultInspectorInstance(result,
+                                        instanceName, null, null, ei, GreenfootMain
+                                        .getInstance().getFrame());
+                                ri.setVisible(true);
+                            }
+                        }
+                        else {
+                            WorldHandler worldHandler = WorldHandler.getInstance();
+                            if(o instanceof Actor) {
+                                interactionListener.createdActor(o, ir.getArgumentValues(), paramTypes);
+                                worldHandler.addObjectAtEvent((Actor) o, event);
+                                worldHandler.repaint();
+                            }
+                            else if(o instanceof greenfoot.World) {
+                                interactionListener.worldConstructed(o);
+                                if (! worldHandler.checkWorldSet()) {
+                                    ImageCache.getInstance().clearImageCache();
+                                    worldHandler.setWorld((World) o);
+                                }
+                            }
+                            else {
+                                inspectorManager.getInspectorInstance(result, "result", null, null,
+                                        GreenfootMain.getInstance().getFrame());
+                            }
+                        }
+                    }
+
+                    update();
+                    if (callable instanceof MethodView) {
+                        MethodView m = (MethodView) callable;
+                        interactionListener.methodCall(obj, instanceName, m.getName(), ir.getArgumentValues(), paramTypes);
+                    }
+                }
+
+                @Override
+                public void putVMTerminated(InvokerRecord ir)
+                {
+                    // What, the VM was terminated? *this* VM? then how am I still executing...?
+                }
+            };
+            InvokerCompiler compiler = project.getDefaultPackage().getCompiler();
+            
+            // Find project character set
+            String csName = project.getProjectProperties().getString("project.charset");
+            if (csName == null) {
+                csName = "UTF-8";
+            }
+            Charset cs;
+            try {
+                cs = Charset.forName(csName);
+            }
+            catch (IllegalCharsetNameException icsne) {
+                cs = Charset.forName("UTF-8");
+            }
+            
+            return new Invoker(frame, callable, watcher, project.getDir(), "", project.getDir().getPath(),
+                    ch, objectBenchVars, objectBench, debugger, compiler, instanceName, cs);
+        }
+        catch (RemoteException re) {
+            Debug.reportError("Error getting invoker instance", re);
+            return null;
+        }
+    }
+
+    /**
+     * Interactively call a method. If necessary, a dialog is presented to ask for
+     * parameters; then the object is constructed.
+     */
+    @Override
+    public void executeMethod(MethodView mv)
+    {
+        Invoker invoker = getInvokerInstance(mv);
+        invoker.invokeInteractive();
+    }
+
+    /**
+     * Interactively call a constructor. If necessary, a dialog is presented to ask for
+     * parameters; then the object is constructed. The ActorInstantiationListener is
+     * notified if an object is created successfully; for an actor, this will result in
+     * the actor being inserted into the world.
+     */
+    @Override
+    public void callConstructor(ConstructorView cv)
+    {
+        Invoker invoker = getInvokerInstance(cv);
+        invoker.invokeInteractive();
+    }
+
+    private void update()
+    {
+        WorldHandler worldHandler = WorldHandler.getInstance();
+        if(worldHandler != null) {
+            worldHandler.repaint();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/ActorInstantiationListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/ActorInstantiationListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f73c6dd58854d54661094317d3f32725a0da3d6
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/ActorInstantiationListener.java
@@ -0,0 +1,60 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import greenfoot.Actor;
+import greenfoot.core.WorldHandler;
+
+import java.awt.event.MouseEvent;
+
+/**
+ * Listens for new instances of GrenfootObjects
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: ActorInstantiationListener.java,v 1.6 2004/11/18
+ *          09:43:52 polle Exp $
+ */
+public class ActorInstantiationListener
+{
+    private WorldHandler worldHandler;
+    
+    public ActorInstantiationListener(WorldHandler worldHandler)
+    {
+        super();
+        this.worldHandler = worldHandler;
+    }
+
+    /**
+     * Notification for when an object has been created.
+     * @param realObject  The newly instantiated object
+     * @param e           The mouse event used to locate where to position the actor
+     *                    (if the object is an actor)
+     */
+    public void localObjectCreated(Object realObject, MouseEvent e)
+    {
+        if(realObject instanceof Actor) {
+            worldHandler.addObjectAtEvent((Actor) realObject, e);
+            worldHandler.repaint();
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/CompileListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/CompileListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..29a36f1fffceef7d8c3c26fccf62cad3797c1c56
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/CompileListener.java
@@ -0,0 +1,43 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import rmiextension.wrappers.event.RCompileEvent;
+
+/**
+ * Listens for compile events in greenfoot.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: CompileListener.java 6725 2009-09-19 04:55:02Z davmac $
+ */
+public interface CompileListener
+{
+    public void compileStarted(RCompileEvent event);
+
+    public void compileError(RCompileEvent event);
+
+    public void compileWarning(RCompileEvent event);
+
+    public void compileSucceeded(RCompileEvent event);
+
+    public void compileFailed(RCompileEvent event);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/CompileListenerForwarder.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/CompileListenerForwarder.java
new file mode 100644
index 0000000000000000000000000000000000000000..6636f22e83b2cdb2a1662acdfdf0d9e25083365a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/CompileListenerForwarder.java
@@ -0,0 +1,118 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import java.rmi.RemoteException;
+import java.util.Iterator;
+import java.util.List;
+
+import rmiextension.wrappers.event.RCompileEvent;
+import rmiextension.wrappers.event.RCompileListenerImpl;
+
+/**
+ * Class that forwards compile events to all the compile listeners registered
+ * with Greenfoot. This is for performance reasons. Many objects are interested
+ * in compile events, and if all these should use remote listeners it might be
+ * to heavy. Consider using non remote compile events as well.
+ * 
+ * <p>Another feature of this class is that the events will be delegated to the compileListeners in
+ * the order in which they appear in the list.
+ * 
+ * @author Poul Henriksen
+ */
+public class CompileListenerForwarder extends RCompileListenerImpl
+{
+    private List<? extends CompileListener> compileListeners;
+
+    /**
+     * Create a new forwarder that sends events to the list of listeners in the
+     * order in which they appear in the list. The first listener in the list
+     * will get the event first, and so on.
+     * 
+     */
+    public CompileListenerForwarder(List<? extends CompileListener> compileListeners)
+        throws RemoteException
+    {
+        this.compileListeners = compileListeners;
+    }
+
+    public void compileStarted(RCompileEvent event)
+        throws RemoteException
+    {
+        synchronized (compileListeners) {
+            for (Iterator<? extends CompileListener> iter = compileListeners.iterator(); iter.hasNext();) {
+                CompileListener element = iter.next();
+                element.compileStarted(event);
+            }
+        }
+    }
+
+    public void compileError(RCompileEvent event)
+        throws RemoteException
+    {
+        synchronized (compileListeners) {
+            for (Iterator<? extends CompileListener> iter = compileListeners.iterator(); iter.hasNext();) {
+                CompileListener element = iter.next();
+                element.compileError(event);
+            }
+        }
+    }
+
+    public void compileWarning(RCompileEvent event)
+        throws RemoteException
+    {
+        synchronized (compileListeners) {
+            for (Iterator<? extends CompileListener> iter = compileListeners.iterator(); iter.hasNext();) {
+                CompileListener element = iter.next();
+                element.compileWarning(event);
+            }
+        }
+    }
+
+    public void compileSucceeded(RCompileEvent event)
+        throws RemoteException
+    {
+        CompileListener [] listenersCopy;
+        
+        synchronized (compileListeners) {
+            listenersCopy = new CompileListener[compileListeners.size()];
+            listenersCopy = compileListeners.toArray(listenersCopy);
+        }
+        
+        for (int i = 0; i < listenersCopy.length; i++) {
+            CompileListener listener = listenersCopy[i];
+            listener.compileSucceeded(event);
+        }
+    }
+
+    public void compileFailed(RCompileEvent event)
+        throws RemoteException
+    {
+        synchronized (compileListeners) {
+            for (Iterator<? extends CompileListener> iter = compileListeners.iterator(); iter.hasNext();) {
+                CompileListener element = iter.next();
+                element.compileFailed(event);
+            }
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/PublishEvent.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/PublishEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..9738ebb2580e8a1ed7e527ca6025387819e90364
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/PublishEvent.java
@@ -0,0 +1,100 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import bluej.Config;
+
+/**
+ * Event from publishing a scenario.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class PublishEvent
+{
+    /** The publish returned an error */
+    public final static int ERROR = 0;
+
+    /**
+     * A status message has been returned. For now, receiving a status message
+     * means that it was a successful submit.
+     */
+    public final static int STATUS = 1;
+
+    /**
+     * Some upload progress has been made. Use getBytes() to find out how
+     * much.
+     */
+    public final static int PROGRESS = 2;
+    
+    private String msg;
+    private int bytes;
+
+    private int type;
+
+    /**
+     * Construct a PublishEvent for an "upload complete" event.
+     * @param type The event type.
+     */
+    public PublishEvent(int type)
+    {
+        this.type = type;
+    }
+    
+    public PublishEvent(String msg, int type)
+    {
+        this.msg = msg;
+        this.type = type;
+    }
+
+    public PublishEvent(int progress, int type)
+    {
+        this.type = type;
+        this.bytes = progress;
+    }
+    
+    public String getMessage()
+    {
+        return msg;
+    }
+    
+    public int getBytes()
+    {
+        return bytes;
+    }
+
+    public int getType()
+    {
+        return type;
+    }
+
+    public String toString()
+    {
+        String s = super.toString() + " [";
+        if (type == ERROR)
+            s += Config.getString("publish.event.error");
+        else if (type == STATUS)
+            s += Config.getString("publish.event.status");
+        s += msg + "]";
+        return s;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/PublishListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/PublishListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..de04bc24ac98034d76002beaf8e0fba86ca5beab
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/PublishListener.java
@@ -0,0 +1,53 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import java.util.EventListener;
+
+/**
+ * Listener for recieving events when publishing a scenario to a website.
+ * 
+ * @author Poul Henriksen
+ */
+public interface PublishListener extends EventListener
+{
+    /**
+     * The upload completed successfully.
+     */
+    public void uploadComplete(PublishEvent event);
+    
+    /**
+     * An error occurred. The upload will not complete.
+     */
+    public void errorRecieved(PublishEvent event);
+    
+    /**
+     * Some upload progress has been made.
+     */
+    public void progressMade(PublishEvent event);
+    
+    /**
+     * Proxy authentication details are required.
+     * @return a 2-element array containing a username/password pair, or null if the user cancels.
+     */
+    public String[] needProxyAuth();
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/SimulationEvent.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/SimulationEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..722d4c088d24322b9f07518710fc67155125046e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/SimulationEvent.java
@@ -0,0 +1,100 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+/*
+ * Created on Oct 7, 2003
+ */
+package greenfoot.event;
+
+import java.util.EventObject;
+
+/**
+ * A simulation event
+ * 
+ * @author Poul Henriksen
+ */
+public class SimulationEvent extends EventObject
+{
+    /** The simulation started running */
+    public final static int STARTED = 0;
+    
+    /** The simulation was paused */
+    public final static int STOPPED = 1;
+    
+    /** The simulation speed changed */
+    public final static int CHANGED_SPEED = 2;   
+    
+    /** 
+     * The simulation was stopped and cannot be restarted
+     * until a STOPPED event is received.
+     */
+    public final static int DISABLED = 3; 
+
+    /** The simulation thread is paused because it hit a breakpoint,
+     *  or the debugger has otherwise stopped its execution.
+     *  
+     *  Obviously, this event will not be processed in the
+     *  Simulation thread.
+     */
+    public final static int DEBUGGER_PAUSED = 5;
+    
+    /** The opposite of DEBUGGER_PAUSED; the debugger has set
+     * the Simulation going again.
+     * 
+     * Like DEBUGGER_PAUSED, this will not be processed in the Simulation
+     * thread.
+     */
+    public final static int DEBUGGER_RESUMED = 6;
+    
+
+    private int type;
+
+    public SimulationEvent(Object source, int type)
+    {
+        super(source);
+        this.type = type;
+    }
+
+    public int getType()
+    {
+        return type;
+    }
+    
+    @Override
+    public String toString()
+    {
+        switch (type) {
+            case STARTED:
+                return "STARTED";
+            case STOPPED:
+                return "STOPPED";
+            case CHANGED_SPEED:
+                return "CHANGED_SPEED";
+            case DISABLED:
+                return "DISABLED";
+            case DEBUGGER_PAUSED:
+                return "DEBUGGER_PAUSED";
+            case DEBUGGER_RESUMED:
+                return "DEBUGGER_RESUMED";
+        }
+        return super.toString();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/SimulationListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/SimulationListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..38f012769cafc3bc4f262832486f707bbe408cb9
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/SimulationListener.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import java.util.EventListener;
+
+/**
+ * Listener for simulation events.
+ * 
+ * <p>Events may be dispatched from the simulation thread and must be dealt with
+ * quickly.
+ * 
+ * @author Poul Henriksen
+ */
+public interface SimulationListener
+    extends EventListener
+{
+    /**
+     * The simulation state changed or a simulation event occurred. The simulation may have
+     * stopped, started, changed enabled state, begun a new act round, etc.
+     */
+    public void simulationChanged(SimulationEvent e);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/SimulationUIListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/SimulationUIListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b62214dac0932cfbdf5f6e1c5996625aeddf882
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/SimulationUIListener.java
@@ -0,0 +1,35 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+/**
+ * A listener for actions on the UI controlling the simulation.
+ * 
+ * @author Davin McCall
+ */
+public interface SimulationUIListener
+{
+    /**
+     * The simulation is about to begin, either for a single round ("act") or continuously ("run").
+     */
+    public void simulationActive();
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredKeyAdapter.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredKeyAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..b63cf7cad7c7b885213a3dff089a586ec09c7594
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredKeyAdapter.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+/*
+ * Created on Apr 22, 2008
+ */
+package greenfoot.event;
+
+import java.awt.event.KeyEvent;
+
+public class TriggeredKeyAdapter
+    implements TriggeredKeyListener
+{
+
+    public void keyPressed(KeyEvent e)
+    {
+
+    }
+
+    public void keyReleased(KeyEvent e)
+    {
+
+    }
+
+    public void keyTyped(KeyEvent e)
+    {
+
+    }
+
+    public void listeningEnded()
+    {
+
+    }
+
+    public void listeningStarted(Object obj)
+    {
+
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredKeyListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredKeyListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..c7fd0a1295896f4f1aaad00419d5e4569a968a38
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredKeyListener.java
@@ -0,0 +1,35 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import java.awt.event.KeyListener;
+
+/**
+ * Interface for classes that wants to be able to receive KeyEvents from the InputManager.
+ * 
+ * @author Poul Henriksen
+ */
+public interface TriggeredKeyListener
+    extends KeyListener, TriggeredListener
+{
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..b65fe5849bdc2393616c0f6c9f09a1b6aca1e836
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredListener.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+/**
+ * Interface for classes that wants to be able to receive events from the InputManager.
+ * 
+ * <p>You should not use this interface directly, but rather one of the sub interfaces.
+ * 
+ * @see TriggeredKeyListener 
+ * @see TriggeredMouseListener
+ * @see TriggeredMouseMotionListener
+ * 
+ * @author Poul Henriksen
+ */
+public interface TriggeredListener
+{
+    /**
+     * Fired when this listener will start receiving events.
+     * 
+     * @param obj Optional object to be passed to the listener. If a state change occurred
+     *            due to an object being constructed, this will be a reference to the constructed object. 
+     *            Can otherwise be null.
+     */
+    public void listeningStarted(Object obj);
+
+    /**
+     * Fired when this event will stop receiving events.
+     * 
+     */
+    public void listeningEnded();
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseAdapter.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1e8aded8348a22762e2e9a7c821e2e34df093aa
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseAdapter.java
@@ -0,0 +1,75 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+/*
+ * Created on Apr 22, 2008
+ */
+package greenfoot.event;
+
+import java.awt.event.MouseEvent;
+
+public class TriggeredMouseAdapter
+    implements TriggeredMouseListener
+{
+
+    public void mouseClicked(MouseEvent e)
+    {
+     
+
+    }
+
+    public void mouseEntered(MouseEvent e)
+    {
+     
+
+    }
+
+    public void mouseExited(MouseEvent e)
+    {
+     
+
+    }
+
+    public void mousePressed(MouseEvent e)
+    {
+     
+
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+     
+
+    }
+
+    public void listeningEnded()
+    {
+     
+
+    }
+
+    public void listeningStarted(Object obj)
+    {
+     
+
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff8c943a6af57b7a2442e0d65fc330372d8627e7
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseListener.java
@@ -0,0 +1,36 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+
+package greenfoot.event;
+
+import java.awt.event.MouseListener;
+
+/**
+ * Interface for classes that wants to be able to receive MouseEvents from the InputManager.
+ * 
+ * @author Poul Henriksen
+ */
+public interface TriggeredMouseListener
+    extends MouseListener, TriggeredListener
+{
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseMotionAdapter.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseMotionAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..e20a71dc9e4f38c229d7d1fff9e3de3fccf7c84e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseMotionAdapter.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+/*
+ * Created on Apr 22, 2008
+ */
+package greenfoot.event;
+
+import java.awt.event.MouseEvent;
+
+public class TriggeredMouseMotionAdapter
+    implements TriggeredMouseMotionListener
+{
+
+    public void mouseDragged(MouseEvent e)
+    {
+     
+
+    }
+
+    public void mouseMoved(MouseEvent e)
+    {
+     
+
+    }
+
+    public void listeningEnded()
+    {
+    
+
+    }
+
+    public void listeningStarted(Object obj)
+    {
+    
+
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseMotionListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseMotionListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..584fb60024255f810ff8c6b34d968fa40b614a27
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/TriggeredMouseMotionListener.java
@@ -0,0 +1,35 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import java.awt.event.MouseMotionListener;
+
+/**
+ * Interface for classes that wants to be able to receive MouseMotionEvents from the InputManager.
+ * 
+ * @author Poul Henriksen
+ */
+public interface TriggeredMouseMotionListener
+    extends MouseMotionListener, TriggeredListener
+{
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/ValidityEvent.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/ValidityEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..7856b8e9576a2137867084598b91d0fdb8fd9a7d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/ValidityEvent.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import java.util.EventObject;
+
+/**
+ * Event used when something changes from being valid to invalid or vice versa.
+ * 
+ * @author Poul Henriksen
+ */
+public class ValidityEvent extends EventObject
+{
+    private String reason;
+
+    /**
+     * Create a new event.
+     * 
+     * @param source
+     *            The source of the event.
+     * @param reason
+     *            The reason for the change of validity.
+     */
+    public ValidityEvent(Object source, String reason)
+    {
+        super(source);
+        this.reason = reason;
+    }
+
+    /**
+     * Get the reason why this event was created. Typically a message explaining
+     * why a it is not valid.
+     */
+    public String getReason()
+    {
+        return reason;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/ValidityListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/ValidityListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..6eaf1a38f6e1d657da001f05a8e95f4f755a442b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/ValidityListener.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import java.util.EventListener;
+
+/**
+ * Listener to be notified when something changes from a valid state to invalid or vice versa.
+ * 
+ * @author Poul Henriksen
+ */
+public interface ValidityListener extends EventListener
+{
+    /**
+     * Change from invalid to valid.
+     */
+    public void changedToValid(ValidityEvent e);
+    
+    /**
+     * Change from valid to invalid.
+     */
+    public void changedToInvalid(ValidityEvent e);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/WorldEvent.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/WorldEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a418cde687be9ee3ed3b2272588b4b83f35772f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/WorldEvent.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import greenfoot.World;
+
+/**
+ * A world event, fired when a world is created or removed.
+ * 
+ * @author Poul Henriksen
+ */
+public class WorldEvent
+{
+    private final World world;
+
+    /**
+     * Construct a world event for the given world.
+     * @param world  The world which was created or removed (non-null).
+     */
+    public WorldEvent(World world)
+    {
+        this.world = world;
+    }
+    
+    /**
+     * Get the world associated with this event.
+     */
+    public World getWorld()
+    {
+        return world;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/WorldListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/WorldListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..e635bdb57b251328dfbb594912ec44c07e5047f7
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/event/WorldListener.java
@@ -0,0 +1,43 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.event;
+
+import java.util.EventListener;
+
+/**
+ * Listener to recieve notifcations when worlds are created and removed.
+ * 
+ * @author Poul Henriksen
+ */
+public interface WorldListener
+    extends EventListener
+{
+    /**
+     * Called when a new world is created and shown.
+     */
+    public void worldCreated(WorldEvent e);
+
+    /**
+     * Called when a world is removed.
+     */
+    public void worldRemoved(WorldEvent e);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/Exporter.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/Exporter.java
new file mode 100644
index 0000000000000000000000000000000000000000..efb04fe3f7ea1b21486ee4ac5740c574c2581ef0
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/Exporter.java
@@ -0,0 +1,499 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+/*
+ * Class Exporter manages the various possible export functions, such as writing 
+ * jar files or publishing to the scenario web server.
+ *
+ * The exporter is a singleton
+ *
+ * @author Michael Kolling
+ */
+
+package greenfoot.export;
+
+import greenfoot.core.GProject;
+import greenfoot.core.WorldHandler;
+import greenfoot.event.PublishEvent;
+import greenfoot.event.PublishListener;
+import greenfoot.export.mygame.MyGameClient;
+import greenfoot.export.mygame.ScenarioInfo;
+import greenfoot.gui.WorldCanvas;
+import greenfoot.gui.export.ExportAppPane;
+import greenfoot.gui.export.ExportDialog;
+import greenfoot.gui.export.ExportPublishPane;
+import greenfoot.gui.export.ExportWebPagePane;
+import greenfoot.gui.export.ProxyAuthDialog;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.UnknownHostException;
+import java.util.Set;
+
+import javax.imageio.ImageIO;
+import javax.swing.SwingUtilities;
+
+import bluej.Boot;
+import bluej.Config;
+import bluej.pkgmgr.Project;
+
+public class Exporter implements PublishListener
+{
+    private static final String GREENFOOT_CORE_JAR = getGreenfootCoreJar();
+    private static final String GALLERY_SHARED_JARS = "sharedjars/";
+    
+    private static String getGreenfootCoreJar()
+    {
+        // The core jar filename doesn't need to include the API internal version increment.
+        String coreJar = "Greenfoot-core-";
+        int lastDot = Boot.GREENFOOT_API_VERSION.lastIndexOf('.');
+        coreJar += Boot.GREENFOOT_API_VERSION.substring(0, lastDot) + ".jar";
+        return coreJar;
+    }
+    
+    private static Exporter instance;
+    
+    public static synchronized Exporter getInstance()
+    {
+        if(instance == null) {
+            instance = new Exporter();
+        }
+        return instance;
+    }
+    
+    private File tmpJarFile;
+    private File tmpImgFile;
+    private File tmpZipFile;
+    private MyGameClient webPublisher;
+    private ExportDialog dlg;
+    
+    /**
+     * Creates a new instance of Exporter.
+     */
+    public Exporter() { }
+    
+   /**
+     * Publish this scenario to the web server.
+     */
+    public void publishToWebServer(GProject project, ExportPublishPane pane, ExportDialog dlg)
+    {
+        this.dlg = dlg;
+        dlg.setProgress(true, Config.getString("export.progress.bundling"));
+        
+        //Create temporary jar        
+        try {
+            tmpJarFile = File.createTempFile("greenfoot", ".jar", null);
+            //make sure it is deleted on exit (should be deleted right after the publish finish - but just in case...)
+            tmpJarFile.deleteOnExit();     
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+            return;
+        }
+        File exportDir = tmpJarFile.getParentFile();
+        String jarName = tmpJarFile.getName();
+        
+        String hostAddress = Config.getPropString("greenfoot.gameserver.address", "http://www.greenfoot.org/");
+        if (! hostAddress.endsWith("/")) {
+            hostAddress += "/";
+        }        
+        
+        String worldClass = project.getLastWorldClassName();
+        
+        boolean  lockScenario = pane.lockScenario();
+        
+        JarCreator jarCreator = new JarCreator(project, exportDir, jarName, worldClass, lockScenario, true);            
+        
+        // do not include source
+        jarCreator.includeSource(false);
+       
+        // Add the Greenfoot standalone classes as a separate external jar
+        jarCreator.addToClassPath(hostAddress + GALLERY_SHARED_JARS + GREENFOOT_CORE_JAR);   
+       
+        // Add 3rd party libraries used by Greenfoot.      
+        Set<File> thirdPartyLibs = GreenfootUtil.get3rdPartyLibs();
+        for (File lib : thirdPartyLibs) {
+            jarCreator.addToClassPath(hostAddress + GALLERY_SHARED_JARS + lib.getName());  
+        }
+        
+        // Extra entries for the manifest
+        jarCreator.putManifestEntry("title", pane.getTitle());
+        
+        jarCreator.putManifestEntry("short-description", pane.getShortDescription());
+        jarCreator.putManifestEntry("description", pane.getDescription());
+        jarCreator.putManifestEntry("url", pane.getURL());
+
+        jarCreator.putManifestEntry("greenfoot-version", Boot.GREENFOOT_VERSION);
+        jarCreator.putManifestEntry("java-version", System.getProperty("java.version"));
+        jarCreator.putManifestEntry("java-vm-name", System.getProperty("java.vm.name"));
+        jarCreator.putManifestEntry("java-vm-version", System.getProperty("java.vm.version"));
+        jarCreator.putManifestEntry("java-vm-vendor", System.getProperty("java.vm.vendor"));
+        jarCreator.putManifestEntry("os-name", System.getProperty("os.name"));
+        jarCreator.putManifestEntry("os-version", System.getProperty("os.version"));
+        jarCreator.putManifestEntry("os-arch", System.getProperty("os.arch"));
+        jarCreator.putManifestEntry("java-home", System.getProperty("java.home"));        
+        
+        Dimension size = getSize(!lockScenario);
+        jarCreator.putManifestEntry("width", "" + size.width);
+        jarCreator.putManifestEntry("height","" + size.height);
+
+        // Make sure the current properties are saved before they are exported.
+        project.getProjectProperties().save();
+        
+        jarCreator.create();
+            
+        // Build zip with source code if needed
+        if(pane.includeSourceCode()) { 
+            //Create temporary zip file for the source code        
+            try {
+                tmpZipFile = File.createTempFile("greenfootSource", ".zip", null);
+                //make sure it is deleted on exit (should be deleted right after the publish finish - but just in case...)
+                tmpZipFile.deleteOnExit();     
+            }
+            catch (IOException e) {
+                e.printStackTrace();
+                return;
+            }
+            String zipName = tmpZipFile.getName();  
+            JarCreator zipCreator = new JarCreator(project, exportDir, zipName);            
+            zipCreator.create();
+        }
+                  
+        // Create image file     
+        if (!pane.keepSavedScenarioScreenshot()){
+            String formatName = "png";
+            try {
+                tmpImgFile = File.createTempFile("greenfoot", "." + formatName, null);
+                BufferedImage img = pane.getImage();
+                ImageIO.write(img, formatName, tmpImgFile);
+                // make sure it is deleted on exit (should be deleted right after
+                // the publish finish - but just in case...)
+                tmpImgFile.deleteOnExit();              
+            }
+            catch (IOException e) {
+                e.printStackTrace();
+                return;
+            }
+        }
+        
+        String login = pane.getUserName();
+        String password = pane.getPassword();     
+        String scenarioName = pane.getTitle();
+        if(scenarioName != null && scenarioName.length() < 1) {
+            scenarioName = "NO_NAME";
+        }       
+        
+        
+        if(webPublisher == null) {
+            webPublisher = new MyGameClient(this);
+        }
+        
+        dlg.setProgress(true, Config.getString("export.progress.publishing"));
+        try {
+            ScenarioInfo info = new ScenarioInfo();
+            info.setTitle(scenarioName);
+            info.setShortDescription(pane.getShortDescription());
+            info.setUpdateDescription(pane.getUpdateDescription());
+            info.setLongDescription(pane.getDescription());
+            if (pane.isUpdate()){
+                info.setUpdate(true);
+            }
+            info.setTags(pane.getTags());
+            info.setUrl(pane.getURL());
+            
+            int uploadSize = (int) tmpJarFile.length();
+            if (tmpImgFile != null) {
+                uploadSize += (int) tmpImgFile.length();
+            }
+            if (tmpZipFile != null) {
+                uploadSize += (int) tmpZipFile.length();
+            }
+            gotUploadSize(uploadSize);
+            
+            webPublisher.submit(hostAddress, login, password,
+                    tmpJarFile.getAbsolutePath(), tmpZipFile, tmpImgFile, size.width, size.height,
+                    info);
+        }
+        catch (UnknownHostException e) {
+            dlg.setProgress(false, Config.getString("export.publish.unknownHost") + " (" + e.getMessage() + ")");
+            return;
+        }
+        catch (IOException e) {
+            dlg.setProgress(false, Config.getString("export.publish.fail") + " " + e.getMessage());
+            return;
+        }
+    }
+
+    /**
+     * Create a web page and jar-file.
+     */
+    public void makeWebPage(GProject project, ExportWebPagePane pane, ExportDialog dlg)
+    {
+        this.dlg = dlg;
+        dlg.setProgress(true, Config.getString("export.progress.writingHTML"));
+        File exportDir = new File(pane.getExportLocation());
+        exportDir.mkdir();
+
+        String worldClass = project.getLastWorldClassName();
+        
+        boolean  includeControls = pane.lockScenario();
+        String jarName = project.getName() + ".jar";
+        JarCreator jarCreator = new JarCreator(project, exportDir, jarName, worldClass, includeControls, true);            
+        
+        // do not include source
+        jarCreator.includeSource(false);        
+
+        // Add the Greenfoot standalone classes
+        File greenfootLibDir = Config.getGreenfootLibDir();        
+        File greenfootDir = new File(greenfootLibDir, "standalone");        
+        jarCreator.addFile(greenfootDir);   
+        
+        // Add 3rd party libraries used by Greenfoot.      
+        Set<File> thirdPartyLibs = GreenfootUtil.get3rdPartyLibs();
+        for (File lib : thirdPartyLibs) {
+            jarCreator.addJar(lib);
+        }
+        
+        // Add jars in +libs dir in project directory
+        File[] jarFiles = getJarsInPlusLib(project);
+        if (jarFiles != null) {
+            for (File file : jarFiles) {
+                jarCreator.addJar(file);
+            }
+        }                    
+        
+        Dimension size = getSize(includeControls);
+
+        // Make sure the current properties are saved before they are exported.
+        project.getProjectProperties().save();
+        
+        jarCreator.create();
+    
+        String htmlName = project.getName() + ".html";
+        String title = project.getName();
+        File outputFile = new File(exportDir, htmlName);
+        jarCreator.generateHTMLSkeleton(outputFile, title, size.width, size.height);
+        dlg.setProgress(false, Config.getString("export.progress.complete")); 
+    }
+
+    private File[] getJarsInPlusLib(GProject project)
+    {
+        File[] jarFiles = null;
+        File plusLibsDir = new File(project.getDir(), Project.projectLibDirName);
+        jarFiles = plusLibsDir.listFiles(new FilenameFilter() {
+            public boolean accept(File dir, String name)
+            {
+                return name.toLowerCase().endsWith(".jar");
+            }
+        });
+        return jarFiles;
+    }
+        
+    /**
+     * Create an application (jar-file)
+     */
+    public void makeApplication(GProject project, ExportAppPane pane, ExportDialog dlg)
+    {
+        dlg.setProgress(true, Config.getString("export.progress.writingJar"));
+        File exportFile = new File(pane.getExportName());
+        File exportDir = exportFile.getParentFile();
+        String jarName = exportFile.getName();
+
+        String worldClass = project.getLastWorldClassName();
+        
+        boolean  includeControls = pane.lockScenario();
+        
+        JarCreator jarCreator = new JarCreator(project, exportDir, jarName, worldClass, includeControls, false); 
+        // do not include source
+        jarCreator.includeSource(false);  
+        
+        // Add the Greenfoot standalone classes
+        File greenfootLibDir = Config.getGreenfootLibDir();        
+        File greenfootDir = new File(greenfootLibDir, "standalone");        
+        jarCreator.addFile(greenfootDir);     
+        
+        // Add 3rd party libraries used by Greenfoot.      
+        Set<File> thirdPartyLibs = GreenfootUtil.get3rdPartyLibs();
+        for (File lib : thirdPartyLibs) {
+            jarCreator.addJarToJar(lib);
+        }
+
+        // Add jars in +libs dir in project directory
+        File[] jarFiles = getJarsInPlusLib(project);
+        if (jarFiles != null) {
+            for (File file : jarFiles) {
+                jarCreator.addJarToJar(file);
+            }
+        }         
+        
+        // Add text file with license information
+        try {
+            File license = new File(GreenfootUtil.getGreenfootDir(), "GREENFOOT_LICENSES.txt");
+            if(license.exists()) {
+                jarCreator.addFile(license);
+            }
+        } catch (IOException e) {
+            // Ignore exceptions with license file since it is not a crucial thing to include.
+        }
+        
+        // Make sure the current properties are saved before they are exported.
+        project.getProjectProperties().save();
+        
+        jarCreator.create();
+        dlg.setProgress(false, Config.getString("export.progress.complete")); 
+    }
+
+    /**
+     * Get the size needed to display the application and control panel.
+     * @return
+     */
+    private Dimension getSize(boolean includeControls)
+    {     
+        //The control panel size is hard coded for now, since it has different sizes on different platforms. 
+        //It is bigger on windows than most other platforms, so this is the size that is used.
+        //Will be even more problematic once we get i18n!
+        Dimension controlPanelSize = null;  
+        Dimension border = GreenfootScenarioViewer.getControlsBorderSize();        
+        if(includeControls) {
+            controlPanelSize = new Dimension(560 + border.width , 48 + border.height);
+        }
+        else {   
+            controlPanelSize = new Dimension(410 + border.width, 48 + border.height);
+        }
+        
+        WorldCanvas canvas = WorldHandler.getInstance().getWorldCanvas();
+        border = GreenfootScenarioViewer.getWorldBorderSize();
+        Dimension size = new Dimension(canvas.getWidth() + border.width, (int) controlPanelSize.getHeight() + canvas.getHeight() + border.height);
+        size.width += 2;  // add some extra padding
+        size.height += 2;
+        size.width = Math.max(size.width, controlPanelSize.width);
+        return size;
+    }
+        
+    /**
+     * Something went wrong when publishing.
+     */
+    public void errorRecieved(final PublishEvent event)
+    {
+        deleteTmpFiles();
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run()
+            {
+                dlg.publishFinished(false,  Config.getString("export.publish.fail") + " " + event.getMessage());
+            }
+        });
+    }
+
+    /**
+     * Publish succeeded.
+     */    
+    public void uploadComplete(PublishEvent event)
+    {
+        deleteTmpFiles();
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run()
+            {
+                dlg.publishFinished(true, Config.getString("export.publish.complete"));
+            }
+        });
+    }
+
+    private void deleteTmpFiles()
+    {
+        if (tmpJarFile != null) {
+            tmpJarFile.delete();
+            tmpJarFile = null;
+        }
+        if (tmpImgFile != null) {
+            tmpImgFile.delete();
+            tmpImgFile = null;
+        }
+        if (tmpZipFile != null) {
+            tmpZipFile.delete();
+            tmpZipFile = null;
+        }
+    }
+    
+    /**
+     * We now know the total upload size.
+     */
+    public void gotUploadSize(final int size)
+    {
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run()
+            {
+                dlg.gotUploadSize(size);
+            }
+        });
+    }
+    
+    /**
+     * Upload progress made.
+     */
+    public void progressMade(final PublishEvent event)
+    {
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run()
+            {
+                dlg.progressMade(event.getBytes());
+            }
+        });
+    }
+    
+    @Override
+    public String[] needProxyAuth()
+    {
+        final String[] details = new String[2];
+
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                @Override
+                public void run()
+                {
+                    ProxyAuthDialog dialog = new ProxyAuthDialog(dlg);
+                    dialog.setVisible(true);
+                    
+                    if (dialog.getResult() == ProxyAuthDialog.OK) {
+                        details[0] = dialog.getUsername();
+                        details[1] = dialog.getPassword();
+                    }
+                }
+            });
+        }
+        catch (InvocationTargetException ite) {
+            throw new RuntimeException(ite.getCause());
+        }
+        catch (InterruptedException ie) {
+            return null;
+        }
+        
+        if (details[0] == null) {
+            return null;
+        }
+        
+        return details;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/GreenfootScenarioMain.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/GreenfootScenarioMain.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d430d9b8ae897a9cfd2c5ee5ad1ec987e7c4163
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/GreenfootScenarioMain.java
@@ -0,0 +1,133 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.export;
+
+import greenfoot.util.StandalonePropStringManager;
+
+import java.awt.EventQueue;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Properties;
+
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+
+import bluej.Config;
+
+/**
+ * The main class for Greenfoot scenarios when they are exported as standalone
+ * applications.
+ * 
+ * <p>This must be a separate class from GreenfootScenarioViewer, and specifically
+ * must not be a Swing/AWT derived class, because we need to set the application
+ * name property (for Mac OS) before any Swing/AWT classes are propertly initialized.
+ * 
+ * @author Davin McCall
+ */
+public class GreenfootScenarioMain
+{
+    public static String scenarioName;
+    public static String [] args;
+    
+    /**
+     * Start the scenario.
+     * <p>
+     * 
+     * BlueJ and the scenario MUST be on the classpath.
+     * 
+     * @param args One argument can be passed to this method. The first one
+     *            should be the World to be instantiated. If no arguments are
+     *            supplied it will read from the properties file. And if that
+     *            can't be found either it will use AntWorld.
+     */
+    public static void main(String[] args)
+    {
+        System.setProperty("apple.laf.useScreenMenuBar", "true");
+        if(args.length != 3 && args.length != 0) {
+            System.err.println("Wrong number of arguments");
+        }
+        
+        GreenfootScenarioMain.args = args; 
+        initProperties(); // discover scenario name
+        System.setProperty("com.apple.mrj.application.apple.menu.about.name", scenarioName);
+        
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                JFrame frame = new JFrame(scenarioName);
+                new GreenfootScenarioViewer(frame);
+                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+                frame.setResizable(false);
+                
+                URL resource = this.getClass().getClassLoader().getResource("greenfoot.png");
+                ImageIcon icon = new ImageIcon(resource);
+                frame.setIconImage(icon.getImage());
+                
+                frame.pack();
+                frame.setVisible(true);
+            }
+        });
+    }
+    
+    /**
+     * Initialize the project properties.
+     */
+    public static void initProperties()
+    {
+        if (scenarioName != null) {
+            return; // already done
+        }
+        
+        Properties p = new Properties();
+        try {
+            ClassLoader loader = GreenfootScenarioMain.class.getClassLoader();
+            InputStream is = loader.getResourceAsStream("standalone.properties");
+            
+            if(is == null && args.length == 3) {
+                // This might happen if we are running from ant
+                // In that case we should have some command line arguments
+                p.put("project.name", args[0]);
+                p.put("main.class", args[1]);
+                p.put("scenario.lock", "true");  
+                File f = new File(args[2]);
+                is = new FileInputStream(f);    
+            } 
+            
+            p.load(is);
+            scenarioName = p.getProperty("project.name");
+
+            // set bluej Config to use the standalone prop values
+            Config.initializeStandalone(new StandalonePropStringManager(p));
+            is.close();
+        }
+        catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/GreenfootScenarioViewer.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/GreenfootScenarioViewer.java
new file mode 100644
index 0000000000000000000000000000000000000000..9482567236191ee5ad7b0db0f292d2f029df3d7f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/GreenfootScenarioViewer.java
@@ -0,0 +1,357 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.export;
+
+import greenfoot.World;
+import greenfoot.core.ProjectProperties;
+import greenfoot.core.Simulation;
+import greenfoot.core.WorldHandler;
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+import greenfoot.gui.CenterLayout;
+import greenfoot.gui.ControlPanel;
+import greenfoot.gui.WorldCanvas;
+import greenfoot.gui.input.mouse.LocationTracker;
+import greenfoot.platforms.standalone.ActorDelegateStandAlone;
+import greenfoot.platforms.standalone.GreenfootUtilDelegateStandAlone;
+import greenfoot.platforms.standalone.SimulationDelegateStandAlone;
+import greenfoot.platforms.standalone.WorldHandlerDelegateStandAlone;
+import greenfoot.sound.SoundFactory;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import javax.swing.BorderFactory;
+import javax.swing.JApplet;
+import javax.swing.JPanel;
+import javax.swing.JRootPane;
+import javax.swing.RootPaneContainer;
+
+import bluej.Config;
+import javax.swing.JScrollPane;
+
+/**
+ * This class can view and run a Greenfoot scenario. It is not possible to
+ * interact with the objects in any way.
+ * 
+ * @author Poul Henriksen
+ */
+public class GreenfootScenarioViewer extends JApplet
+{
+    private static final int EMPTY_BORDER_SIZE = 5;
+
+    private static String scenarioName;
+
+    private boolean isApplet;
+    private ProjectProperties properties;
+    private Simulation sim;
+    private WorldCanvas canvas;
+    private ControlPanel controls;
+    private RootPaneContainer rootPaneContainer;
+
+    private Constructor<?> worldConstructor;
+
+    /**
+     * The default constructor, used when the scenario runs as an applet.
+     */
+    public GreenfootScenarioViewer()
+    {
+        isApplet = true;
+    }
+
+    /**
+     * Constructor for when the scenario runs as an application.
+     */
+    public GreenfootScenarioViewer(RootPaneContainer rootPane)
+    {
+        rootPaneContainer = rootPane;
+        isApplet = false;
+        init();
+    }
+
+    /**
+     * Returns the size of the borders around the controls.
+     */
+    public static Dimension getControlsBorderSize()
+    {
+        return new Dimension((EMPTY_BORDER_SIZE ) * 2, (EMPTY_BORDER_SIZE ) * 2);
+    } 
+    
+    /**
+     * Returns the size of the borders around the world panel.
+     */
+    public static Dimension getWorldBorderSize()
+    {
+        return new Dimension((EMPTY_BORDER_SIZE + 1) * 2, EMPTY_BORDER_SIZE + 1 * 2);
+    }
+    
+    private void buildGUI()
+    {
+        if (rootPaneContainer == null) {
+            // it will be null when running as applet, so set it to the applet.
+            rootPaneContainer = this;
+        }
+        
+        JPanel centerPanel = new JPanel(new CenterLayout());
+        centerPanel.add( canvas );
+        centerPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
+        
+        JScrollPane outer = new JScrollPane( centerPanel );
+        outer.setBorder(BorderFactory.createEmptyBorder(EMPTY_BORDER_SIZE,EMPTY_BORDER_SIZE,EMPTY_BORDER_SIZE,EMPTY_BORDER_SIZE));
+        controls.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createEmptyBorder(0,EMPTY_BORDER_SIZE,EMPTY_BORDER_SIZE,EMPTY_BORDER_SIZE), BorderFactory.createEtchedBorder()));
+        
+        rootPaneContainer.getContentPane().add(outer, BorderLayout.CENTER);
+        rootPaneContainer.getContentPane().add(controls, BorderLayout.SOUTH);
+    }
+    
+    @Override
+    public String getParameter(String name)
+    {
+        if (isApplet)
+            return super.getParameter(name);
+        else
+            return null;
+    }
+
+    /**
+     * Called by the browser or applet viewer to inform this JApplet that it has
+     * been loaded into the system. It is always called before the first time
+     * that the start method is called.
+     */
+    public void init()
+    {
+        GreenfootScenarioMain.initProperties();
+        
+        boolean storageStandalone = getParameter("storage.standalone") != null;
+        String storageHost = getParameter("storage.server");
+        String storagePort = getParameter("storage.serverPort");
+        String storagePasscode = getParameter("storage.passcode");
+        String storageScenarioId = getParameter("storage.scenarioId");
+        String storageUserId = getParameter("storage.userId");
+        String storageUserName = getParameter("storage.userName");
+        
+        // this is a workaround for a security conflict with some browsers
+        // including some versions of Netscape & Internet Explorer which do
+        // not allow access to the AWT system event queue which JApplets do
+        // on startup to check access. May not be necessary with your browser.
+        JRootPane rootPane = this.getRootPane();
+        rootPane.putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE);
+        
+        String worldClassName = Config.getPropString("main.class"); 
+        boolean lockScenario = Config.getPropBoolean("scenario.lock");
+
+        try {
+            GreenfootUtil.initialise(new GreenfootUtilDelegateStandAlone(storageStandalone, storageHost, storagePort, storagePasscode, storageScenarioId, storageUserId, storageUserName));
+            properties = new ProjectProperties();
+
+            ActorDelegateStandAlone.setupAsActorDelegate();
+            ActorDelegateStandAlone.initProperties(properties);
+
+            // We must construct the simulation before the world, as a call to
+            // Greenfoot.setSpeed() requires a call to the simulation instance.
+            Simulation.initialize(new SimulationDelegateStandAlone());
+            canvas = new WorldCanvas(null);
+            canvas.addMouseListener(new MouseAdapter() {
+                public void mouseClicked(MouseEvent e)
+                {
+                    canvas.requestFocusInWindow();
+                    // Have to use requestFocus, since it is the only way to
+                    // make it work in some browsers (Ubuntu's Firefox 1.5
+                    // and 2.0)
+                    canvas.requestFocus();
+                }
+            });        
+            
+            WorldHandler.initialise(canvas, new WorldHandlerDelegateStandAlone(this, lockScenario));
+            WorldHandler worldHandler = WorldHandler.getInstance();
+            sim = Simulation.getInstance();
+            sim.attachWorldHandler(worldHandler);
+            LocationTracker.initialize();
+            controls = new ControlPanel(sim, ! lockScenario);
+
+            // Make sure the SoundCollection is initialized and listens for events
+            sim.addSimulationListener(SoundFactory.getInstance().getSoundCollection());
+            
+            sim.addSimulationListener(new SimulationListener() {
+                public void simulationChanged(SimulationEvent e)
+                {
+                    // If the simulation starts, try to transfer keyboard
+                    // focus to the world canvas to allow control of Actors
+                    // via the keyboard
+                    if (e.getType() == SimulationEvent.STARTED) {
+                        canvas.requestFocusInWindow();
+                        // Have to use requestFocus, since it is the only way to
+                        // make it work in some browsers: (Ubuntu's Firefox 1.5
+                        // and 2.0)
+                        canvas.requestFocus();
+                    }
+                }
+            });
+            
+            try {
+                int initialSpeed = properties.getInt("simulation.speed");
+                sim.setSpeed(initialSpeed);
+            } catch (NumberFormatException nfe) {
+                // If there is no speed info in the properties we don't care...
+            }
+            
+            Class<?> worldClass = Class.forName(worldClassName);
+            worldConstructor = worldClass.getConstructor(new Class[]{});
+            World world = instantiateNewWorld();
+            if (! worldHandler.checkWorldSet()) {
+                worldHandler.setWorld(world);
+            }
+            // Although setting the world on worldHandler also sets it on canvas,
+            // it does so later (via EventQueue.invokeLater()). We need to do it
+            // here and now, so that the canvas size will be calculated correctly.
+            canvas.setWorld(worldHandler.getWorld());
+            
+            buildGUI();
+        }
+        catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        }
+        catch (SecurityException e) {
+            e.printStackTrace();
+        }
+        catch (NoSuchMethodException e) {
+            e.printStackTrace();
+        }
+        catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        }
+    }
+    
+    /**
+     * Called by the browser or applet viewer to inform this JApplet that it
+     * should start its execution. It is called after the init method and each
+     * time the JApplet is revisited in a Web page.
+     */
+    public void start()
+    {
+    }
+
+    /**
+     * Called by the browser or applet viewer to inform this JApplet that it
+     * should stop its execution. It is called when the Web page that contains
+     * this JApplet has been replaced by another page, and also just before the
+     * JApplet is to be destroyed.
+     */
+    public void stop()
+    {
+        sim.setPaused(true);
+    }
+
+    /**
+     * Called by the browser or applet viewer to inform this JApplet that it is
+     * being reclaimed and that it should destroy any resources that it has
+     * allocated. The stop method will always be called before destroy.
+     */
+    public void destroy()
+    {
+        sim.abort();
+    }
+
+    /**
+     * Returns information about this applet. An applet should override this
+     * method to return a String containing information about the author,
+     * version, and copyright of the JApplet.
+     * 
+     * @return a String representation of information about this JApplet
+     */
+    public String getAppletInfo()
+    {
+        // provide information about the applet
+        return Config.getString("scenario.viewer.appletInfo") + " " + scenarioName; //"Title:   \nAuthor:   \nA simple applet example description. ";
+    }
+
+    /**
+     * Returns parameter information about this JApplet. Returns information
+     * about the parameters than are understood by this JApplet. An applet
+     * should override this method to return an array of Strings describing
+     * these parameters. Each element of the array should be a set of three
+     * Strings containing the name, the type, and a description.
+     * 
+     * @return a String[] representation of parameter information about this
+     *         JApplet
+     */
+    public String[][] getParameterInfo()
+    {
+        // provide parameter information about the applet
+        String paramInfo[][] = {};
+        /*
+         * {"firstParameter", "1-10", "description of first parameter"},
+         * {"status", "boolean", "description of second parameter"}, {"images",
+         * "url", "description of third parameter"} };
+         */
+        return paramInfo;
+    }
+
+    
+    /**
+     * Creates a new instance of the world. And initialises with that world.
+     */
+    public World instantiateNewWorld() 
+    {
+        try {
+            World world = (World) worldConstructor.newInstance(new Object[]{});
+            return world;
+        }
+        catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        }
+        catch (InstantiationException e) {
+            e.printStackTrace();
+        }
+        catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+        catch (InvocationTargetException e) {
+            e.getCause().printStackTrace();
+        }
+        return null;
+    }
+    
+    /**
+     * Get access to the world. Being a public method in the applet class allows
+     * this method to be called via JavaScript.
+     */
+    public World getWorld()
+    {
+        return WorldHandler.getInstance().getWorld();
+    }
+    
+    /**
+     * Get access to the world lock, for the given world.
+     */
+    public ReentrantReadWriteLock getWorldLock(World world)
+    {
+        return WorldHandler.getInstance().getWorldLock();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/JarCreator.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/JarCreator.java
new file mode 100644
index 0000000000000000000000000000000000000000..b0fc1fc27435b2423445a5a5c396b33961bbcc27
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/JarCreator.java
@@ -0,0 +1,733 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.export;
+
+import greenfoot.core.GProject;
+import greenfoot.util.GreenfootUtil;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.jar.Attributes;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipOutputStream;
+
+import bluej.Boot;
+import bluej.Config;
+import bluej.pkgmgr.Project;
+import bluej.utility.BlueJFileReader;
+import bluej.utility.Debug;
+import bluej.utility.FileUtility;
+
+/**
+ * Utility class to create jar or zip files from a Greenfoot project.
+ * 
+ * @author Poul Henriksen <polle@polle.org>
+ */
+public class JarCreator
+{
+    private static final String SOURCE_SUFFIX = ".java";    
+
+    /** Should source files be included in the jar? */
+    private boolean includeSource;
+
+    /** The main class attribute for the JAR. */
+    private String mainClass;
+    
+    /** Directory where the jar is exported to. */
+    private File exportDir;
+    
+    /** Directory to be exported. */
+    private File projectDir;
+    
+    /** Name of the jar file that will be created. */
+    private String jarName;
+    
+    /** List of extra jars that should be put in the same dir as the created jar (the exportDir)*/
+    private List<File> extraJars = new LinkedList<File>();
+    
+    /** List of extra jars whose contents should be put into the created jar */
+    private List<File> extraJarsInJar = new LinkedList<File>();
+
+    /** List of paths to external jars that should be included in the manifest's classpath. */
+    private List<String> extraExternalJars = new LinkedList<String>();
+    
+    private List<File> dirs = new LinkedList<File>();
+    private List<PrefixedFile> prefixDirs = new LinkedList<PrefixedFile>();
+
+    /** array of directory names not to be included in jar file * */
+    private List<String> skipDirs = new LinkedList<String>();
+
+    /** array of file names not to be included in jar file * */
+    private List<String> skipFiles = new LinkedList<String>();
+    
+    /** The maninfest */ 
+    private Manifest manifest = new Manifest();
+    
+    /** Properties that contains information read by the GreenfootScnearioViewer */
+    private Properties properties;
+ 
+    private boolean isZip = false;
+
+    /**
+     * Prepares a new jar creator. Once everything is set up, call create()
+     * 
+     * @param exportDir The directory in which to store the jar-file and any
+     *            other resources required. Must exist and be writable
+     * @param jarName The name of the jar file.
+     */
+    public JarCreator(File exportDir, String jarName)
+    {
+
+        File jarFile = new File(exportDir, jarName);
+        if (!jarFile.canWrite() && jarFile.exists()) {
+            throw new IllegalArgumentException("Cannot write file: " + jarFile);
+        }
+        this.exportDir = exportDir;
+        this.jarName = jarName;
+        properties = new Properties();
+    }
+
+    /**
+     * Export the class files for a project.
+     * 
+     * Convenience constructor that includes settings that are common for all
+     * projects and export types. This will exclude BlueJ metafiles.
+     * 
+     * @param project The project to be exported.
+     * @param exportDir The directory to export to.
+     * @param jarName Name of the jar file that should be created.
+     * @param worldClass Name of the main class.
+     * @param lockScenario Should the exported scenario include 'act'
+     *            and speedslider.
+     * @param applet Whether the export is for an applet on a webpage (true) or for a stand-alone JAR (false) 
+     */
+    public JarCreator(GProject project, File exportDir, String jarName, String worldClass, boolean lockScenario, boolean applet) 
+    {   
+        this(exportDir, jarName);
+        
+        // get the project directory        
+        projectDir = project.getDir();
+        
+        String scenarioName = project.getName();
+        
+        addFile(projectDir);
+
+        // skip CVS stuff
+        addSkipDir("CVS");
+        addSkipFile(".cvsignore");
+        
+        // skip Subversion files
+        addSkipDir(".svn");
+        
+        // skip Mac files
+        addSkipFile(".DS_Store");
+        
+        // skip doc dir
+        addSkipDir(projectDir.getPath() + System.getProperty("file.separator") + "doc");
+        
+        // skip the export dir (in case it is in the projectDir)
+        addSkipDir(exportDir.getAbsolutePath());
+        
+        // skip BlueJ files
+        addSkipFile(".ctxt");
+        addSkipFile("bluej.pkg");
+        addSkipFile("bluej.pkh");   
+        
+        // Exlude +libs. These should be added with the addJar() method.
+        addSkipDir(Project.projectLibDirName);
+        
+        // Set the main class
+        String mainClass = (applet ? GreenfootScenarioViewer.class : GreenfootScenarioMain.class).getCanonicalName();
+        setMainClass(mainClass);
+        
+        // Add the properties read by the GreenfootScenarioViewer
+        properties.put("project.name", scenarioName);
+        properties.put("project.greenfootversion", Boot.GREENFOOT_VERSION);
+        properties.put("project.javaspecversion", System.getProperty("java.specification.version"));
+        properties.put("project.javaversion", System.getProperty("java.version"));
+        properties.put("project.javaclassversion", System.getProperty("java.class.version"));
+        properties.put("main.class", worldClass);
+        properties.put("scenario.lock", "" + lockScenario);
+        properties.put("scenario.viewer.appletInfo", Config.getString("scenario.viewer.appletInfo"));
+        properties.put("run.once", Config.getString("run.once"));
+        properties.put("run.simulation", Config.getString("run.simulation"));
+        properties.put("pause.simulation", Config.getString("pause.simulation"));
+        properties.put("reset.world", Config.getString("reset.world"));
+        properties.put("controls.speed.label", Config.getString("controls.speed.label"));
+        properties.put("controls.runonce.longDescription", Config.getString("controls.runonce.longDescription"));
+        properties.put("controls.runonce.shortDescription", Config.getString("controls.runonce.shortDescription"));
+        properties.put("controls.run.longDescription", Config.getString("controls.run.longDescription"));
+        properties.put("controls.run.shortDescription", Config.getString("controls.run.shortDescription"));
+        properties.put("controls.pause.longDescription", Config.getString("controls.pause.longDescription"));
+        properties.put("controls.pause.shortDescription", Config.getString("controls.pause.shortDescription"));
+        properties.put("controls.run.button", Config.getString("controls.run.button"));
+        properties.put("controls.pause.button", Config.getString("controls.pause.button"));
+        properties.put("controls.reset.longDescription", Config.getString("controls.reset.longDescription"));
+        properties.put("controls.reset.shortDescription", Config.getString("controls.reset.shortDescription"));
+        properties.put("controls.speedSlider.tooltip", Config.getString("controls.speedSlider.tooltip"));
+        
+        // Error messages etc
+        properties.put("sound-line-unavailable", Config.getString("sound-line-unavailable"));
+    }
+    
+    /**
+     * Export source code. Includes all the project files. Creates a dir in the
+     * zip with the same name as the project dir.
+     *
+     * <p>Convenience constructor that includes settings that are common for all
+     * projects and export types.
+     * 
+     * @param project The project to be exported.
+     * @param exportDir The directory to export to.
+     * @param zipName Name of the jar file that should be created.
+     */
+    public JarCreator(GProject project, File exportDir, String zipName) 
+    {   
+        this(exportDir, zipName);
+        
+        isZip = true;
+        
+        projectDir = project.getDir();
+        
+        addFile(projectDir);        
+        
+        // skip CVS stuff
+        addSkipDir("CVS");
+        addSkipFile(".cvsignore");
+        
+        // skip Subversion files
+        addSkipDir(".svn");
+        
+        // skip Mac files
+        addSkipFile(".DS_Store");
+        
+        // skip doc dir
+        addSkipDir(projectDir.getPath() + System.getProperty("file.separator") + "doc");
+        
+        // skip the export dir (in case it is in the projectDir)
+        addSkipDir(exportDir.getAbsolutePath());
+        
+        // skip the greenfoot subdir that are in the projects
+        addSkipDir(projectDir.getPath() + System.getProperty("file.separator") + "greenfoot");
+        
+        // skip BlueJ files
+        addSkipFile("bluej.pkg");
+        addSkipFile("bluej.pkh");   
+        
+        includeSource(true);
+    }
+    
+    /**
+     * Creates the jar file with the current settings.
+     */
+    public void create()
+    {        
+        File jarFile = new File(exportDir, jarName);
+        File propertiesFile = null;
+        File soundFile = null;
+        OutputStream oStream = null;
+        ZipOutputStream jStream = null;
+
+        try {
+            oStream = new BufferedOutputStream(new FileOutputStream(jarFile));
+            String pathPrefix = ""; // Put everything in top level of jar
+            if (! isZip) {
+                // It is a jar file so we write the manifest and the properties.
+                writeManifest();
+                propertiesFile = new File(projectDir, "standalone.properties");
+                writePropertiesFile(propertiesFile);
+                soundFile = new File(projectDir, "soundindex.list");
+                writeSoundFilesList(soundFile);
+                jStream = new JarOutputStream(oStream, manifest);
+            }
+            else {
+                // It is a zip, so we want a dir with the project name inside the zip
+                pathPrefix = projectDir.getName() + "/";
+                jStream = new ZipOutputStream(oStream);
+            }
+            // Write contents of directories added
+            for(File dir : dirs) {
+                writeFileToJar(dir, pathPrefix, jStream, jarFile.getCanonicalFile(), true);
+            }
+            for(PrefixedFile dir : prefixDirs) {
+                writeFileToJar(dir.getFile(), pathPrefix + dir.getPrefix(), jStream, jarFile.getCanonicalFile(), true);
+            }
+            for(File jar : extraJarsInJar) {
+                writeJarToJar(jar, jStream);
+            }
+            copyLibsToDir(extraJars, exportDir);            
+        }
+        catch (IOException exc) {
+            Debug.reportError("problem writing jar file: " + exc);
+        }
+        finally {
+            try {
+                if (jStream != null)
+                    jStream.close();
+            }
+            catch (IOException e) {}
+            if(propertiesFile != null) {
+                propertiesFile.delete();
+            }
+        }
+    }
+
+    private void writeSoundFilesList(File file)
+    {
+        BufferedWriter os = null;
+        try {
+            file.createNewFile();
+            os = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
+            for (String name : GreenfootUtil.getSoundFiles())
+            {
+                os.write(name + "\n");
+            }
+            os.close();
+        }
+        catch (IOException e)
+        {
+            Debug.reportError("Error writing list of sounds: ", e);
+        }
+        
+    }
+
+    /**
+     * Writes the properties to the given file.
+     */
+    private void writePropertiesFile(File file)
+    {
+        OutputStream os = null;
+        try {
+            file.createNewFile();
+            os = new BufferedOutputStream(new FileOutputStream(file));
+            properties.store(os, "Properties for running Greenfoot scenarios alone.");
+        }
+        catch (FileNotFoundException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        finally {
+            try {
+                os.close();
+            }
+            catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Puts an entry into to the manifest file.
+     * 
+     * @param key The key 
+     * @param value The value
+     */
+    public void putManifestEntry(String key, String value)
+    {
+        Attributes attr = manifest.getMainAttributes();
+        value = fixNewlines(value);
+        attr.put(new Attributes.Name(key), value);
+    }
+    
+    private String fixNewlines(String value)
+    {
+        StringBuffer buffer = new StringBuffer(value.length());
+        
+        //(?m) MULTILINE is required for $ and ^ to work. 
+        //(?s) DOTALL makes . match newlines as well.
+        String newLineRegExp = "(?m)(?s)$.^";
+        //\\z matches end of input, so this will match all trailing newlines.
+        String trailingNewLineReqExp = "$.\\z";
+        String[] lines = value.split(newLineRegExp + "|" + trailingNewLineReqExp );
+        for (int i = 0; i < lines.length; i++) {
+            String string = lines[i];
+            if(i!=0) {
+                buffer.append("<br>");
+            }
+            buffer.append(string);
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Writes entries to the manifest file.
+     */
+    private void writeManifest()
+    {
+        // Construct classpath with used library jars
+        String classpath = "";
+
+        // add extra jars to classpath
+        for (Iterator<File> it = extraJars.iterator(); it.hasNext();) {
+            classpath += " " + it.next().getName();
+        }
+        
+        // add extra external jars to classpath
+        for (Iterator<String> it = extraExternalJars.iterator(); it.hasNext();) {
+            classpath += " " + it.next();
+        }
+        
+        Attributes attr = manifest.getMainAttributes();
+        attr.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+        attr.put(Attributes.Name.MAIN_CLASS, mainClass);
+        attr.put(Attributes.Name.CLASS_PATH, classpath);
+    }
+
+    /**
+     * Whether to include sources or not.
+     */
+    public void includeSource(boolean b)
+    {
+        includeSource = b;
+    }
+    
+    /**
+     * Sets the main class for this JAR. The class that contains the main method
+     * or Applet class.
+     * 
+     * @param mainClass
+     */
+    public void setMainClass(String mainClass)
+    {
+        this.mainClass = mainClass;
+    }
+
+    /**
+     * Adds a jar file to be distributed together with this jar-file. It will be
+     * copied into the same location as the jar-file created (the exportDir).
+     * 
+     * <p>This will usually be the jars +libs dir and userlib jars
+     * 
+     * @param jar A jar file.
+     */
+    public void addJar(File jar)
+    {
+        extraJars.add(jar);
+    }
+    
+    /** 
+     * Add a jar to the list of extra jars whose contents should be put into the created jar 
+     * 
+     * <p>This will usually be the jars +libs dir and userlib jars
+     * 
+     * @param jar A jar file.
+     */
+    public void addJarToJar(File jar)
+    {
+        extraJarsInJar.add(jar);
+    }
+
+    /**
+     * Adds a location of an external jar file. This will be added to the
+     * classpath of the manifest.
+     * 
+     * @param  path Usually a URL or a relative path.
+     */
+    public void addToClassPath(String path)
+    {
+        extraExternalJars.add(path);
+    }
+    
+    /**
+     * Directory or file to include in export.
+     */
+    public void addFile(File file)
+    {
+        dirs.add(file);
+    }
+
+    
+    /**
+     * Directory or file to include in export, with the given prefix added when putting
+     * it into the jar.
+     */
+    public void addFile(String prefix, File file)
+    {
+        prefixDirs.add(new PrefixedFile(prefix, file));
+    }
+    
+    /**
+     * All dirs that end with the specified string will be skipped.
+     * Be aware of platform dependent file separators.
+     */
+    public void addSkipDir(String dir)
+    {
+        skipDirs.add(dir);
+    }
+
+
+    /**
+     * All files that end with the specified string will be skipped.
+     * Be aware of platform dependent file separators.
+     */
+    public void addSkipFile(String file)
+    {
+        skipFiles.add(file);
+    }
+
+    /**
+     * Write the contents of a directory to a jar stream. Recursively called for
+     * subdirectories. outputFile should be the canonical file representation of
+     * the Jar file we are creating (to prevent including itself in the Jar
+     * file)
+     */
+    private void writeDirToJar(File sourceDir, String pathPrefix, ZipOutputStream stream, File outputFile)
+        throws IOException
+    {
+        if (!skipDir(sourceDir)) {
+            File[] dir = sourceDir.listFiles();
+            for (int i = 0; i < dir.length; i++) {
+                writeFileToJar(dir[i], pathPrefix, stream, outputFile, false);
+            }
+        }
+    }
+    
+    /**
+     * Writes a file or directory to a jar. Recursively called for
+     * subdirectories. outputFile should be the canonical file representation of
+     * the Jar file we are creating (to prevent including itself in the Jar
+     * file). If the source file does not exist, this method will just return without 
+     * doing anything.
+     * 
+     * @param onlyDirContents If sourceFile is a dir, this parameter indicates that
+     *           the contents of the dir should be added, not the dir itself.
+     */
+    private void writeFileToJar(File sourceFile, String pathPrefix, ZipOutputStream stream, File outputFile, boolean onlyDirContents)
+        throws IOException
+    {
+        if(!sourceFile.exists()) {
+            // if the file is not available, just return.
+            return;
+        }
+        
+        if(sourceFile.isDirectory()) {
+            if(!onlyDirContents) {
+                pathPrefix += sourceFile.getName()  + "/";
+            }
+            writeDirToJar(sourceFile, pathPrefix, stream, outputFile);
+        }
+        else {
+            // check against a list of files we don't want to export and also
+            // check that we don't try to export the jar file we are writing
+            // (hangs the machine)
+            if (!skipFile(sourceFile.getName(), !includeSource)
+                    && !outputFile.equals(sourceFile.getCanonicalFile())) {
+                writeJarEntry(sourceFile, stream, pathPrefix + sourceFile.getName());
+            }
+        }
+    }
+    
+    /**
+     * Write the contents of a jar into another jar stream. If the source file does not exist,
+     * this method will just return without doing anything.
+     */
+    private void writeJarToJar(File inputJar, ZipOutputStream outputStream)
+        throws IOException
+    {
+        if(!inputJar.exists()) {
+            // if the file is not available, just return.
+            return;
+        }
+        
+        JarInputStream inputStream = new JarInputStream(
+                new BufferedInputStream(new FileInputStream(inputJar)));
+        
+        ZipEntry inputEntry = inputStream.getNextJarEntry();
+        while(inputEntry != null) {
+            //TODO: What if we have duplicate files????
+            outputStream.putNextEntry(inputEntry);
+            FileUtility.copyStream(inputStream, outputStream);
+            inputStream.closeEntry();
+            inputEntry = inputStream.getNextJarEntry();
+        }        
+        inputStream.close();
+    }
+
+    /**
+     * Copy all files specified in the given list to the new jar directory.
+     */
+    private void copyLibsToDir(List<File> userLibs, File destDir)
+    {
+        for (Iterator<File> it = userLibs.iterator(); it.hasNext();) {
+            File lib = it.next();
+
+            // Ignore files that do not exist
+            if(lib.exists()) {
+                File destFile = new File(destDir, lib.getName());
+                try {
+                    FileUtility.copyFile(lib, destFile);
+                }
+                catch (IOException e) {
+                    Debug.reportError("Error when copying file: " + lib + " to: " + destFile, e);               
+                }
+            }
+        }
+    }
+
+    /**
+     * Test whether a given directory should be skipped (not included) in
+     * export.
+     */
+    private boolean skipDir(File dir) throws IOException
+    {
+
+        Iterator<String> it = skipDirs.iterator();
+        while(it.hasNext()) {
+            String skipDir = it.next();
+            if (dir.getCanonicalFile().getPath().endsWith(skipDir))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether a file should be skipped during a copy operation. 
+     */
+    private boolean skipFile(String fileName, boolean skipSource)
+    {
+
+        for(String skipFile : skipFiles) {
+            if (fileName.endsWith(skipFile))
+                return true;            
+        }
+        
+        if (fileName.endsWith(SOURCE_SUFFIX))
+            return !includeSource;
+
+
+        return false;
+    }
+
+    /**
+     * Write a jar file entry to the jar output stream. Note: entryName should
+     * always be a path with / seperators (NOT the platform dependant
+     * File.seperator)
+     */
+    private void writeJarEntry(File file, ZipOutputStream stream, String entryName)
+        throws IOException
+    {
+        InputStream in = null;
+        try {
+            in = new BufferedInputStream(new FileInputStream(file));
+            stream.putNextEntry(new ZipEntry(entryName));
+            FileUtility.copyStream(in, stream);
+        }
+        catch (ZipException exc) {
+            Debug.message("warning: " + exc);
+        }
+        finally {
+            if (in != null)
+                in.close();
+        }
+    }
+    
+    public void generateHTMLSkeleton(File outputFile, String title, int width, int height)
+    {
+        Hashtable<String,String> translations = new Hashtable<String,String>();
+
+        translations.put("TITLE", title);
+       // translations.put("COMMENT", htmlComment);
+        translations.put("CLASSFILE", mainClass + ".class");
+        // whilst it would be nice to be able to have no codebase, it is in the
+        // HTML template file and hence even if we define no CODEBASE here, it
+        // will appear in the resulting HTML anyway (as CODEBASE=$CODEBASE)
+        translations.put("CODEBASE", "");
+        translations.put("APPLETWIDTH", "" + width);
+        translations.put("APPLETHEIGHT", "" + height);
+
+        // add libraries from <project>/+libs/ to archives
+        /*
+        This does not work on Safari (and maybe other browser as well)
+        String archives = jarName;
+        try {
+            for (int i = 0; i < libs.length; i++) {
+                if (archives.length() == 0)
+                    archives = libs[i].toURI().toURL().toString();
+                else
+                    archives += "," + libs[i].toURL();
+            }
+        }
+        catch (MalformedURLException e) {}*/
+
+        translations.put("ARCHIVE", jarName);
+
+
+        String baseName = "greenfoot/templates/html.tmpl";
+        File template = Config.getLanguageFile(baseName);
+        
+        try {
+            Charset utf8 = Charset.forName("UTF-8");
+            BlueJFileReader.translateFile(template, outputFile, translations, utf8, utf8);
+        }
+        catch (IOException e) {
+            Debug.reportError("Exception during file translation from " + template + " to " + outputFile);
+            e.printStackTrace();
+        }
+    }
+    
+    static class PrefixedFile 
+    {
+        private File file;
+        public File getFile()
+        {
+            return file;
+        }
+
+        public String getPrefix()
+        {
+            return prefix;
+        }
+
+        private String prefix;
+
+        public PrefixedFile(String prefix, File file) 
+        {
+            this.prefix = prefix;
+            this.file = file;
+        }    
+    }
+    
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/ExistingScenarioChecker.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/ExistingScenarioChecker.java
new file mode 100644
index 0000000000000000000000000000000000000000..e81c24bc1308025610fde71d525a831aa71e25b6
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/ExistingScenarioChecker.java
@@ -0,0 +1,188 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.export.mygame;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+
+import bluej.utility.SwingWorker;
+
+/**
+ * Abstract class that can be used to check (asynchronously) whether a scenario already exists on the
+ * publish site.
+ * 
+ * @author Poul Henriksen
+ */
+public abstract class ExistingScenarioChecker
+{
+    /** Worker to handle asynchronously checking of existing scenario */
+    private SwingWorker worker;
+
+    /** Are we in the process of checking? */
+    private boolean checking = false;
+
+    /** Indicates that the user wants to abort checking for this scenario. */
+    private boolean abort = false;
+
+    /** Indicates that the checking has finished. */
+    private boolean finished = false;
+
+    private volatile String hostName;
+    private volatile String userName;
+    private volatile String scenarioName;
+
+    class ScenarioWorker extends SwingWorker
+    {
+        @Override
+        public Object construct()
+        {
+            return checkExistence(hostName, userName, scenarioName);
+        }
+
+        @Override
+        public void finished()
+        {
+            workerFinished(getValue());
+        }
+    }
+
+    /**
+     * Will start a thread that checks whether a scenario with the given name
+     * exists for the given user. When a result is ready the method
+     * scenarioExistenceChecked will be called. The result for the given host / user / scenario
+     * combination may be cached.
+     */
+    public void startScenarioExistenceCheck(final String hostName, final String userName,
+            final String scenarioName)
+    {
+        synchronized (this) {
+            boolean sameScenario = hostName.equals(this.hostName) && userName.equals(this.userName)
+                    && scenarioName.equals(this.scenarioName);
+            if (sameScenario) {
+                return;
+            }
+            if (checking) {
+                // Abort the current check in preparation for the new one.
+                abort();
+            }
+
+            this.hostName = hostName;
+            this.userName = userName;
+            this.scenarioName = scenarioName;
+
+            checking = true;
+            abort = false;
+            finished = false;
+            worker = new ScenarioWorker();
+            worker.start();
+        }
+    }
+
+    /**
+     * Will abort the checking.
+     * 
+     * @return True if successful abort, false if we didn't manage to abort
+     *         (because it already finished the check)
+     *         
+     * @throws IllegalStateException If the check has not started yet.
+     */
+    public synchronized boolean abort()
+    {
+        // pre: is checking
+        if (finished) {
+            return false;
+        }
+
+        if (!checking) {
+            throw new IllegalStateException("Check not started yet. Nothing to abort.");
+        }
+
+        abort = true;
+        worker.interrupt();
+        return true;
+    }
+
+    /**
+     * Method that will be called when the check has finished.
+     * 
+     * This will execute on the swing event thread.
+     * 
+     * @param info If the scenario exists info about it will be returned. If it
+     *            does not exist it will return null.
+     */
+    public abstract void scenarioExistenceChecked(ScenarioInfo info);
+
+    /**
+     * Method that will be called if a check fails. This can be because if a
+     * network error or other things. This will execute on the swing event
+     * thread.
+     * 
+     * @param reason
+     */
+    public abstract void scenarioExistenceCheckFailed(Exception reason);
+
+    /**
+     * Checks the existence of the given scenario.
+     */
+    private Object checkExistence(final String hostName, final String userName, final String scenarioName)
+    {
+        MyGameClient client = new MyGameClient(null);
+        ScenarioInfo info = new ScenarioInfo();
+        Exception exception = null;
+        try {
+            if (client.checkExistingScenario(hostName, userName, scenarioName, info)) {
+                return info;
+            }
+            else {
+                return null;
+            }
+
+        }
+        catch (UnknownHostException e) {
+            exception = e;
+        }
+        catch (IOException e) {
+            exception = e;
+        }
+
+        return exception;
+    }
+
+    /**
+     * Called when the worker has finished and the result is ready to be
+     * processed.
+     */
+    private synchronized void workerFinished(Object value)
+    {
+        finished = true;
+        checking = false;
+
+        if (!abort) {
+            if (value instanceof Exception) {
+                scenarioExistenceCheckFailed((Exception) value);
+            }
+            else {
+                scenarioExistenceChecked((ScenarioInfo) value);
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/MyGameClient.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/MyGameClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..2085a82b6da48dbe7d4d9d9acab34344433aee1c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/MyGameClient.java
@@ -0,0 +1,463 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.export.mygame;
+
+import greenfoot.event.PublishEvent;
+import greenfoot.event.PublishListener;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HostConfiguration;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
+import org.apache.commons.httpclient.methods.multipart.Part;
+import org.apache.commons.httpclient.methods.multipart.StringPart;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import bluej.Config;
+
+/**
+ * MyGame client.
+ * 
+ * @author Davin McCall
+ */
+public class MyGameClient
+{
+    private PublishListener listener;
+    
+    public MyGameClient(PublishListener listener)
+    {
+        this.listener = listener;
+        
+        // Disable logging, prevents guff going to System.err
+        LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog");
+    }
+    
+    public final MyGameClient submit(String hostAddress, String uid, String password,
+            String jarFileName, File sourceFile, File screenshotFile, int width, int height,
+            ScenarioInfo info)
+        throws UnknownHostException, IOException
+    {
+        String gameName = info.getTitle();
+        String shortDescription = info.getShortDescription();
+        String longDescription = info.getLongDescription();
+        String updateDescription = info.getUpdateDescription();
+        String gameUrl = info.getUrl();
+        
+        HttpClient httpClient = getHttpClient();
+        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(20 * 1000); // 20s timeout
+        
+        // Authenticate user and initiate session
+        PostMethod postMethod = new PostMethod(hostAddress + "account/authenticate");
+        
+        postMethod.addParameter("user[username]", uid);
+        postMethod.addParameter("user[password]", password);
+        
+        int response = httpClient.executeMethod(postMethod);
+        
+        if (response == 407 && listener != null) {
+            // proxy auth required
+            String[] authDetails = listener.needProxyAuth();
+            if (authDetails != null) {
+                String proxyHost = httpClient.getHostConfiguration().getProxyHost();
+                int proxyPort = httpClient.getHostConfiguration().getProxyPort();
+                AuthScope authScope = new AuthScope(proxyHost, proxyPort);
+                Credentials proxyCreds =
+                    new UsernamePasswordCredentials(authDetails[0], authDetails[1]);
+                httpClient.getState().setProxyCredentials(authScope, proxyCreds);
+
+                // Now retry:
+                response = httpClient.executeMethod(postMethod);
+            }
+        }
+        
+        if (response > 400) {
+            error(Config.getString("export.publish.errorResponse") + " - " + response);
+            return this;
+        }
+        
+        // Check authentication result
+        if(! handleResponse(postMethod)) {
+            return this;
+        }
+        
+        // Send the scenario and associated info
+        List<String> tagsList = info.getTags();
+        boolean hasSource = sourceFile != null;
+        //determining the number of parts to send through
+        //use a temporary map holder
+        Map<String, String> partsMap = new HashMap<String, String>();
+        if (info.isUpdate()){
+            partsMap.put("scenario[update_description]", updateDescription);
+        }
+        else {
+            partsMap.put("scenario[long_description]", longDescription);
+            partsMap.put("scenario[short_description]", shortDescription);
+        }
+        int size = partsMap.size();
+       
+        if (screenshotFile!= null){
+            size=size+1;
+        }
+
+        //base number of parts is 6
+        int counter=6;
+        Part [] parts = new Part[ counter + size + tagsList.size() + (hasSource ? 1 : 0)];
+        parts[0] = new StringPart("scenario[title]", gameName, "UTF-8");
+        parts[1] = new StringPart("scenario[main_class]", "greenfoot.export.GreenfootScenarioViewer", "UTF-8");
+        parts[2] = new StringPart("scenario[width]", "" + width, "UTF-8");
+        parts[3] = new StringPart("scenario[height]", "" + height, "UTF-8");
+        parts[4] = new StringPart("scenario[url]", gameUrl, "UTF-8");
+        parts[5] = new ProgressTrackingPart("scenario[uploaded_data]", new File(jarFileName), this);
+        Iterator <String> mapIterator=partsMap.keySet().iterator();
+        String key="";
+        String obj="";
+        while (mapIterator.hasNext()){
+            key = mapIterator.next().toString();
+            obj = partsMap.get(key).toString();
+            parts[counter]= new StringPart(key, obj, "UTF-8");
+            counter=counter+1;
+        }
+        
+        if (hasSource) {
+            parts[counter] = new ProgressTrackingPart("scenario[source_data]", sourceFile, this);
+            counter=counter+1;
+        }
+        if (screenshotFile!= null){
+            parts[counter] = new ProgressTrackingPart("scenario[screenshot_data]", screenshotFile, this);
+            counter=counter+1;
+        }
+
+        int tagNum = 0;
+        for (Iterator<String> i = tagsList.iterator(); i.hasNext(); ) {
+            parts[counter] = new StringPart("scenario[tag" + tagNum++ + "]", i.next());
+            counter=counter+1;
+        }
+        
+        postMethod = new PostMethod(hostAddress + "upload-scenario");
+        postMethod.setRequestEntity(new MultipartRequestEntity(parts,
+                postMethod.getParams()));
+        
+        response = httpClient.executeMethod(postMethod);
+        if (response > 400) {
+            error(Config.getString("export.publish.errorResponse") + " - " + response);
+            return this;
+        }
+        
+        if(! handleResponse(postMethod)) {
+            return this;
+        }
+        
+        // Done.
+        listener.uploadComplete(new PublishEvent(PublishEvent.STATUS));
+        
+        return this;
+    }
+
+    /**
+     * Checks the result of of the given method. Should only be called after the
+     * postMethod has been executed.
+     * 
+     * If the check is successful the method will return true. Otherwise it will
+     * print an error message and return false.
+     * 
+     * @param postMethod The method to check the result for.
+     * @return True if the execution was successful, false otherwise.
+     * @throws NumberFormatException
+     */
+    private boolean handleResponse(PostMethod postMethod)
+    {
+        Header statusHeader = postMethod.getResponseHeader("X-mygame-status");
+        if (statusHeader == null) {
+            error(Config.getString("export.publish.errorResponse"));
+            return false;
+        }
+        String responseString = statusHeader.getValue();
+        int spaceIndex = responseString.indexOf(" ");
+        if (spaceIndex == -1) {
+            error(Config.getString("export.publish.errorResponse"));
+            return false;
+        }
+        try {
+            int statusCode = Integer.parseInt(responseString.substring(0, spaceIndex));
+            switch(statusCode) {
+            case 0 :
+                // Everything is good!
+                return true;
+            case 1 :
+                error(Config.getString("export.publish.errorPassword"));
+                return false;
+            case 2 :
+                error(Config.getString("export.publish.errorTooLarge"));
+                return false;
+            default :
+                // Unknown error - print it!
+                error(responseString.substring(spaceIndex + 1));
+            return false;
+            }
+        }
+        catch (NumberFormatException nfe) {
+            error(Config.getString("export.publish.errorResponse"));
+            return false;
+        }
+    }
+    
+    /**
+     * Get a http client, configured to use the proxy if specified in Greenfoot config
+     */
+    protected HttpClient getHttpClient()
+    {
+        HttpClient httpClient = new HttpClient();
+        
+        String proxyHost = Config.getPropString("proxy.host", null);
+        String proxyPortStr = Config.getPropString("proxy.port", null);
+        if (proxyHost != null && proxyHost.length() != 0 && proxyPortStr != null) {
+            HostConfiguration hostConfig = httpClient.getHostConfiguration();
+
+            int proxyPort = 80;
+            try {
+                proxyPort = Integer.parseInt(proxyPortStr);
+            }
+            catch (NumberFormatException nfe) {}
+
+            hostConfig.setProxy(proxyHost, proxyPort);
+            String proxyUser = Config.getPropString("proxy.user", null);
+            String proxyPass = Config.getPropString("proxy.password", null);
+            if (proxyUser != null) {
+                AuthScope authScope = new AuthScope(proxyHost, proxyPort);
+                Credentials proxyCreds =
+                    new UsernamePasswordCredentials(proxyUser, proxyPass);
+                httpClient.getState().setProxyCredentials(authScope, proxyCreds);
+            }
+        }
+        
+        return httpClient;
+    }
+    
+    /**
+     * Check whether a pre-existing scenario with the given title exists. Returns true
+     * if the scenario exists or false if not.
+     * 
+     * @param hostAddress   The game server address
+     * @param uid           The username of the user
+     * @param gameName      The scenario title
+     * @param info        If not null, this will on return have the title, short description,
+     *                    long description and tags set to whatever the existing scenario has. 
+     * @return  true iff the scenario exists on the server
+     */
+    public boolean checkExistingScenario(String hostAddress, String uid,
+            String gameName, ScenarioInfo info)
+        throws UnknownHostException, IOException
+    {
+        HttpClient client = getHttpClient();
+        client.getHttpConnectionManager().getParams().setConnectionTimeout(20 * 1000);
+        // 20 second timeout is quite generous
+        
+        String encodedName = URLEncoder.encode(gameName, "UTF-8");
+        encodedName = encodedName.replace("+", "%20");
+        GetMethod getMethod = new GetMethod(hostAddress +
+                "user/"+ uid + "/check_scenario/" + encodedName);
+        
+        int response = client.executeMethod(getMethod);
+        if (response > 400) {
+            throw new IOException("HTTP error response " + response + " from server.");
+        }
+        
+        Header statusHeader = getMethod.getResponseHeader("X-mygame-scenario");
+        if (statusHeader == null) {
+            // Weird.
+            throw new IOException("X-mygame-scenario header missing from server response");
+        }
+        else if (!statusHeader.getValue().equals("0 FOUND")) {
+            // not found
+            return false;
+        }
+
+        // found - now we can parse the response
+        if (info != null) {
+            InputStream responseStream = getMethod.getResponseBodyAsStream();
+            parseScenarioXml(info, responseStream);
+            info.setTitle(gameName);
+        }
+        
+        return true;
+    }
+    
+    private void parseScenarioXml(ScenarioInfo info, InputStream xmlStream)
+        throws IOException
+    {
+        try {
+            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+            DocumentBuilder dbuilder = dbf.newDocumentBuilder();
+
+            Document doc = dbuilder.parse(xmlStream);
+            Element root = doc.getDocumentElement();
+            if (root == null || !root.getTagName().equals("scenario")) {
+                return;
+            }
+            
+            NodeList children = root.getChildNodes();
+            for (int i = 0; i < children.getLength(); i++) {
+                Node childNode = children.item(i);
+                if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+                    Element element = (Element) childNode;
+                    if (element.getTagName().equals("shortdescription")) {
+                        info.setShortDescription(element.getTextContent());
+                    }
+                    else if (element.getTagName().equals("longdescription")) {
+                        info.setLongDescription(element.getTextContent());
+                    }
+                    else if (element.getTagName().equals("taglist")) {
+                        info.setTags(parseTagListXmlElement(element));
+                    }
+                    else if (element.getTagName().equals("webpage")) {
+                        info.setUrl(element.getTextContent());
+                    }
+                    else if (element.getTagName().equals("hassource")) {
+                        info.setHasSource(element.getTextContent().equals("true"));
+                    }
+                }
+            }
+        }
+        catch (ParserConfigurationException pce) {
+            // what the heck do we do with this?
+        }
+        catch (SAXException saxe) {
+            
+        }
+    }
+    
+    private List<String> parseTagListXmlElement(Element element)
+    {
+        List<String> tags = new ArrayList<String>();
+        
+        Node child = element.getFirstChild();
+        while (child != null) {
+            if (child.getNodeType() == Node.ELEMENT_NODE) {
+                element = (Element) child;
+                if (element.getTagName().equals("tag")) {
+                    tags.add(element.getTextContent());
+                }
+            }
+            child = child.getNextSibling();
+        }
+        
+        return tags;
+    }
+    
+    /**
+     * Get a list of commonly used tags from the server.
+     * 
+     * @throws UnknownHostException if the host is unknown
+     * @throws org.apache.commons.httpclient.ConnectTimeoutException if the connection timed out
+     * @throws IOException if some other I/O exception occurs
+     */
+    public List<String> getCommonTags(String hostAddress, int maxNumberOfTags)
+        throws UnknownHostException, IOException
+    {
+        HttpClient client = getHttpClient();
+        client.getHttpConnectionManager().getParams().setConnectionTimeout(20 * 1000);
+        
+        GetMethod getMethod = new GetMethod(hostAddress +
+                "common-tags/"+ maxNumberOfTags);
+        
+        int response = client.executeMethod(getMethod);
+        if (response > 400) {
+            throw new IOException("HTTP error response " + response + " from server.");
+        }
+        
+        // found - now we can parse the response
+        InputStream responseStream = getMethod.getResponseBodyAsStream();
+        
+        try {
+            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+            DocumentBuilder dbuilder = dbf.newDocumentBuilder();
+
+            Document doc = dbuilder.parse(responseStream);
+            Element root = doc.getDocumentElement();
+            if (root == null || !root.getTagName().equals("taglist")) {
+                return Collections.<String>emptyList();
+            }
+
+            return parseTagListXmlElement(root);
+        }
+        catch(SAXException saxe) { }
+        catch(ParserConfigurationException pce) { }
+        finally {
+            responseStream.close();
+        }
+        
+        return Collections.<String>emptyList();
+    }
+    
+    /**
+     * An error occurred.
+     */
+    private void error(String s)
+    {
+        listener.errorRecieved(new PublishEvent(s, PublishEvent.ERROR));
+    }
+    
+    /**
+     * The specified number of bytes have just been sent.
+     */
+    public void progress(int bytes)
+    {
+        listener.progressMade(new PublishEvent(bytes, PublishEvent.PROGRESS));
+    }
+    
+    /**
+     * Prompt the user for proxy authentication details (username and password).
+     * 
+     * @return A 2-element array with the username as the first element and the password as the second,
+     *         or null if the user elected to cancel the upload.
+     */
+    public String[] promptProxyAuth()
+    {
+        return listener.needProxyAuth();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/ProgressTrackingPart.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/ProgressTrackingPart.java
new file mode 100644
index 0000000000000000000000000000000000000000..fe92638960272ac5db8e0a061918d28b3d1f8285
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/ProgressTrackingPart.java
@@ -0,0 +1,69 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.export.mygame;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.httpclient.methods.multipart.FilePart;
+
+/**
+ * A FilePart which tracks upload progress.
+ * 
+ * @author Davin McCall
+ */
+public class ProgressTrackingPart extends FilePart
+{
+    private MyGameClient listener;
+    
+    public ProgressTrackingPart(String partName, File file, MyGameClient listener)
+        throws FileNotFoundException
+    {
+        super(partName, file);
+        this.listener = listener;
+    }
+    
+    @Override
+    protected void sendData(OutputStream output) throws IOException
+    {
+        if (lengthOfData() == 0) {
+            return;
+        }
+        
+        byte [] buf = new byte[4096];
+        InputStream istream = getSource().createInputStream();
+        try {
+            int len = istream.read(buf);
+            while (len != -1) {
+                output.write(buf, 0, len);
+                listener.progress(len);
+                len = istream.read(buf);
+            }
+        }
+        finally {
+            istream.close();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/ScenarioInfo.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/ScenarioInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..d0ead47eae8cda6c1f220a6e9b3c929190144a53
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/export/mygame/ScenarioInfo.java
@@ -0,0 +1,231 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009, 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.export.mygame;
+
+import greenfoot.core.ProjectProperties;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Holds various information about a scenario.
+ * 
+ * @author Davin McCall
+ */
+public class ScenarioInfo
+{
+    private String title;
+    private String shortDescription;
+    private String longDescription;
+    private String updateDescription;
+    private List<String> tags;
+    private String url;
+    private boolean hasSource;
+    private boolean isLocked;
+    private boolean isUpdate = false;
+    
+    private static final String PUBLISH_TITLE = "publish.title";
+    private static final String PUBLISH_SHORT_DESC = "publish.shortDesc";
+    private static final String PUBLISH_LONG_DESC = "publish.longDesc";
+    private static final String PUBLISH_URL = "publish.url";
+    private static final String PUBLISH_TAGS = "publish.tags";
+    private static final String PUBLISH_HAS_SOURCE = "publish.hasSource";
+    private static final String PUBLISH_LOCKED = "publish.locked";
+    private static final String PUBLISH_UPDATE_DESC = "publish.updateDesc";
+    
+    public void setTitle(String title)
+    {
+        if (title!=null) {
+            this.title = title.trim();
+        }
+    }
+    
+    public String getTitle()
+    {
+        return title;
+    }
+
+    public void setShortDescription(String shortDesc)
+    {
+        shortDescription = shortDesc;
+    }
+    
+    public String getShortDescription()
+    {
+        return shortDescription;
+    }
+    
+    public void setLongDescription(String longDesc)
+    {
+        longDescription = longDesc;
+    }
+    
+    public String getLongDescription()
+    {
+        return longDescription;
+    }
+    
+    public void setTags(List<String> tags)
+    {
+        this.tags = tags;
+    }
+ 
+    public List<String> getTags()
+    {
+        return tags;
+    }
+    
+    public void setUrl(String url)
+    {
+        this.url = url;
+    }
+    
+    public String getUrl()
+    {
+        return url;
+    }
+    
+    public void setHasSource(boolean hasSource)
+    {
+        this.hasSource = hasSource;
+    }
+    
+    public boolean isLocked()
+    {
+        return isLocked;
+    }
+    
+    public void setLocked(boolean locked)
+    {
+        this.isLocked = locked;
+    }
+    
+    public boolean getHasSource()
+    {
+        return hasSource;
+    }
+    
+    /**
+     * Stores the scenario information into the specified project properties.
+     */
+    public void store(ProjectProperties properties)
+    {
+        properties.setString(PUBLISH_TITLE, getTitle());
+        if (getShortDescription()!=null)
+        {
+            properties.setString(PUBLISH_SHORT_DESC, getShortDescription());
+        }
+        if (getLongDescription()!=null) 
+        {
+            properties.setString(PUBLISH_LONG_DESC, getLongDescription());
+        }
+        properties.setString(PUBLISH_URL, getUrl());
+        properties.setString(PUBLISH_TAGS, getTagsAsString());
+        properties.setBoolean(PUBLISH_HAS_SOURCE, getHasSource());
+        properties.setBoolean(PUBLISH_LOCKED, isLocked());
+        if (getUpdateDescription() !=null){
+            properties.setString(PUBLISH_UPDATE_DESC, getUpdateDescription());
+        }
+    }
+
+    private String getTagsAsString()
+    {
+        StringBuilder tags = new StringBuilder();
+        List<String> tagList = getTags();
+        for (Iterator<String> iterator = tagList.iterator(); iterator.hasNext();) {
+            String tag = iterator.next();
+            tags.append(tag);
+            tags.append(" ");
+        }
+        return tags.toString();
+    }
+
+    /**
+     * Attempts to load previously saved ScenarioInfo for this project.
+     * 
+     * @return true if it found and loaded the stored values.
+     */
+    public boolean load(ProjectProperties properties)
+    {
+        //if it is a saved scenario it should have at least a title set
+        if (properties.getString(PUBLISH_TITLE) == null) {
+            return false;
+        }
+        setTitle(properties.getString(PUBLISH_TITLE));
+        setShortDescription(properties.getString(PUBLISH_SHORT_DESC));
+        setLongDescription(properties.getString(PUBLISH_LONG_DESC));
+        setUrl(properties.getString(PUBLISH_URL));
+        List<String> tagList = new LinkedList<String>();
+        String tags = properties.getString(PUBLISH_TAGS);
+        if (tags!=null){
+            String[] tagArray = tags.split(" ");
+            for (int i = 0; i < tagArray.length; i++) {
+                String string = tagArray[i];
+                tagList.add(string);
+            }
+        }
+        setTags(tagList);
+        setHasSource(properties.getBoolean(PUBLISH_HAS_SOURCE, "false"));
+        setLocked(properties.getBoolean(PUBLISH_LOCKED, "true"));
+        setUpdateDescription(properties.getString(PUBLISH_UPDATE_DESC));
+        return true;
+    }
+
+    /**
+     * If we're updating an existing scenario, return a description of the udpate.
+     * @see #isUpdate()
+     */
+    public String getUpdateDescription()
+    {
+        return updateDescription;
+    }
+
+    /**
+     * Set the update description (if this is an update).
+     * @param updateDescription   The update description provided by the user.
+     * @see #setUpdate(boolean)
+     */
+    public void setUpdateDescription(String updateDescription)
+    {
+        this.updateDescription = updateDescription;
+    }
+
+    /**
+     * Check whether this is (as far as we're aware) an update of an existing scenario.
+     * If it is {@link #getUpdateDescription()} will return a description of the update.
+     */
+    public boolean isUpdate()
+    {
+        return isUpdate;
+    }
+
+    /**
+     * Specify whether this is an update of an existing scenario. Also use {@link #setUpdateDescription(String)}
+     * to set the update description as provided by the user.
+     */
+    public void setUpdate(boolean isUpdate)
+    {
+        this.isUpdate = isUpdate;
+    }
+ 
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/AboutGreenfootDialog.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/AboutGreenfootDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ee92b06acdb8b310ff7388fd45f3bfae35ce091
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/AboutGreenfootDialog.java
@@ -0,0 +1,139 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.net.URL;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.utility.DialogManager;
+import bluej.utility.MultiLineLabel;
+
+/**
+ * The BlueJ about box.
+ * 
+ * @author Poul Henriksen
+ * @version $Id: AboutGreenfootDialog.java 9003 2011-06-16 13:11:18Z mik $
+ */
+public class AboutGreenfootDialog extends JDialog
+{
+    private static final String dialogTitle =Config.getString("about.title");
+
+    public AboutGreenfootDialog(JFrame parent, String version)
+    {
+        super(parent, dialogTitle, true);
+
+        // Create About box text
+        JPanel aboutPanel = new JPanel();
+        aboutPanel.setBorder(BlueJTheme.dialogBorder);
+        aboutPanel.setLayout(new BorderLayout(12, 0));
+        aboutPanel.setBackground(Color.white);
+
+        // insert logo
+        URL splashURL = this.getClass().getClassLoader().getResource("greenfoot-about.jpg");
+        Icon icon = new ImageIcon(splashURL);
+        JLabel logoLabel = new JLabel(icon);
+        aboutPanel.add(logoLabel, BorderLayout.WEST);
+
+        // Create Text Panel
+        MultiLineLabel text = new MultiLineLabel(LEFT_ALIGNMENT, 6);
+        text.setBackground(Color.white);
+        text.addText("The Greenfoot team:" + "\n ", false, true);
+        text.addText("      Neil Brown\n");     
+        text.addText("      Michael K\u00F6lling\n");
+        text.addText("      Davin McCall\n");
+        text.addText("      John Rosenberg\n");
+        text.addText("      Philip Stevens\n");        
+        text.addText("      Ian Utting\n");
+        text.addText("      Marion Zalk\n");        
+        aboutPanel.add(text, BorderLayout.CENTER);
+
+        // footer text
+        MultiLineLabel bottomtext = new MultiLineLabel(LEFT_ALIGNMENT);
+        bottomtext.setBackground(Color.white);
+        bottomtext.addText(" ");
+        bottomtext.addText("Greenfoot version " + version + "  (" + Config.getString("about.java.version") + " "
+                + System.getProperty("java.version") + ")", true, false);
+        bottomtext.addText(" ");
+        bottomtext.addText(Config.getString("about.vm") + " " + System.getProperty("java.vm.name") + " "
+                + System.getProperty("java.vm.version") + " (" + System.getProperty("java.vm.vendor") + ")");
+        bottomtext.addText(Config.getString("about.runningOn") + " " + System.getProperty("os.name") + " "
+                + System.getProperty("os.version") + " (" + System.getProperty("os.arch") + ")");
+        bottomtext.addText(Config.getString("about.javahome") + " " + System.getProperty("java.home"));
+        bottomtext.addText(" ");
+        bottomtext.addText(Config.getString("about.moreInfo"));
+        bottomtext.addText(" ");
+        bottomtext.addText(Config.getString("about.logfile") + " " + Config.getUserConfigFile(Config.greenfootDebugLogName));
+
+        aboutPanel.add(bottomtext, BorderLayout.SOUTH);
+
+        // Create Button Panel
+        JPanel buttonPanel = new JPanel();
+        // buttonPanel.setBackground(Color.white);
+        buttonPanel.setLayout(new FlowLayout());
+        JButton ok = BlueJTheme.getOkButton();
+        buttonPanel.add(ok);
+
+        getContentPane().setLayout(new BorderLayout());
+        getContentPane().add(aboutPanel, BorderLayout.CENTER);
+        getContentPane().add(buttonPanel, BorderLayout.SOUTH);
+
+        // Close Action when OK is pressed
+        ok.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent event)
+            {
+                setVisible(false);
+                dispose();
+            }
+        });
+
+        // Close Action when close button is pressed
+        addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent event)
+            {
+                Window win = (Window) event.getSource();
+                win.setVisible(false);
+                win.dispose();
+            }
+        });
+
+        setResizable(false);
+        pack();
+        DialogManager.centreDialog(this);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/CenterLayout.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/CenterLayout.java
new file mode 100644
index 0000000000000000000000000000000000000000..53791517e1c9ad5dd70bae65c300458def529753
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/CenterLayout.java
@@ -0,0 +1,112 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+
+/**
+ * This is a layout class for a container that has exactly one child component.
+ * The layout places that child in the centre of the container.
+ *
+ * @author mik
+ * @version 0.2
+ */
+public class CenterLayout implements LayoutManager
+{
+    public CenterLayout()
+    {
+    }
+    
+    @Override
+    public void layoutContainer(Container target)
+    {
+        synchronized (target.getTreeLock()) {
+            Insets insets = target.getInsets();
+            int maxwidth = target.getWidth() - (insets.left + insets.right);
+            int maxheight = target.getHeight() - (insets.top + insets.bottom);
+
+            Component m = target.getComponent(0);
+            if (m.isVisible()) {
+                Dimension d = m.getPreferredSize();
+                d.width = Math.min(d.width, maxwidth);
+                d.height = Math.min(d.height, maxheight);
+                m.setSize(d);
+
+                int hspace = maxwidth - d.width;
+                int xpos = insets.left + (hspace / 2);
+
+                int vspace = maxheight - d.height;
+                int ypos = insets.top + (vspace / 2);
+
+                m.setLocation(xpos, ypos);
+            }
+        }
+    }
+    
+    @Override
+    public void addLayoutComponent(String name, Component comp)
+    {
+    }
+
+    @Override
+    public void removeLayoutComponent(Component comp)
+    {
+    }
+
+    @Override
+    public Dimension preferredLayoutSize(Container parent)
+    {
+        Dimension d;
+        if (parent.getComponentCount() > 0) {
+            Component m = parent.getComponent(0);
+            d = m.getPreferredSize();
+        }
+        else {
+            d = new Dimension(0,0);
+        }
+        Insets insets = parent.getInsets();
+        d.height += insets.top + insets.bottom;
+        d.width += insets.left + insets.right;
+        return d;
+    }
+
+    @Override
+    public Dimension minimumLayoutSize(Container parent)
+    {
+        Dimension d;
+        if (parent.getComponentCount() > 0) {
+            Component m = parent.getComponent(0);
+            d = m.getMinimumSize();
+        }
+        else {
+            d = new Dimension(0,0);
+        }
+        Insets insets = parent.getInsets();
+        d.height += insets.top + insets.bottom;
+        d.width += insets.left + insets.right;
+        return d;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/ClassNameVerifier.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/ClassNameVerifier.java
new file mode 100644
index 0000000000000000000000000000000000000000..f769fbe628a6ec2a31fe83a43010796d9154d7c4
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/ClassNameVerifier.java
@@ -0,0 +1,218 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import greenfoot.core.GPackage;
+import greenfoot.event.ValidityEvent;
+import greenfoot.event.ValidityListener;
+
+import javax.swing.InputVerifier;
+import javax.swing.JComponent;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.EventListenerList;
+
+import bluej.Config;
+import bluej.utility.JavaNames;
+
+/**
+ * Class that verifies a class name typed into a TextField. It checks that the
+ * class name is a legal name of a Java class and that the class does not
+ * already exist. It is also possible to listen for changes in the validity of
+ * the TextField.
+ * 
+ * @author Poul Henriksen
+ */
+public class ClassNameVerifier extends InputVerifier
+    implements DocumentListener
+{
+    private EventListenerList listenerList = new EventListenerList();
+    private String classExists = Config.getString("newclass.dialog.err.classExists");
+    private String illegalClassName = Config.getString("newclass.dialog.err.classNameIllegal");
+    
+    /** Is the text field currently in a valid state? */
+    private boolean valid = false;
+
+    /**
+     * Flag used to indicate whether it is the first check. If it is, we should
+     * fire an event no matter what.
+     */
+    private boolean firstCheck = true;
+
+    /** The package the class will be added to */
+    private GPackage pkg;
+
+    /** The text field to listen for DocumentEvents on */
+    private JTextField textField;
+
+    /**
+     * Create new class name verifier. This will add the appropate listeners to
+     * the textField.
+     * <p>
+     * If using a Cancel button it might be useful to set
+     * {@link JComponent.#setVerifyInputWhenFocusTarget(boolean)} to false on
+     * the cancel button.
+     * 
+     * @param pkg
+     *            Package containing the user classes for which to check
+     *            against.
+     */
+    public ClassNameVerifier(JTextField textField, GPackage pkg)
+    {
+        this.pkg = pkg;
+        this.textField = textField;
+        textField.getDocument().addDocumentListener(this);
+        textField.setInputVerifier(this);
+        textField.setVerifyInputWhenFocusTarget(true);
+    }
+
+    /**
+     * Verifies that the TextField doesn't contain the name of an existing
+     * class.
+     * 
+     * @param jTextField
+     *            The component must be of the type JTextField.
+     */
+    @Override
+    public boolean verify(JComponent textField)
+    {
+        if(this.textField != textField) {
+            System.err.println("Illegal textfield verified.");
+            return false;
+        }
+        String className = this.textField.getText();
+        return JavaNames.isIdentifier(className) && !classNameExist(className) && !isGreenfootClassName(className);
+    }
+
+    @Override
+    public boolean shouldYieldFocus(JComponent jTextField)
+    {
+        return checkValidity();
+    }
+
+    private boolean isGreenfootClassName(String className)
+    {
+        return className.equals("Actor") || className.equals("World");
+    }
+    
+    /**
+     * Returns true if a class with the given name already exists.
+     * 
+     * @param className
+     * @return
+     */
+    private boolean classNameExist(String className)
+    {
+        return pkg.getClass(className) != null;
+    }
+
+    /**
+     * Checks whether the text field contains a valid class name. It will send
+     * the relevant events to notify ValidityListeners.
+     * 
+     * @return true, if it is valid.
+     */
+    private boolean checkValidity()
+    {
+        boolean inputOK = verify(textField);
+        if (inputOK != valid || firstCheck) {
+            firstCheck = false;
+            valid = inputOK;
+            if (valid) {
+                fireValidEvent(new ValidityEvent(textField, "All OK"));
+            }
+            else {
+                String className = textField.getText();
+                ValidityEvent validityEvent = null;
+                if (classNameExist(className) || isGreenfootClassName(className)) {
+                    validityEvent = new ValidityEvent(textField, classExists);
+                }
+                else {
+                    validityEvent = new ValidityEvent(textField, illegalClassName);
+                }
+                fireInvalidEvent(validityEvent);
+            }
+        }
+        return inputOK;
+    }
+
+    /**
+     * Adds a listener to receive events when the validity of the component
+     * changes.
+     */
+    public void addValidityListener(ValidityListener l)
+    {
+        listenerList.add(ValidityListener.class, l);
+    }
+
+    public void removeValidityListner(ValidityListener l)
+    {
+        listenerList.remove(ValidityListener.class, l);
+    }
+
+    private void fireValidEvent(ValidityEvent event)
+    {
+        // Guaranteed to return a non-null array
+        Object[] listeners = listenerList.getListenerList();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length - 2; i >= 0; i -= 2) {
+            if (listeners[i] == ValidityListener.class) {
+                ((ValidityListener) listeners[i + 1]).changedToValid(event);
+            }
+        }
+    }
+
+    private void fireInvalidEvent(ValidityEvent event)
+    {
+        // Guaranteed to return a non-null array
+        Object[] listeners = listenerList.getListenerList();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length - 2; i >= 0; i -= 2) {
+            if (listeners[i] == ValidityListener.class) {
+                ((ValidityListener) listeners[i + 1]).changedToInvalid(event);
+            }
+        }
+    }
+
+    private void change()
+    {
+        checkValidity();
+    }
+
+    public void changedUpdate(DocumentEvent e)
+    {
+        // Nothing to do
+    }
+
+    public void insertUpdate(DocumentEvent e)
+    {
+        change();
+    }
+
+    public void removeUpdate(DocumentEvent e)
+    {
+        change();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/ControlPanel.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/ControlPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c73c9e261e57d875ce4385eb9dad9c0f8360dd5
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/ControlPanel.java
@@ -0,0 +1,226 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import greenfoot.actions.PauseSimulationAction;
+import greenfoot.actions.ResetWorldAction;
+import greenfoot.actions.RunOnceSimulationAction;
+import greenfoot.actions.RunSimulationAction;
+import greenfoot.core.Simulation;
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.FlowLayout;
+
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import bluej.Config;
+
+/**
+ * Panel that holds the buttons that controls the simulation.
+ * 
+ * @author Poul Henriksen
+ */
+public class ControlPanel extends Box
+    implements ChangeListener, SimulationListener
+{
+    private RunSimulationAction runSimulationAction;
+    private PauseSimulationAction pauseSimulationAction;
+    private RunOnceSimulationAction runOnceSimulationAction;
+
+    private ResetWorldAction resetWorldAction ;
+    private JSlider speedSlider;
+ 
+    private Simulation simulation;
+    private JPanel buttonPanel;
+    private JButton pauseButton;
+    private JButton runButton;
+    
+    /**
+     * 
+     * @param simulation
+     * @param includeAllControls If false, the act-button and speedslider will be excluded.
+     */
+    public ControlPanel(Simulation simulation, boolean includeAllControls)
+    {
+        super(BoxLayout.X_AXIS);
+        
+        this.simulation = simulation;
+        
+        add(createButtonPanel(simulation, includeAllControls));
+
+        if (includeAllControls) {
+            add(createSpeedSlider());
+        }
+        simulation.addSimulationListener(this);
+
+    }
+
+    private JPanel createButtonPanel(Simulation simulation, boolean includeAllControls)
+    {
+        buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
+        
+        if (includeAllControls) {
+            runOnceSimulationAction = RunOnceSimulationAction.getInstance();
+            runOnceSimulationAction.attachSimulation(simulation);
+            runOnceSimulationAction.putValue(Action.LONG_DESCRIPTION, 
+                Config.getString("controls.runonce.longDescription"));
+            runOnceSimulationAction.putValue(Action.SHORT_DESCRIPTION, 
+                Config.getString("controls.runonce.shortDescription"));
+            runOnceSimulationAction.setEnabled(false);
+            AbstractButton stepButton = GreenfootUtil.createButton(runOnceSimulationAction);
+
+            buttonPanel.add(stepButton);
+        }
+
+        runSimulationAction = RunSimulationAction.getInstance();
+        runSimulationAction.attachSimulation(simulation);
+        runSimulationAction.putValue(Action.LONG_DESCRIPTION, 
+            Config.getString("controls.run.longDescription"));
+        runSimulationAction.putValue(Action.SHORT_DESCRIPTION, 
+            Config.getString("controls.run.shortDescription"));
+        runSimulationAction.setEnabled(false);
+        runButton = GreenfootUtil.createButton(runSimulationAction);
+
+        pauseSimulationAction = PauseSimulationAction.getInstance();
+        pauseSimulationAction.attachSimulation(simulation);
+        pauseSimulationAction.putValue(Action.LONG_DESCRIPTION, 
+            Config.getString("controls.pause.longDescription"));
+        pauseSimulationAction.putValue(Action.SHORT_DESCRIPTION, 
+            Config.getString("controls.pause.shortDescription"));
+        pauseSimulationAction.setEnabled(false);
+        pauseButton = GreenfootUtil.createButton(pauseSimulationAction);
+        
+        // Make buttons the same size
+        if(pauseButton.getPreferredSize().getWidth() > runButton.getPreferredSize().getWidth()) {
+            runButton.setPreferredSize(pauseButton.getPreferredSize());
+            runButton.setMaximumSize(pauseButton.getMaximumSize());
+            runButton.setMinimumSize(pauseButton.getMinimumSize());
+        } else  {
+            pauseButton.setPreferredSize(runButton.getPreferredSize());
+            pauseButton.setMaximumSize(runButton.getMaximumSize());
+            pauseButton.setMinimumSize(runButton.getMinimumSize());
+        }
+        
+        buttonPanel.add(runButton);
+                
+        resetWorldAction = ResetWorldAction.getInstance();
+        resetWorldAction.putValue(Action.LONG_DESCRIPTION, Config.getString("controls.reset.longDescription"));
+        resetWorldAction.putValue(Action.SHORT_DESCRIPTION, Config.getString("controls.reset.shortDescription"));
+        resetWorldAction.attachSimulation(simulation);
+        resetWorldAction.setEnabled(false);
+        AbstractButton resetButton = GreenfootUtil.createButton(resetWorldAction);
+        buttonPanel.add(resetButton);
+        
+        return buttonPanel;
+    }
+
+    private JComponent createSpeedSlider()
+    {
+        JPanel speedPanel = new JPanel(new FlowLayout());
+        JLabel speedLabel = new JLabel(Config.getString("controls.speed.label"));
+        speedPanel.add(speedLabel);
+        
+        int min = 0;
+        int max = Simulation.MAX_SIMULATION_SPEED;
+        speedSlider = new JSlider(JSlider.HORIZONTAL, min, max, simulation.getSpeed());
+        speedSlider.setPaintLabels(false);
+        speedSlider.setMajorTickSpacing( max / 2);
+        speedSlider.setMinorTickSpacing( max / 4);
+        speedSlider.setPaintTicks(true);
+        speedSlider.setEnabled(false);
+        speedSlider.addChangeListener(this);
+        speedSlider.setToolTipText(Config.getString("controls.speedSlider.tooltip"));
+        speedSlider.setFocusable(false);
+        speedPanel.add(speedSlider);
+        
+        return speedPanel;
+    }
+    
+    @Override
+    public void simulationChanged(SimulationEvent e)
+    {        
+        final int etype = e.getType();
+        if (etype == SimulationEvent.DEBUGGER_PAUSED
+              || etype == SimulationEvent.DEBUGGER_RESUMED) {
+            // we don't care about these events here so we want to avoid
+            // creating a new thread below.
+            return;
+        }
+
+        SwingUtilities.invokeLater(new Thread() {
+            public void run()
+            {
+                if (etype == SimulationEvent.STARTED) {
+                    if (speedSlider != null) {
+                        speedSlider.setEnabled(true);
+                    }
+                    buttonPanel.remove(runButton);
+                    buttonPanel.add(pauseButton, 1);
+                    buttonPanel.validate();
+                }
+                else if (etype == SimulationEvent.STOPPED) {
+                    if (speedSlider != null) {
+                        speedSlider.setEnabled(true);
+                    }
+                    buttonPanel.remove(pauseButton);
+                    buttonPanel.add(runButton, 1);
+                    buttonPanel.validate();
+                }
+                else if (etype == SimulationEvent.CHANGED_SPEED) {
+                    if (speedSlider != null) {
+                        speedSlider.setEnabled(true);
+                        int newSpeed = simulation.getSpeed();
+                        if (newSpeed != speedSlider.getValue()) {
+                            speedSlider.setValue(newSpeed);
+                        }
+                    }
+                }
+                else if (etype == SimulationEvent.DISABLED) {
+                    if (speedSlider != null) {
+                        speedSlider.setEnabled(false);
+                    }
+                }
+            }
+        });
+    }
+    
+
+    // ---------- ChangeListener interface (for speed slider changes) -----------
+    
+    public void stateChanged(ChangeEvent e)
+    {
+        simulation.setSpeed(speedSlider.getValue());
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/DragGlassPane.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/DragGlassPane.java
new file mode 100644
index 0000000000000000000000000000000000000000..1d65dfae518b2eb71aa3b37a46a9b3dcb4c15140
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/DragGlassPane.java
@@ -0,0 +1,531 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+import greenfoot.GreenfootImage;
+import greenfoot.core.GClass;
+import greenfoot.core.WorldHandler;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.gui.classbrowser.SelectionManager;
+import greenfoot.gui.classbrowser.role.ActorClassRole;
+import greenfoot.gui.input.mouse.LocationTracker;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.image.BufferedImage;
+import java.net.URL;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JMenuBar;
+import javax.swing.RootPaneContainer;
+import javax.swing.SwingUtilities;
+
+/**
+ * Component that can be used for dragging. It should be used as a glasspane on
+ * a JFrame. A drag is started with the startDrag() method. The drag will end
+ * when the mouse is released and the component on that location get the
+ * MouseEvent (mouseReleased)
+ * <p>
+ * All instance methods in this class should be called on the Swing event thread.
+ * <p>
+ * This component is used for dragging initiated either by invoking a
+ * constructor through the menus or by using the SHIFT-add feature.
+ * <p>
+ * Some of this is taken from:
+ * http://java.sun.com/docs/books/tutorial/uiswing/components/example-1dot4/GlassPaneDemo.java
+ * 
+ * after startDrag(): - drag() sent to drop target when object is dragged over
+ * it - dragEnded() sent to drop target when object is dragged off it
+ * 
+ * If the object is dropped on a drop target: - drop() is sent to the drop
+ * target (dragEnded() is not sent) - dragFinished() is sent to the drag
+ * listener
+ * 
+ * If the drag is cancelled: - dragEnded() is sent to the drop target -
+ * dragFinished() is sent to the drag listener
+ * 
+ * @author Poul Henriksen
+ * @version $Id: DragGlassPane.java 8232 2010-09-02 10:06:20Z nccb $
+ * 
+ */
+public class DragGlassPane extends JComponent
+    implements TriggeredMouseMotionListener, TriggeredMouseListener, DragListener
+{
+    /** Singleton */
+    private static DragGlassPane instance;
+
+    /** The image displayed when dragging where no DropTarget is below */
+    private Icon noParkingIcon;
+
+    /** Should the dragGlassPane display the no drop image? */
+    private boolean paintNoDropImage;
+
+    /** The object that is dragged */
+    private Object data;
+
+    /** Rectangle defining the current bounds of the object being dragged */
+    private Rectangle dragRect = new Rectangle();
+
+    /** Rectangle defining the last bounds of where a drag object was painted */
+    private Rectangle lastPaintRect = new Rectangle();
+
+    /**
+     * Keeps track of the last drop target, in order to send messages to old
+     * drop targets when drag moves away from the component
+     */
+    private DropTarget lastDropTarget;
+
+    /**
+     * The listener to be notified when the drag operation finishes.
+     */
+    private DragListener dragListener;
+
+    /**
+     * Image used when dragging. If this is null, no dragging is happening at
+     * the moment.
+     */
+    private BufferedImage dragImage;
+
+    private boolean isQuickAddActive;
+
+    private SelectionManager classSelectionManager;
+
+    private boolean listening;
+
+    /**
+     * Sets the selection manager.
+     * 
+     * @param selectionManager
+     */
+    public void setSelectionManager(SelectionManager selectionManager)
+    {
+        this.classSelectionManager = selectionManager;
+    }
+
+    public static DragGlassPane getInstance()
+    {
+        if (instance == null) {
+            instance = new DragGlassPane();
+        }
+        return instance;
+    }
+
+    private DragGlassPane()
+    {
+        this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+        URL noParkingIconFile = this.getClass().getClassLoader().getResource("noParking.png");
+        if (noParkingIconFile != null) {
+            noParkingIcon = new ImageIcon(noParkingIconFile);
+        }
+    }
+
+    public void paintComponent(Graphics g)
+    {
+        // We only handle painting here if no drop-target could handle the
+        // painting, and if we have a dragImage
+        if (dragImage != null && paintNoDropImage) {
+            Graphics2D g2 = (Graphics2D) g;
+            // Set the clip to be the union between the image we are going to
+            // paint now, and the previously painted image.
+            Rectangle currentClip = new Rectangle(dragRect.x, dragRect.y, dragImage.getWidth(), dragImage.getHeight());
+            Rectangle temp = new Rectangle(currentClip);
+            currentClip.add(lastPaintRect);
+            lastPaintRect = temp;
+            g2.clip(currentClip);
+            g2.drawImage(dragImage, dragRect.x, dragRect.y, null);
+        }
+        else {
+            // we do nothing - a DropTarget should have handled this
+        }
+    }
+
+    /**
+     * Initiates a drag.
+     * <p>
+     * 
+     * There are two types of drag: a "genuine" drag where an object is being
+     * dragged with the mouse button down, and a "forced" drag where the button
+     * is up. In the case of a genuine drag, the DragGlassPane should be added
+     * as a MouseListener and MouseMotionListener to the component receiving the
+     * drag events. Otherwise, this is not necessary.
+     * 
+     * @param object
+     *            The object to drag.
+     * @param dl
+     *            The listener to be notified when the operation finishes
+     * @param initialDropTarget
+     *            An initial drop target. It can be null. Used when we want to
+     *            immediately paint a dragImage unto the drop target.
+     * @param forcedDrag
+     *            indicates whether the drag is done without any buttons
+     *            pressed. This allows the drag to continue even if no keyboard
+     *            or mouse buttons are pressed.
+     * 
+     */
+    private void startDrag(Actor object, DragListener dl, DropTarget initialDropTarget, boolean forcedDrag)
+    {
+        // Save the listener first, so that calls to endDrag() work.
+        dragListener = dl;
+
+        if (object == null) {
+            endDrag();
+            return;
+        }
+        GreenfootImage objectImage = ActorVisitor.getDragImage(object);
+
+        // get last mouseevent to get first location
+        MouseEvent e = LocationTracker.instance().getMouseMotionEvent();
+        if (e == null) {
+            // This startDrag was probably initiated by a mouse event that was
+            // handled before the LocationTracker got a chance to handle it.
+            endDrag();
+            return;
+        }
+
+        setDragImage(objectImage);
+        setDragObject(object);
+        paintNoDropImage = true;
+
+        storePosition(e);
+        lastDropTarget = initialDropTarget;
+
+        setVisible(true);
+        if (initialDropTarget != null) {
+            // force painting of drag object
+            Point p = e.getPoint();
+            paintNoDropImage = !initialDropTarget.drag(object, p);
+            if (paintNoDropImage) {
+                repaint();
+            }
+        }
+    }
+
+    /**
+     * Call this method to cancel a drag/drop operation. dragEnded() will be
+     * called for the dropTarget over which the object is currently being
+     * dragged, and then dragFinished() will be called on the DragListener.
+     */
+    private void cancelDrag()
+    {
+        isQuickAddActive = false;
+        endDrag();
+    }
+
+    /**
+     * The drag is finished.
+     */
+    private void endDrag()
+    {
+        if (lastDropTarget != null) {
+            lastDropTarget.dragEnded(data);
+        }
+
+        // Save the old values of dragListener and data for the "dragFinished"
+        // call below
+        DragListener dl = dragListener;
+        Object od = data;
+
+        setVisible(false);
+        data = null;
+        dragImage = null;
+        dragListener = null;
+
+        // Call dragFinished
+        if (dl != null) {
+            dl.dragFinished(od);
+        }
+    }
+
+    /**
+     * Sets the image to be dragged around
+     * 
+     * @param image
+     *            The image
+     */
+    public void setDragImage(final greenfoot.GreenfootImage image)
+    {
+        BufferedImage awtImage = image.getAwtImage();
+
+        // TODO: run on event thread since it is used in paintComponent?
+        dragImage = GreenfootUtil.createDragShadow(awtImage);
+
+        dragRect.width = image.getWidth();
+        dragRect.height = image.getHeight();
+
+        Graphics2D g = dragImage.createGraphics();
+
+        // We use original image proportions, to get the icon in the middle when
+        // not considering the shadow.
+        int x = (image.getWidth() - noParkingIcon.getIconWidth()) / 2;
+        int y = (image.getHeight() - noParkingIcon.getIconHeight()) / 2;
+        g.setColor(Color.RED);
+        noParkingIcon.paintIcon(this, g, x, y);
+        g.dispose();
+    }
+
+    /**
+     * Sets the object to be dragged.
+     * 
+     * @param object
+     */
+    public void setDragObject(final Object object)
+    {
+        data = object;
+    }
+
+    private void move(MouseEvent e)
+    {
+        if (dragImage == null) {
+            // No valid drag object available.
+            return;
+        }
+        storePosition(e);
+        boolean doRepaint = true;
+        Component destination = getComponentBeneath(e);
+        DropTarget dropTarget = null;
+        if (destination instanceof DropTarget) {
+            dropTarget = (DropTarget) destination;
+
+            Point tp = e.getPoint().getLocation(); // copy the point
+            Point p = SwingUtilities.convertPoint(e.getComponent(), tp, destination);
+            if (dropTarget.drag(data, p)) {
+                if (paintNoDropImage) {
+                    paintNoDropImage = false;
+                }
+                else {
+                    // The dropTarget has handled repaint, and since
+                    // paintNoDropImage didn't changed state we do not need a
+                    // repaint
+                    doRepaint = false;
+                }
+            }
+            else {
+                paintNoDropImage = true;
+            }
+        }
+        else {
+            paintNoDropImage = true;
+        }
+
+        if (lastDropTarget != null && dropTarget != lastDropTarget) {
+            lastDropTarget.dragEnded(data);
+        }
+        lastDropTarget = dropTarget;
+        if (isVisible() && doRepaint) {
+            // We need to repaint because the drag was not processed by another
+            // component.
+            repaint();
+        }
+
+    }
+
+    public void mouseMoved(MouseEvent e)
+    {
+        move(e);
+    }
+
+    public void mouseDragged(MouseEvent e)
+    {
+        move(e);
+    }
+
+    public void mouseClicked(MouseEvent e)
+    {}
+
+    public void mouseEntered(MouseEvent e)
+    {}
+
+    public void mouseExited(MouseEvent e)
+    {}
+
+    public void mousePressed(MouseEvent e)
+    {}
+
+    public void mouseReleased(MouseEvent e)
+    {
+        Component destination = getComponentBeneath(e);
+
+        if (destination != null && destination instanceof DropTarget) {
+            DropTarget dropTarget = (DropTarget) destination;
+            Point tp = e.getPoint().getLocation();
+            Point destinationPoint = SwingUtilities.convertPoint(e.getComponent(), tp, destination);
+            Object tmpData = data;
+            dropTarget.drop(tmpData, destinationPoint);
+            lastDropTarget = null;
+        }
+        endDrag();
+    }
+
+    private Component getComponentBeneath(MouseEvent e)
+    {
+        RootPaneContainer frame = getRootPaneContainer(this);
+        if (frame == null) {
+            return null;
+        }
+        Container contentPane = frame.getContentPane();
+
+        Component glassPane;
+        if (e.getSource() instanceof Component)
+            glassPane = (Component) e.getSource();
+        else
+            glassPane = null;
+
+        int menuBarHeight = 0;
+        if (frame instanceof JFrame) {
+            JMenuBar menuBar = ((JFrame) frame).getJMenuBar();
+            if (menuBar != null) {
+                menuBarHeight = menuBar.getHeight();
+            }
+        }
+        Point glassPanePoint = e.getPoint();
+        Container container = contentPane;
+        Point containerPoint = SwingUtilities.convertPoint(glassPane, glassPanePoint, contentPane);
+        if (containerPoint.y < 0) { // we're not in the content pane
+            if (containerPoint.y + menuBarHeight >= 0) {
+                // The mouse event is over the menu bar.
+                // Could handle specially.
+            }
+            else {
+                // The mouse event is over non-system window
+                // decorations, such as the ones provided by
+                // the Java look and feel.
+                // Could handle specially.
+            }
+        }
+        else {
+            // The mouse event is probably over the content pane.
+            // Find out exactly which component it's over.
+            Component destination = SwingUtilities.getDeepestComponentAt(container, containerPoint.x, containerPoint.y);
+            return destination;
+        }
+        return null;
+    }
+
+    /**
+     * Returns the RootPaneContainer from this components parent hierarchy.
+     * 
+     * @param pane
+     * @return
+     */
+    private RootPaneContainer getRootPaneContainer(Component pane)
+    {
+        Component c = pane;
+        while (c.getParent() != null && !(c instanceof RootPaneContainer)) {
+            c = c.getParent();
+        }
+
+        return (RootPaneContainer) c;
+    }
+
+    private void storePosition(MouseEvent e)
+    {
+        e = SwingUtilities.convertMouseEvent((Component) e.getSource(), e, this);
+        dragRect.x = (int) (e.getX() - dragRect.getWidth() / 2);
+        dragRect.y = (int) (e.getY() - dragRect.getHeight() / 2);
+    }
+
+    /**
+     * Do a "quick add" of the currently selected class, *iff* quick-add is "active"
+     * (i.e. if shift is currently pressed).
+     */
+    private void quickAddIfActive()
+    {
+        if (isQuickAddActive) {
+            WorldHandler worldHandler = WorldHandler.getInstance();
+            ClassView cls = (ClassView) classSelectionManager.getSelected();
+            if (canBeInstantiatedWithoutParams(cls) ) {
+                ActorClassRole role = (ActorClassRole) cls.getRole();
+                Actor actor = role.createObjectDragProxy();
+                DragGlassPane.getInstance().startDrag(actor, this, worldHandler.getWorldCanvas(), false);
+            }
+        }
+    }
+
+    /**
+     * Returns true if the given class is in a state where it can be instantiated.
+     * 
+     */
+    private boolean canBeInstantiatedWithoutParams(ClassView cls)
+    {
+        if(cls == null) 
+            return false;
+        if(! (cls.getRole() instanceof ActorClassRole))
+            return false;
+        GClass gCls = cls.getGClass();
+        if(! gCls.isCompiled()) {
+            return false;
+        }
+        Class<?> realClass = gCls.getJavaClass();
+        if(realClass != null && java.lang.reflect.Modifier.isAbstract(realClass.getModifiers())) {
+            return false;
+        }
+        try {
+            realClass.getConstructor();
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+        return true;
+    }
+
+    public void dragFinished(Object o)
+    {
+        quickAddIfActive();
+    }
+    
+    public void listeningEnded()
+    {
+        listening = false;
+        cancelDrag();
+    }
+
+    public void listeningStarted(Object obj)
+    {
+        // We can get several invocation of listeningStarted, so we only listen to the first one.
+        if(listening) {
+            return;            
+        }        
+        listening = true;
+        
+        if(obj != null) {
+            startDrag((Actor) obj, null, null, true);
+            SwingUtilities.getWindowAncestor(this).toFront();
+        } else {
+            isQuickAddActive = true;
+            quickAddIfActive();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/DragListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/DragListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae19a8f501c6ef38f8c2540048b7293f1c4f033a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/DragListener.java
@@ -0,0 +1,37 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+/**
+ * Interface to use for objects that need to receive notification about a
+ * drag/drop operation.
+ * 
+ * @author Davin McCall
+ * @version $Id: DragListener.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public interface DragListener
+{
+    /**
+     * A drag-n-drop operation has finished.
+     */
+    public void dragFinished(Object o);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/DropTarget.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/DropTarget.java
new file mode 100644
index 0000000000000000000000000000000000000000..729533d740c379640f79c35adc2e42cabc1a9d41
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/DropTarget.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import java.awt.Point;
+
+/**
+ * Interface that components can use for accepting dropping of objects
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: DropTarget.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public interface DropTarget
+{
+    /**
+     * Tells this component to do whatever when a component is dragged along it.
+     * 
+     * The component is responsible for repainting itself.
+     * 
+     * @param o
+     * @return true if the drag was processed, false otherwise
+     */
+    public boolean drag(Object o, Point p);
+
+    /**
+     * Drops the object to this component if possible.
+     * 
+     * @param o
+     * @return true if the drop was succesfull, false otherwise
+     */
+    public boolean drop(Object o, Point p);
+
+    /**
+     * A drag has ended on this component (the object has been dragged off
+     * the component) - do cleanup
+     */
+    public void dragEnded(Object o);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/EditableList.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/EditableList.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7c04a32a3778b8dce7c347afa225d145fef2f25
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/EditableList.java
@@ -0,0 +1,335 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.io.Serializable;
+import java.util.List;
+
+import javax.swing.JComponent;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.EventListenerList;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+
+/**
+ * A list based on JTable that behaves similar to a JList but allows editing of
+ * the elements.
+ * 
+ * TODO: it is to easy to accidentally start editing. Editing should only be
+ * triggered by a few specific actions (double click, enter, F2) depending on
+ * OS.
+ * 
+ * @author Poul Henriksen
+ */
+public class EditableList<T> extends JTable
+{
+    private DefaultTableModel tableModel;
+    private ListSelectionListener selectionListener;
+
+    /**
+     * Construct an empty EditableList.
+     */
+    public EditableList(final boolean editable)
+    {
+        tableModel = new DefaultTableModel(1, 1) {
+            public boolean isCellEditable(int row, int col)
+            {
+                return editable;
+            }
+        };
+        setModel(tableModel);
+
+        setShowGrid(false);
+        setRowSelectionAllowed(true);
+        setColumnSelectionAllowed(false);
+        setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        setIntercellSpacing(new Dimension());
+        setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+        getTableHeader().setVisible(false);
+
+        getSelectionModel().addListSelectionListener(new ListSelectionHandler());
+    }
+
+    /**
+     * Notify that the component has been added as a child of a container.
+     */
+    public void addNotify()
+    {
+        // The table header gets added to the enclosing scrollpane from
+        // JTable.addNotify(). Remove it again immediately.
+        super.addNotify();
+        removeHeader();
+    }
+
+    /**
+     * Ensures that the header of the table is not shown at all!
+     * 
+     */
+    private void removeHeader()
+    {
+        this.unconfigureEnclosingScrollPane();
+    }
+
+    /**
+     * Ensure that the preferred width can fit the biggest element in the list.
+     */
+    private void setPreferredWidthToFit(List<T> listData)
+    {
+        TableColumn tableColumn = getColumnModel().getColumn(0);
+        int contentsMaxWidth = getMaxWidth(listData);
+        int prefWidth = tableColumn.getPreferredWidth();
+        if (prefWidth < contentsMaxWidth) {
+            tableColumn.setPreferredWidth(contentsMaxWidth);
+        }
+    }
+
+    /**
+     * Finds the maximum width among all the elements in the given data.
+     */
+    private int getMaxWidth(List<T> listData)
+    {
+        TableColumn tableColumn = getColumnModel().getColumn(0);
+        TableCellRenderer ltcr = tableColumn.getCellRenderer();
+        int contentsMaxWidth = 0;
+        int row = 0;
+        for (T data : listData) {
+            Component n = ltcr.getTableCellRendererComponent(this, data, false, false, row, 0);
+            int labelWidth = n.getPreferredSize().width;
+            if (labelWidth > contentsMaxWidth) {
+                contentsMaxWidth = labelWidth;
+            }
+            row++;
+        }
+
+        return contentsMaxWidth;
+    }
+
+    /**
+     * Set the data to populate this list. Will replace the current list with
+     * this data.
+     */
+    public void setListData(List<T> data)
+    {
+
+        tableModel.setRowCount(0);
+        if (data == null) {
+            return;
+        }
+
+        for (T object : data) {
+            tableModel.addRow(new Object[]{object});
+
+        }
+
+        setPreferredWidthToFit(data);
+        revalidate();
+    }
+
+    /**
+     * If the given value exists in this list, it will be selected.
+     * 
+     * Uses the 'equals' method to determine if the value exist.
+     * 
+     * @return The row that was selected, or -1 if the value could not be found.
+     */
+    public int setSelectedValue(Object value)
+    {
+        if (value == null) {
+            return -1;
+        }
+        int rowCount = tableModel.getRowCount();
+        for (int row = 0; row < rowCount; row++) {
+            if (value.equals(getValueAt(row, 0))) {
+                setSelectedRow(row);
+                return row;
+            }
+        }
+        return -1;
+    }
+    
+    /**
+     * Sets the selected row
+     */
+    public void setSelectedRow(int row)
+    {
+        getSelectionModel().setSelectionInterval(row, row);
+    }
+
+    /**
+     * Scrolls the list within an enclosing viewport to make the specified cell
+     * completely visible. This calls {@code scrollRectToVisible} with the
+     * bounds of the specified cell. For this method to work, the {@code
+     * EditableList} must be within a <code>JViewport</code>.
+     * <p>
+     * If the given index is outside the list's range of cells, this method
+     * results in nothing.
+     * 
+     * @param index the index of the cell to make visible
+     * @see JComponent#scrollRectToVisible
+     * @see #getCellRect(int, int, boolean)
+     */
+    public void ensureIndexIsVisible(int index)
+    {
+        if (index < 0 || index >= tableModel.getRowCount()) {
+            return;
+        }
+        Rectangle cellBounds = getCellRect(index, 0, false);
+        if (cellBounds != null) {
+            scrollRectToVisible(cellBounds);
+        }
+    }
+
+    /**
+     * Get the currently selected value.
+     */
+    @SuppressWarnings("unchecked")
+    public T getSelectedValue()
+    {
+        int row = getSelectedRow();
+        if (row == -1)
+            return null;
+        return (T) tableModel.getValueAt(row, 0);
+    }
+    
+    /**
+     * Returns an array of the values for the selected cells. The returned values are sorted in increasing index order.
+     * @returns: the selected values or an empty list if nothing is selected
+     */
+    public Object[] getSelectedValues()
+    {
+        int[] rows = getSelectedRows();
+        Object[] selected = new Object[rows.length];
+        int count = 0;
+        for (int row : rows) {
+            selected[count] = tableModel.getValueAt(row, 0);
+            count++;
+        }
+        return selected;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see javax.swing.Scrollable#getPreferredScrollableViewportSize()
+     */
+    public Dimension getPreferredScrollableViewportSize()
+    {
+        // Limit the preferred viewport width to the preferred width (which will
+        // be calculated based on the contents of the list)
+        Dimension d = super.getPreferredScrollableViewportSize();
+        d.width = Math.min(d.width, getPreferredSize().width);
+        return d;
+    }
+
+    /**
+     * Notifies {@code ListSelectionListener}s added directly to the list of
+     * selection changes made to the selection model. {@code JList} listens for
+     * changes made to the selection in the selection model, and forwards
+     * notification to listeners added to the list directly, by calling this
+     * method.
+     * <p>
+     * This method constructs a {@code ListSelectionEvent} with this list as the
+     * source, and the specified arguments, and sends it to the registered
+     * {@code ListSelectionListeners}.
+     * 
+     * @param firstIndex the first index in the range, {@code <= lastIndex}
+     * @param lastIndex the last index in the range, {@code >= firstIndex}
+     * @param isAdjusting whether or not this is one in a series of multiple
+     *            events, where changes are still being made
+     * 
+     * @see #addListSelectionListener
+     * @see #removeListSelectionListener
+     * @see javax.swing.event.ListSelectionEvent
+     * @see EventListenerList
+     */
+    protected void fireSelectionValueChanged(int firstIndex, int lastIndex, boolean isAdjusting)
+    {
+        Object[] listeners = listenerList.getListenerList();
+        ListSelectionEvent e = null;
+
+        for (int i = listeners.length - 2; i >= 0; i -= 2) {
+            if (listeners[i] == ListSelectionListener.class) {
+                if (e == null) {
+                    e = new ListSelectionEvent(this, firstIndex, lastIndex, isAdjusting);
+                }
+                ((ListSelectionListener) listeners[i + 1]).valueChanged(e);
+            }
+        }
+    }
+
+    /*
+     * A ListSelectionListener that forwards ListSelectionEvents from the
+     * selectionModel to the JList ListSelectionListeners. The forwarded events
+     * only differ from the originals in that their source is the JList instead
+     * of the selectionModel itself.
+     */
+    private class ListSelectionHandler
+        implements ListSelectionListener, Serializable
+    {
+        public void valueChanged(ListSelectionEvent e)
+        {
+            fireSelectionValueChanged(e.getFirstIndex(), e.getLastIndex(), e.getValueIsAdjusting());
+        }
+    }
+
+    /**
+     * Adds a listener to the list, to be notified each time a change to the
+     * selection occurs; the preferred way of listening for selection state
+     * changes. {@code JList} takes care of listening for selection state
+     * changes in the selection model, and notifies the given listener of each
+     * change. {@code ListSelectionEvent}s sent to the listener have a {@code
+     * source} property set to this list.
+     * 
+     * @param listener the {@code ListSelectionListener} to add
+     * @see #getSelectionModel
+     * @see #getListSelectionListeners
+     */
+    public void addListSelectionListener(ListSelectionListener listener)
+    {
+        if (selectionListener == null) {
+            selectionListener = new ListSelectionHandler();
+            getSelectionModel().addListSelectionListener(selectionListener);
+        }
+
+        listenerList.add(ListSelectionListener.class, listener);
+    }
+
+    /**
+     * Removes a selection listener from the list.
+     * 
+     * @param listener the {@code ListSelectionListener} to remove
+     * @see #addListSelectionListener
+     * @see #getSelectionModel
+     */
+    public void removeListSelectionListener(ListSelectionListener listener)
+    {
+        listenerList.remove(ListSelectionListener.class, listener);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/FirstStartupDialog.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/FirstStartupDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..4060d680b4772dfde4ceb834037017c17cbcf832
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/FirstStartupDialog.java
@@ -0,0 +1,177 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+
+/**
+ * This is a dialog box presented to the user the very first time greenfoot is
+ * started. The purpose it to make it easy to use greenfoot for the very first
+ * time by presenting the user with a few options to select among. The dialog
+ * will only be shown the very first time after installing greenfoot.
+ * 
+ * @author Poul Henriksen
+ * @version $id:$
+ */
+public class FirstStartupDialog extends JDialog
+{
+    public enum Result {
+        TUTORIAL, OPEN, CREATE, WITHOUT;
+    }
+
+    private Result result = Result.WITHOUT;
+    
+    public FirstStartupDialog()
+    {
+        super((Frame) null, "Greenfoot");
+        setModal(true);
+        buildUI();
+        pack();
+    }
+
+    public void buildUI() {
+        JPanel contentPane = new JPanel();
+        setContentPane(contentPane);
+        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
+        contentPane.setBorder(BlueJTheme.dialogBorder);
+        
+        int spacingLarge = BlueJTheme.componentSpacingLarge;
+        int spacingSmall = BlueJTheme.componentSpacingSmall;
+        
+        String headerText = Config.getString("startup.header");
+        String welcomeText = Config.getString("startup.welcome");
+        String questionText = Config.getString("startup.question");
+        
+        //TODO maybe a nicely rendered image instead
+        JLabel headerLabel = new JLabel(headerText);
+        Font f = headerLabel.getFont();
+        f = f.deriveFont((f.getSize() + 4f));
+        headerLabel.setFont(f);
+        WrappingMultiLineLabel welcomeLabel = new WrappingMultiLineLabel(welcomeText, 60);
+        JLabel questionLabel = new JLabel(questionText);
+        
+       /* headerLabel.setBorder(new EmptyBorder(5,5,5,5));
+        welcomeLabel.setBorder(new EmptyBorder(5,5,5,5));        
+        questionLabel.setBorder(new EmptyBorder(5,5,5,5));*/
+        
+        headerLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
+        welcomeLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
+        questionLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
+        
+        
+        contentPane.add(headerLabel);   
+        contentPane.add(GreenfootUtil.createSpacer(GreenfootUtil.Y_AXIS, spacingSmall));
+        contentPane.add(welcomeLabel);
+        
+        contentPane.add(Box.createVerticalGlue());
+        contentPane.add(GreenfootUtil.createSpacer(GreenfootUtil.Y_AXIS, spacingLarge));
+        contentPane.add(questionLabel);
+        contentPane.add(GreenfootUtil.createSpacer(GreenfootUtil.Y_AXIS, spacingSmall));
+        
+        JPanel buttonPanel = new JPanel();
+        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS)); //
+        JButton tutorialButton = new JButton(Config.getString("startup.tutorial.button"));
+        JButton openButton = new JButton(Config.getString("startup.open.button"));
+        JButton createButton = new JButton(Config.getString("startup.create.button"));
+        JButton continueButton = new JButton(Config.getString("startup.continue.button"));       
+
+        getRootPane().setDefaultButton(tutorialButton);
+        
+        tutorialButton.setAlignmentX(Component.CENTER_ALIGNMENT);
+        openButton.setAlignmentX(Component.CENTER_ALIGNMENT);
+        createButton.setAlignmentX(Component.CENTER_ALIGNMENT);
+        continueButton.setAlignmentX(Component.CENTER_ALIGNMENT);
+        
+        Dimension bigSize = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+        tutorialButton.setMaximumSize(bigSize);
+        openButton.setMaximumSize(bigSize);
+        createButton.setMaximumSize(bigSize);
+        continueButton.setMaximumSize(bigSize);
+        
+        tutorialButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                result = Result.TUTORIAL;
+                dispose();
+            }
+        });
+        openButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                result = Result.OPEN;
+                dispose();
+            }
+        });
+        createButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                result = Result.CREATE;
+                dispose();
+            }
+        });
+        continueButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                result = Result.WITHOUT;
+                dispose();
+            }
+        });
+        
+        buttonPanel.add(tutorialButton);
+        buttonPanel.add(GreenfootUtil.createSpacer(GreenfootUtil.Y_AXIS, spacingSmall));
+        buttonPanel.add(openButton);
+        buttonPanel.add(GreenfootUtil.createSpacer(GreenfootUtil.Y_AXIS, spacingSmall));
+        buttonPanel.add(createButton);
+        buttonPanel.add(GreenfootUtil.createSpacer(GreenfootUtil.Y_AXIS, spacingSmall));
+        buttonPanel.add(continueButton);
+        
+        JPanel nonGreedyPanel = new JPanel();
+        nonGreedyPanel.add(buttonPanel);
+        contentPane.add(nonGreedyPanel);
+    }
+
+    public Result getResult()
+    {
+        return result;
+    }
+    
+    
+    
+}
+
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/GreenfootFrame.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/GreenfootFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..be51e4100974c32450081e472b51e06b1df151c9
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/GreenfootFrame.java
@@ -0,0 +1,1042 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import greenfoot.Actor;
+import greenfoot.World;
+import greenfoot.actions.AboutGreenfootAction;
+import greenfoot.actions.CloseProjectAction;
+import greenfoot.actions.CompileAllAction;
+import greenfoot.actions.ExportProjectAction;
+import greenfoot.actions.ImportClassAction;
+import greenfoot.actions.NewClassAction;
+import greenfoot.actions.NewProjectAction;
+import greenfoot.actions.OpenProjectAction;
+import greenfoot.actions.OpenRecentProjectAction;
+import greenfoot.actions.PauseSimulationAction;
+import greenfoot.actions.PreferencesAction;
+import greenfoot.actions.QuitAction;
+import greenfoot.actions.RemoveSelectedClassAction;
+import greenfoot.actions.ResetWorldAction;
+import greenfoot.actions.RunOnceSimulationAction;
+import greenfoot.actions.RunSimulationAction;
+import greenfoot.actions.SaveAsAction;
+import greenfoot.actions.SaveProjectAction;
+import greenfoot.actions.SaveWorldAction;
+import greenfoot.actions.SetPlayerAction;
+import greenfoot.actions.ShowApiDocAction;
+import greenfoot.actions.ShowCopyrightAction;
+import greenfoot.actions.ShowReadMeAction;
+import greenfoot.actions.ShowWebsiteAction;
+import greenfoot.actions.ToggleAction;
+import greenfoot.actions.ToggleDebuggerAction;
+import greenfoot.actions.ToggleSoundAction;
+import greenfoot.core.ClassStateManager;
+import greenfoot.core.GClass;
+import greenfoot.core.GCoreClass;
+import greenfoot.core.GPackage;
+import greenfoot.core.GProject;
+import greenfoot.core.GreenfootMain;
+import greenfoot.core.ProjectProperties;
+import greenfoot.core.Simulation;
+import greenfoot.core.WorldHandler;
+import greenfoot.event.CompileListener;
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+import greenfoot.event.WorldEvent;
+import greenfoot.event.WorldListener;
+import greenfoot.gui.classbrowser.ClassBrowser;
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.gui.classbrowser.Selectable;
+import greenfoot.gui.classbrowser.SelectionListener;
+import greenfoot.gui.input.mouse.LocationTracker;
+import greenfoot.platforms.ide.SimulationDelegateIDE;
+import greenfoot.platforms.ide.WorldHandlerDelegateIDE;
+import greenfoot.sound.SoundFactory;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.HeadlessException;
+import java.awt.Image;
+import java.awt.Menu;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.ButtonModel;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.KeyStroke;
+
+import rmiextension.wrappers.RBlueJ;
+import rmiextension.wrappers.event.RCompileEvent;
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.DBox;
+
+import com.apple.eawt.AboutHandler;
+import com.apple.eawt.AppEvent.AboutEvent;
+import com.apple.eawt.AppEvent.PreferencesEvent;
+import com.apple.eawt.AppEvent.QuitEvent;
+import com.apple.eawt.Application;
+import com.apple.eawt.PreferencesHandler;
+import com.apple.eawt.QuitHandler;
+import com.apple.eawt.QuitResponse;
+
+/**
+ * The main frame for a Greenfoot project (one per project)
+ * 
+ * @author Poul Henriksen
+ * @author mik
+ */
+public class GreenfootFrame extends JFrame
+    implements WindowListener, CompileListener, WorldListener, SelectionListener
+{
+    private static final String shareIconFile = "export-publish-small.png";
+    private static final String compileIconFile = "compile.png";
+    private static final int WORLD_MARGIN = 40;
+
+    private static final int accelModifier = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+    private static final int shiftAccelModifier = accelModifier | KeyEvent.SHIFT_MASK;
+
+    private RBlueJ rBlueJ;
+    private GProject project;
+    private GreenfootInspectorManager inspectorManager = new GreenfootInspectorManager();
+        
+    private WorldCanvas worldCanvas;
+    private WorldHandler worldHandler;
+    private WorldHandlerDelegateIDE worldHandlerDelegate;
+    private Dimension worldDimensions;
+    private ClassBrowser classBrowser;
+    private ControlPanel controlPanel;
+    private JScrollPane classScrollPane;
+    /** The panel that needs to be revalidated when the world size changes */
+    private JComponent centrePanel;
+    
+    private NewClassAction newClassAction;
+    private ImportClassAction importClassAction;
+    private SaveProjectAction saveProjectAction;
+    private SaveAsAction saveAsAction;
+    private ShowReadMeAction showReadMeAction;
+    private ExportProjectAction exportProjectAction;
+    private ExportProjectAction shareAction;
+    private CloseProjectAction closeProjectAction;
+    private RemoveSelectedClassAction removeSelectedClassAction;
+    private CompileAllAction compileAllAction;
+    private SaveWorldAction saveWorldAction;
+    private SetPlayerAction setPlayerAction;
+    
+    private ToggleDebuggerAction toggleDebuggerAction;
+    private ToggleSoundAction toggleSoundAction;
+    
+    private JMenu recentProjectsMenu;
+    
+    /**
+     * Specifies whether the project has been closed and only the empty frame is showing.
+     * (Behind the scenes, the project is actually still open).
+     */
+    private boolean isClosedProject = true;
+    
+    /**
+     * Returns whether the project is closed or not
+     * @return isClosedProject  True if the project is closed and false if not
+     */
+    public boolean isClosedProject() 
+    {
+        return isClosedProject;
+    }
+
+    /**
+     * Indicate whether we want to resize. 
+     * 
+     * @see #setResizeWhenPossible(boolean)
+     * @see #needsResize()
+     */
+    private boolean resizeWhenPossible = false;
+    
+    private static GreenfootFrame instance;
+    
+    public static GreenfootFrame getGreenfootFrame(final RBlueJ blueJ, ClassStateManager classStateManager)
+    {
+        instance = new GreenfootFrame(blueJ, classStateManager);                        
+        return instance;
+    }
+    
+    /**
+     * Creates a new top level frame with all the GUI components.
+     * @param classStateManager 
+     */
+    private GreenfootFrame(RBlueJ blueJ, ClassStateManager classStateManager)
+        throws HeadlessException
+    {
+        super("Greenfoot");
+        
+        this.rBlueJ = blueJ;
+        
+        LocationTracker.instance(); //force initialisation
+        Image icon = BlueJTheme.getApplicationIcon("greenfoot");
+        if (icon != null) {
+            setIconImage(icon);
+        }
+
+        makeFrame(classStateManager);
+        addWindowListener(this);
+        
+        restoreFrameState();
+
+        prepareMacOSApp();
+    }
+    
+    /**
+     * Restore the current main window size from the project properties.
+     */
+    private void restoreFrameState()
+    {
+        if (project == null) {
+            // We don't have a project yet: just use default size
+            setBounds(40, 40, 700, 500);
+            setResizeWhenPossible(true);
+            return;
+        }
+        
+        ProjectProperties projectProperties = project.getProjectProperties();
+
+        try {            
+            int x = projectProperties.getInt("mainWindow.x");
+            int y = projectProperties.getInt("mainWindow.y");
+
+            int width = projectProperties.getInt("mainWindow.width");
+            int height = projectProperties.getInt("mainWindow.height");
+            
+            Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+            
+            if (x > (d.width - 50)) {
+                x = d.width - 50;
+            }
+
+            if (y > (d.height - 50)) {
+                y = d.height - 50;
+            }
+
+            setBounds(x, y, width, height);
+            setResizeWhenPossible(false);
+        } 
+        catch (NumberFormatException ecx) {
+            // doesn't matter - just use some default size
+            setBounds(40, 40, 700, 500);
+            setResizeWhenPossible(true);
+        }
+        
+    }
+
+    
+    /**
+     * Prepare MacOS specific behaviour (About menu, Preferences menu, Quit menu)
+     */
+    private Application prepareMacOSApp()
+    {
+        if (Config.isMacOS()) {
+            Application macApp = Application.getApplication();
+            macApp.setPreferencesHandler(new PreferencesHandler() {
+                @Override
+                public void handlePreferences(PreferencesEvent e)
+                {
+                    PreferencesAction.getInstance().actionPerformed(null);
+                }
+            });
+            macApp.setAboutHandler(new AboutHandler() {
+                @Override
+                public void handleAbout(AboutEvent arg0)
+                {
+                    AboutGreenfootAction.getInstance(GreenfootFrame.this).actionPerformed(null);                    
+                }
+            });
+            macApp.setQuitHandler(new QuitHandler() {
+                @Override
+                public void handleQuitRequestWith(QuitEvent e,
+                        QuitResponse response)
+                {
+                    exit();
+                    // response.confirmQuit() does not need to be called, since System.exit(0) is called explicitly
+                }
+            });
+            
+            return macApp;
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Open a given project into this frame.
+     */
+    public void openProject(final GProject project)
+    {
+        if (isClosedProject) {
+            this.project = project;
+            worldHandlerDelegate.attachProject(project);
+            project.addCompileListener(this);
+            setTitle("Greenfoot: " + project.getName());
+            enableProjectActions();
+
+            worldCanvas.setVisible(false);
+
+            // Class browser
+            buildClassBrowser();
+            populateClassBrowser(classBrowser, project);
+            classBrowser.setVisible(true);
+            classScrollPane.setViewportView(classBrowser);
+
+            restoreFrameState();
+
+            try {
+                ProjectProperties props = project.getProjectProperties();
+                int initialSpeed = props.getInt("simulation.speed");
+                Simulation.getInstance().setSpeed(initialSpeed);
+            } catch (NumberFormatException nfe) {
+                // If there is no speed info in the properties we don't care...
+            }
+            
+            worldHandler.instantiateNewWorld();
+            if (needsResize()) {
+                pack();
+            }
+            // set our project to be this possibly new project
+            toggleDebuggerAction.setProject(project);
+            toggleSoundAction.setProject(project);
+            isClosedProject = false;
+        }
+    }
+    
+    /**
+     * Calling this will make the current frame an empty frame.
+     */
+    public void closeProject()
+    {
+        setTitle("Greenfoot: ");
+        project.removeCompileListener(this);
+        project.closeEditors();
+        worldCanvas.setVisible(false);
+        classBrowser.setVisible(false);
+        project = null;
+        enableProjectActions();
+        repaint();
+        isClosedProject = true;
+    }
+
+    /**
+     * Get the class browser currently embedded in this frame.
+     */
+    public ClassBrowser getClassBrowser()
+    {
+        return classBrowser;
+    }
+    
+    /**
+     * Get the project showing in this frame. If this frame is empty,
+     * will return null.
+     */
+    public GProject getProject()
+    {
+        return project;
+    }
+    
+    /**
+     * Create the GUI components for this project in the top level frame.
+     * This includes opening the project and displaying the project classes.
+     * @param classStateManager 
+     */
+    private void makeFrame(ClassStateManager classStateManager)
+    {
+        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        
+        // Some first-time initializations
+        worldCanvas = new WorldCanvas(null);
+        worldCanvas.setWorldSize(200, 100);
+        worldCanvas.setVisible(false);
+        
+        worldHandlerDelegate = new WorldHandlerDelegateIDE(this, inspectorManager, classStateManager);
+        WorldHandler.initialise(worldCanvas, worldHandlerDelegate);
+        worldHandler = WorldHandler.getInstance();
+        worldHandler.addWorldListener(this);
+        Simulation.initialize(new SimulationDelegateIDE());
+        Simulation sim = Simulation.getInstance();
+        sim.attachWorldHandler(worldHandler);
+       
+        // Build the class browser before building the menu, because
+        // some menu actions work on the class browser.
+        buildClassBrowser();
+        setupActions();
+        setJMenuBar(buildMenu(classStateManager));
+        setGlassPane(DragGlassPane.getInstance());
+
+        // build the centre panel. this includes the world and the controls
+        
+        centrePanel = new JPanel(new BorderLayout(4, 4)) {
+            @Override
+            public boolean isValidateRoot()
+            {
+                return true;
+            }
+        };
+
+        sim.addSimulationListener(new SimulationListener() {
+            public void simulationChanged(SimulationEvent e)
+            {
+                // If the simulation starts, try to transfer keyboard
+                // focus to the world canvas to allow control of Actors
+                // via the keyboard
+                if (e.getType() == SimulationEvent.STARTED) {
+                    worldCanvas.requestFocusInWindow();
+                }
+            }
+        });
+
+        sim.addSimulationListener(SoundFactory.getInstance().getSoundCollection());
+        
+        worldCanvas.setBorder(BorderFactory.createLineBorder(Color.BLACK));
+        
+        JPanel canvasPanel = new JPanel(new CenterLayout());
+        canvasPanel.setBorder(BorderFactory.createEtchedBorder());        
+        canvasPanel.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {
+                if (e.isPopupTrigger()) {
+                    worldHandlerDelegate.showWorldPopupMenu(e);
+                }
+            }
+            @Override
+            public void mouseReleased(MouseEvent e) {
+                if (e.isPopupTrigger()) {
+                    worldHandlerDelegate.showWorldPopupMenu(e);
+                }
+            }
+        });
+        
+        JScrollPane worldScrollPane = new JScrollPane(worldCanvas);
+        //Stop the world scroll pane scrolling when arrow keys are pressed - stops it interfering with the scenario.
+        String[] scrollLabels = new String[]{"unitScrollLeft", "unitScrollRight", "unitScrollUp", "unitScrollDown"};
+        for(String scrollLabel : scrollLabels) {
+            worldScrollPane.getActionMap().put(scrollLabel, new AbstractAction() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    //Do nothing
+                }
+            });
+        }
+        DBox worldBox = new DBox(DBox.Y_AXIS, 0.5f); // scroll pane
+        worldBox.addAligned(worldScrollPane);
+
+        canvasPanel.add(worldBox);
+        // Set the scroll bar increments so that using the scroll wheel works well:
+        setScrollIncrements(worldScrollPane);
+        worldScrollPane.setOpaque(false);
+        // Why are these not opaque? Maybe they have to be on some platforms? looks fine on Mac OS X Leopard.
+        worldScrollPane.getViewport().setOpaque(false);
+        worldScrollPane.setBorder(null);
+        
+        centrePanel.add(canvasPanel, BorderLayout.CENTER);
+        
+        // the control panel
+        
+        controlPanel = new ControlPanel(sim, true);
+        controlPanel.setBorder(BorderFactory.createEtchedBorder());
+
+        centrePanel.add(controlPanel, BorderLayout.SOUTH);
+
+        
+        // EAST side: project info button and class browser
+        
+        JPanel eastPanel = new JPanel(new BorderLayout(12, 12));
+
+        JButton shareButton = GreenfootUtil.createButton(shareAction); 
+        shareButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource(shareIconFile)));
+        shareButton.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
+        eastPanel.add(shareButton, BorderLayout.NORTH);       
+        
+        // the class browser 
+        
+        classScrollPane = new JScrollPane(classBrowser) {
+            public Dimension getPreferredSize()
+            {
+                Dimension size = super.getPreferredSize();
+                // Always leave room for the vertical scroll bar to appear
+                // This stops a horizontal scroll bar getting added when the vertical one appears
+                size.width += getVerticalScrollBar().getWidth();
+                return size;
+            }
+            
+        };
+        setScrollIncrements(classScrollPane);
+        classScrollPane.setOpaque(false);
+        classScrollPane.getViewport().setOpaque(false);
+        classScrollPane.setBorder(BorderFactory.createEtchedBorder());
+        eastPanel.add(classScrollPane, BorderLayout.CENTER);
+
+        // the compile button at the bottom
+        
+        JButton button = GreenfootUtil.createButton(compileAllAction);
+        button.setFocusable(false);
+        // set the icon image: currently empty, but used to force same button look as readme button
+        button.setIcon(new ImageIcon(getClass().getClassLoader().getResource(compileIconFile)));
+        eastPanel.add(button, BorderLayout.SOUTH);
+        
+        // arrange the major components in the content pane
+        JPanel contentPane = new JPanel();
+        setContentPane(contentPane);
+        contentPane.setLayout(new BorderLayout(12, 12));
+        contentPane.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
+
+        contentPane.add(centrePanel, BorderLayout.CENTER);
+        contentPane.add(eastPanel, BorderLayout.EAST);
+
+        contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(Config.GREENFOOT_SET_PLAYER_NAME_SHORTCUT, "setPlayerAction");
+        contentPane.getActionMap().put("setPlayerAction", setPlayerAction);
+        
+        pack();
+    }
+
+    /**
+     * Sets the scroll increments on a scroll pane to be something sensible
+     * and useable.
+     */
+    private static void setScrollIncrements(JScrollPane scrollPane)
+    {
+        scrollPane.getVerticalScrollBar().setUnitIncrement(20);
+        scrollPane.getVerticalScrollBar().setBlockIncrement(30);
+        scrollPane.getHorizontalScrollBar().setUnitIncrement(20);
+        scrollPane.getHorizontalScrollBar().setBlockIncrement(30);
+    }
+
+    /**
+     * Pack the components in this frame.
+     * As part of this, try to make sure that the frame does not get too big.
+     * If necessary, make it smaller to fit on screen.
+     * 
+     * <p>Call on event thread only.
+     */
+    public void pack()
+    {
+        super.pack();
+        
+        int width = getSize().width;
+        int height = getSize().height;
+        boolean change = false;
+        
+        if (width > getMaximumSize().width) {
+            width = getMaximumSize().width;
+            change = true;
+        }
+        if (height > getMaximumSize().height) {
+            height = getMaximumSize().height;
+            change = true;
+        }
+        if (change) {
+            setSize(width, height);
+        }
+    }
+    
+    /**
+     * Return the preferred size for the frame. The preferred size adds a bit of
+     * spacing to the default size to get a margin around the world display.
+     */
+    public  Dimension getPreferredSize()
+    {
+        Dimension dim = super.getPreferredSize();
+        dim.setSize(dim.width + WORLD_MARGIN, dim.height + WORLD_MARGIN);
+        return dim;
+    }
+
+    /**
+     * Build a new (empty) class browser.
+     */
+    private void buildClassBrowser()
+    {
+        classBrowser = new ClassBrowser(project, this);
+        classBrowser.getSelectionManager().addSelectionChangeListener(this);
+        DragGlassPane.getInstance().setSelectionManager(classBrowser.getSelectionManager());
+    }
+
+    /**
+     * Read the classes from a given project and display them in the class browser.
+     */
+    private void populateClassBrowser(ClassBrowser classBrowser, GProject project)
+    {
+        if (project != null) {
+            try {
+                GPackage pkg = project.getDefaultPackage();
+
+                GClass[] classes = pkg.getClasses(false);
+                //add the system classes
+                classBrowser.quickAddClass(new ClassView(classBrowser,
+                        new GCoreClass(World.class, project), worldHandlerDelegate));
+                classBrowser.quickAddClass(new ClassView(classBrowser,
+                        new GCoreClass(Actor.class, project), worldHandlerDelegate));
+
+                for (int i = 0; i < classes.length; i++) {
+                    GClass gClass = classes[i];
+                    classBrowser.quickAddClass(new ClassView(classBrowser, gClass, worldHandlerDelegate));
+                }
+
+                classBrowser.updateLayout();
+            }
+            catch (Exception exc) {
+                //Debug.reportError("Could not open classes in scenario", exc);
+                exc.printStackTrace();
+            }
+        }
+    }
+
+    private void setupActions()
+    {
+        newClassAction = new NewClassAction(this, worldHandlerDelegate);
+        saveProjectAction = new SaveProjectAction(this);
+        saveAsAction = new SaveAsAction(this, rBlueJ);
+        showReadMeAction = new ShowReadMeAction(this);
+        saveWorldAction = worldHandlerDelegate.getSaveWorldAction();
+        setPlayerAction = new SetPlayerAction(this);
+        exportProjectAction = new ExportProjectAction(this, false);
+        shareAction = new ExportProjectAction(this, true);
+        importClassAction = new ImportClassAction(this, worldHandlerDelegate);
+        closeProjectAction = new CloseProjectAction(this);
+        removeSelectedClassAction = new RemoveSelectedClassAction(this);
+        removeSelectedClassAction.setEnabled(false);
+        compileAllAction = new CompileAllAction(project);
+    }
+    
+    /**
+     * Build the menu bar.
+     * @param classStateManager
+     */
+    private JMenuBar buildMenu(ClassStateManager classStateManager)
+    {
+        JMenuBar menuBar = new JMenuBar();
+
+        JMenu projectMenu = addMenu(Config.getString("menu.scenario"), menuBar, 's');
+        
+        addMenuItem(NewProjectAction.getInstance(), projectMenu, -1, false, KeyEvent.VK_N);
+        addMenuItem(OpenProjectAction.getInstance(), projectMenu, KeyEvent.VK_O, false, KeyEvent.VK_O);
+        
+        recentProjectsMenu = new JMenu(Config.getString("menu.openRecent"));
+        projectMenu.add(recentProjectsMenu);
+        updateRecentProjects(classStateManager);
+        
+        addMenuItem(closeProjectAction, projectMenu, KeyEvent.VK_W, false, KeyEvent.VK_C);
+        addMenuItem(saveProjectAction, projectMenu, KeyEvent.VK_S, false, KeyEvent.VK_S);
+        addMenuItem(saveAsAction, projectMenu, -1, false, -1);
+        projectMenu.addSeparator();
+        addMenuItem(showReadMeAction, projectMenu, -1, false, -1);
+        addMenuItem(exportProjectAction, projectMenu, KeyEvent.VK_E, false, KeyEvent.VK_E);
+
+        if(! Config.isMacOS()) {
+            projectMenu.addSeparator();
+            addMenuItem(QuitAction.getInstance(), projectMenu, KeyEvent.VK_Q, false, KeyEvent.VK_Q);
+        }
+        
+        JMenu editMenu = addMenu(Config.getString("menu.edit"), menuBar, 'e');
+        
+        addMenuItem(newClassAction, editMenu, KeyEvent.VK_N, false, KeyEvent.VK_N);
+        addMenuItem(importClassAction, editMenu, KeyEvent.VK_I, false, KeyEvent.VK_I);
+        addMenuItem(removeSelectedClassAction, editMenu, KeyEvent.VK_D, false, KeyEvent.VK_R);
+                
+        if (!Config.usingMacScreenMenubar()) { // no "Preferences" here for
+            // Mac
+            editMenu.addSeparator();
+            addMenuItem(PreferencesAction.getInstance(), editMenu, KeyEvent.VK_COMMA, false, KeyEvent.VK_COMMA);
+        }
+        
+        JMenu ctrlMenu = addMenu(Config.getString("menu.controls"), menuBar, 'c');
+        
+        addMenuItem(RunOnceSimulationAction.getInstance(), ctrlMenu, KeyEvent.VK_A, false, KeyEvent.VK_A);
+        addMenuItem(RunSimulationAction.getInstance(), ctrlMenu, KeyEvent.VK_R, false, KeyEvent.VK_R);
+        addMenuItem(PauseSimulationAction.getInstance(), ctrlMenu, KeyEvent.VK_R, true, KeyEvent.VK_P);
+        addMenuItem(ResetWorldAction.getInstance(), ctrlMenu, KeyEvent.VK_T, false, KeyEvent.VK_T);
+
+        RunOnceSimulationAction.getInstance().attachListener(worldHandlerDelegate);
+        RunSimulationAction.getInstance().attachListener(worldHandlerDelegate);
+
+        ctrlMenu.addSeparator();
+        toggleDebuggerAction = new ToggleDebuggerAction(Config.getString("menu.debugger"), project);
+        createCheckboxMenuItem(toggleDebuggerAction, false, ctrlMenu, KeyEvent.VK_B, false, KeyEvent.VK_B);
+        
+        toggleSoundAction = new ToggleSoundAction(Config.getString("menu.soundRecorder"), project);
+        createCheckboxMenuItem(toggleSoundAction, false, ctrlMenu, KeyEvent.VK_U, false, KeyEvent.VK_U);
+        addMenuItem(saveWorldAction, ctrlMenu, -1, false, KeyEvent.VK_W);
+        ctrlMenu.addSeparator();
+        addMenuItem(compileAllAction, ctrlMenu, KeyEvent.VK_K, false, -1);
+        
+        JMenu helpMenu = addMenu(Config.getString("menu.help"), menuBar, 'h');
+        
+        if(! Config.isMacOS()) {
+            addMenuItem(AboutGreenfootAction.getInstance(this), helpMenu, -1, false, KeyEvent.VK_A);
+        }
+        addMenuItem(ShowCopyrightAction.getInstance(this), helpMenu, -1, false, -1);
+        helpMenu.addSeparator();
+        addMenuItem(new ShowApiDocAction(Config.getString("menu.help.classDoc")), helpMenu, -1, false, -1);
+        addMenuItem(new ShowWebsiteAction(Config.getString("menu.help.javadoc"), Config.getPropString("greenfoot.url.javaStdLib")), helpMenu, -1, false, -1);
+        helpMenu.addSeparator();
+        addMenuItem(new ShowWebsiteAction(Config.getString("menu.help.tutorial"), Config.getPropString("greenfoot.url.tutorial")), helpMenu, -1, false, -1);
+        addMenuItem(new ShowWebsiteAction(Config.getString("menu.help.website"), Config.getPropString("greenfoot.url.greenfoot")), helpMenu, -1, false, -1);
+        addMenuItem(new ShowWebsiteAction(Config.getString("menu.help.moreScenarios"), Config.getPropString("greenfoot.url.scenarios")), helpMenu, -1, false, -1);
+        helpMenu.addSeparator();
+        addMenuItem(new ShowWebsiteAction(Config.getPropString("greenfoot.gameserver.name"), Config.getPropString("greenfoot.gameserver.address")), helpMenu, -1, false, -1);
+        addMenuItem(new ShowWebsiteAction(Config.getString("menu.help.discuss"), Config.getPropString("greenfoot.url.discuss")), helpMenu, -1, false, -1);
+        
+        return menuBar;
+    }
+
+    /** 
+     * Add a menu to a menu bar.
+     */
+    private JMenu addMenu(String name, JMenuBar menubar, char mnemonic)
+    {
+        JMenu menu = new JMenu(name);
+        if(!Config.isMacOS()) {
+            menu.setMnemonic(mnemonic);
+        }
+        menubar.add(menu);
+        return menu;
+    }
+
+    /** 
+     * Add a menu item to a menu.
+     */
+    private void addMenuItem(Action action, JMenu menu, int accelKey, boolean shift, int mnemonicKey)
+    {
+        if(accelKey != -1) {
+            if(shift) {
+                action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(accelKey, shiftAccelModifier));
+            }
+            else {
+                action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(accelKey, accelModifier));
+            }
+        }
+        if(!Config.isMacOS() && mnemonicKey != -1) {
+            action.putValue(Action.MNEMONIC_KEY, Integer.valueOf(mnemonicKey));
+        }
+        menu.add(action);
+    }
+
+    /**
+     * Adds a new checkbox menu item to the {@link JMenu} provided. 
+     * Uses the {@link ToggleAction} action to setup the changing 
+     * selected state of the action, often determined by events elsewhere 
+     * in the BlueJ/Greenfoot code.
+     * 
+     * @param action        To be added to the {@link Menu}.
+     * @param selected      Default state of the action if its {@link ButtonModel} is null.
+     * @param menu          That the {@link ToggleAction} will be added to.
+     * @param accelKey      Quick keyboard shortcut for this action.
+     * @param shift         Used to determine if the accelKey needs shift pressed to happen
+     * @param mnemonicKey   Quick keyboard shortcut via the menu for this action.
+     */
+    private void createCheckboxMenuItem(ToggleAction action, boolean selected, JMenu menu, int accelKey, boolean shift, int mnemonicKey)
+    {
+        if(accelKey != -1) {
+            if(shift) {
+                action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(accelKey, shiftAccelModifier));
+            }
+            else {
+                action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(accelKey, accelModifier));
+            }
+        }
+        if(!Config.isMacOS() && mnemonicKey != -1) {
+            action.putValue(Action.MNEMONIC_KEY, Integer.valueOf(mnemonicKey));
+        }
+        JCheckBoxMenuItem item = new JCheckBoxMenuItem(action);
+        ButtonModel bm = action.getToggleModel();
+        if (bm == null) {
+            item.setSelected(selected);
+        } else {
+            item.setModel(bm);
+        }
+        menu.add(item);
+    }
+    
+    /**
+     * Update the 'Open Recent' menu, trying to include
+     * the current project as the first item where possible.
+     * @param classStateManager
+     */
+    private void updateRecentProjects(ClassStateManager classStateManager)
+    {
+        JMenuItem item = null;
+        
+        // can only add in the current project if there is a current project
+        if (classStateManager != null && classStateManager.getProject() != null) {
+            String currentName = classStateManager.getProject().getDir().getPath();
+            item = new JMenuItem(currentName);
+            item.addActionListener(OpenRecentProjectAction.getInstance());
+            recentProjectsMenu.add(item);
+            recentProjectsMenu.addSeparator();
+        }
+        
+        List<?> projects = PrefMgr.getRecentProjects();
+        for (Iterator<?> it = projects.iterator(); it.hasNext();) {
+            item = new JMenuItem((String)it.next());
+            item.addActionListener(OpenRecentProjectAction.getInstance());
+            recentProjectsMenu.add(item);
+        }
+    }
+
+    /**
+     * Enable/disable the project specific actions, depending on whether a
+     * project is currently open.
+     */
+    private void enableProjectActions() 
+    {
+        boolean state = (project != null);
+    
+        closeProjectAction.setEnabled(state);
+        saveProjectAction.setEnabled(state);
+        saveAsAction.setEnabled(state);
+        newClassAction.setEnabled(state);
+        importClassAction.setEnabled(state);
+        showReadMeAction.setEnabled(state);
+        saveWorldAction.setEnabled(state);
+        exportProjectAction.setEnabled(state);
+        shareAction.setEnabled(state);
+        
+        // Disable simulation buttons
+        if (state == false) {
+            WorldHandler.getInstance().discardWorld();
+            removeSelectedClassAction.setEnabled(false);
+        }
+        
+        compileAllAction.setProject(project);
+    }
+
+    /**
+     * Quit Greenfoot.
+     */
+    private void exit()
+    {
+        super.dispose();
+        GreenfootMain.closeAll();
+    }
+
+    /**
+     * This frame should never be disposed (at least not until the program is
+     * closed). BlueJ disposes all windows when compiling, so dispose is
+     * overridden to avoid it for this frame. Be aware of this when it should
+     * really shut down!
+     * 
+     * @see java.awt.Window#dispose()
+     * @see #exit()
+     */
+    public void dispose()
+    {
+        // I will not close :-)
+    }
+
+    /**
+     * Returns the maximum size, which is the size of the screen.
+     */
+    public Dimension getMaximumSize()
+    {
+        return Toolkit.getDefaultToolkit().getScreenSize();
+    }
+    
+    /**
+     * Returns true if we need to resize the frame. Based on whether the world
+     * has changed size or we have specifically asked for a resize by setting resizeWhenPossible.
+     * 
+     * @see #setResizeWhenPossible(boolean)
+     * @return true, if we need a resize.
+     */
+    private boolean needsResize()
+    {
+        // Note that worldDimensions is actually the dimensions of the canvas for the _last_ world.
+        // The dimensions of the canvas for the current world is held in 'dim'.
+
+        Dimension dim = worldCanvas.getPreferredSize();
+        if (resizeWhenPossible) {
+            return true;
+        }
+        else if (worldDimensions == null) {
+            // If the worldDimensions are null here, it means that we set the
+            // size specifically when we created the frame.
+            return false;
+        }
+        else if ( worldDimensions.width < dim.width || worldDimensions.height < dim.height ) {
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+    
+    /**
+     * Resizes the frame to its preferred size by running pack().
+     * <p>
+     * Should be run on the event thread.
+     */
+    private void resize()
+    {
+        setResizeWhenPossible(false);
+        pack();
+    }
+
+    /**
+     * Indicate whether we want to resize the next time we get new information
+     * about the size, and hence might want to do a resize of the entire frame.
+     */
+    public void setResizeWhenPossible(boolean b)
+    {
+        worldDimensions = null;
+        this.resizeWhenPossible = b;
+    }
+    
+    // ----------- WindowListener interface -----------
+    
+    public void windowOpened(WindowEvent e) {}
+
+    public void windowClosing(WindowEvent e)
+    {
+        GreenfootMain.closeProject(this, true);
+    }
+
+    public void windowClosed(WindowEvent e) {}
+
+    public void windowIconified(WindowEvent e) {}
+
+    public void windowDeiconified(WindowEvent e) {}
+
+    public void windowActivated(WindowEvent e) {}
+
+    public void windowDeactivated(WindowEvent e) {}
+
+    // ----------- CompileListener interface -----------
+    
+    public void compileStarted(RCompileEvent event)
+    {
+        WorldHandler.getInstance().discardWorld();
+    }
+
+    public void compileError(RCompileEvent event) { }
+
+    public void compileWarning(RCompileEvent event) { }
+
+    public void compileSucceeded(RCompileEvent event)
+    {
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                WorldHandler.getInstance().instantiateNewWorld();
+                classBrowser.repaint();
+                compileAllAction.setEnabled(project != null);
+            }
+        });
+    }
+
+    public void compileFailed(RCompileEvent event)
+    {
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                compileAllAction.setEnabled(project != null);
+            }
+        });
+    }
+    
+    // ----------- end of WindowListener interface -----------
+    
+    // ----------- WorldListener interface -------------
+    
+    @Override
+    public void worldCreated(WorldEvent e)
+    {
+        World newWorld = e.getWorld();
+        if (needsResize() && newWorld != null) {
+            // ensure we don't lose fullscreen on resize
+            final int state = getExtendedState();
+            if ( state != MAXIMIZED_BOTH ) {
+                resize();
+            }
+        }
+        worldCanvas.setVisible(true);
+        centrePanel.revalidate();
+        worldDimensions = worldCanvas.getPreferredSize();
+    }
+    
+    @Override
+    public void worldRemoved(WorldEvent e)
+    {
+        inspectorManager.removeAllInspectors();
+        worldCanvas.setVisible(false);
+    }
+
+    // ------------- end of WorldListener interface ------------
+    
+    // ------------- SelectionListener interface ---------------
+    
+    public void selectionChange(Selectable source)
+    {
+        if (source instanceof ClassView) {
+            ClassView classView = (ClassView)source;
+            if(classView.getRealClass() == null) {
+                removeSelectedClassAction.setEnabled(true);
+            }
+            else if(! (classView.getRealClass().getName().equals("greenfoot.Actor")) &&
+                    ! (classView.getRealClass().getName().equals("greenfoot.World")))  {
+                removeSelectedClassAction.setEnabled(true);
+            }
+            else {
+                removeSelectedClassAction.setEnabled(false);
+            }
+        }
+        else {
+            removeSelectedClassAction.setEnabled(false);
+        }
+    }
+    
+    // ------------- end of SelectionListener interface --------
+
+    /**
+     * Get a reference to the inspector manager for the project shown in this frame.
+     */
+    public GreenfootInspectorManager getInspectorManager()
+    {
+        return inspectorManager;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/GreenfootInspectorManager.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/GreenfootInspectorManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..00fb6ff897c6ee1f41b0b67815bafadc0feae2cf
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/GreenfootInspectorManager.java
@@ -0,0 +1,163 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011, 2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import greenfoot.gui.inspector.GreenfootClassInspector;
+import greenfoot.gui.inspector.GreenfootObjectInspector;
+import greenfoot.gui.inspector.GreenfootResultInspector;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.swing.JFrame;
+
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerObject;
+import bluej.debugmgr.ExpressionInformation;
+import bluej.debugmgr.inspector.ClassInspector;
+import bluej.debugmgr.inspector.Inspector;
+import bluej.debugmgr.inspector.InspectorManager;
+import bluej.debugmgr.inspector.ObjectInspector;
+import bluej.debugmgr.inspector.ResultInspector;
+import bluej.pkgmgr.Package;
+import bluej.testmgr.record.ClassInspectInvokerRecord;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.DialogManager;
+
+/**
+ * An inspector manager for Greenfoot projects.
+ * 
+ * @author Davin McCall
+ */
+public class GreenfootInspectorManager implements InspectorManager
+{
+    /** This holds all object inspectors for a world. */
+    private Map<DebuggerObject, Inspector> objectInspectors = new HashMap<DebuggerObject, Inspector> ();
+    /** This holds all class inspectors for a world. */
+    private Map<String, Inspector> classInspectors = new HashMap<String, Inspector> ();
+
+    @Override
+    public void removeInspector(DebuggerObject obj)
+    {
+        objectInspectors.remove(obj);
+    }
+
+    @Override
+    public void removeInspector(DebuggerClass cls)
+    {
+        classInspectors.remove(cls.getName());
+    }
+
+    @Override
+    public ObjectInspector getInspectorInstance(DebuggerObject obj,
+            String name, Package pkg, InvokerRecord ir, JFrame parent)
+    {
+        ObjectInspector inspector = (ObjectInspector) objectInspectors.get(obj);
+        
+        if (inspector == null) {
+            inspector = new GreenfootObjectInspector(obj, this, name, pkg, ir, parent);
+            objectInspectors.put(obj, inspector);
+            inspector.setVisible(true);
+        }
+        else {
+            inspector.update();
+            inspector.updateLayout();
+            inspector.setVisible(true);
+            inspector.bringToFront();
+        }
+        
+        return inspector;
+    }
+
+    @Override
+    public ClassInspector getClassInspectorInstance(DebuggerClass clss,
+            Package pkg, JFrame parent)
+    {
+        ClassInspector inspector = (ClassInspector) classInspectors.get(clss.getName());
+
+        if (inspector == null) {
+            ClassInspectInvokerRecord ir = new ClassInspectInvokerRecord(clss.getName());
+            inspector = new GreenfootClassInspector(clss, this, pkg, ir, parent);
+            classInspectors.put(clss.getName(), inspector);
+        } else {
+            inspector.update();
+            inspector.updateLayout();
+        }
+        
+        inspector.setVisible(true);
+        inspector.bringToFront();
+
+        return inspector;
+    }
+
+    @Override
+    public ResultInspector getResultInspectorInstance(DebuggerObject obj,
+            String name, Package pkg, InvokerRecord ir,
+            ExpressionInformation info, JFrame parent)
+    {
+        ResultInspector inspector = (ResultInspector) objectInspectors.get(obj);
+        
+        if (inspector == null) {
+            inspector = new GreenfootResultInspector(obj, this, name, pkg, ir, info);
+            objectInspectors.put(obj, inspector);
+            DialogManager.centreWindow(inspector, parent);
+            inspector.setVisible(true);
+        }
+        else {
+            inspector.update();
+            inspector.updateLayout();
+            inspector.setVisible(true);
+            inspector.bringToFront();
+        }
+
+        return inspector;
+    }
+
+    @Override
+    public boolean inTestMode()
+    {
+        // Greenfoot does not support testing:
+        return false;
+    }
+
+    /**
+     * Removes all inspector instances for this project.
+     * This is used when VM is reset or the project is recompiled.
+     */
+    public void removeAllInspectors()
+    {
+        for (Iterator<Inspector> it = objectInspectors.values().iterator(); it.hasNext();) {
+            Inspector inspector = it.next();
+            inspector.setVisible(false);
+            inspector.dispose();
+        }
+        objectInspectors.clear();
+        
+        for (Iterator<Inspector> it = classInspectors.values().iterator(); it.hasNext();) {
+            Inspector inspector = it.next();
+            inspector.setVisible(false);
+            inspector.dispose();
+        }
+        classInspectors.clear();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/ImportClassWindow.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/ImportClassWindow.java
new file mode 100644
index 0000000000000000000000000000000000000000..55559da9e63422c59d1e58ae20d815d671dce96a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/ImportClassWindow.java
@@ -0,0 +1,475 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import greenfoot.core.GClass;
+import greenfoot.core.GProject;
+import greenfoot.gui.classbrowser.ClassBrowser;
+import greenfoot.gui.classbrowser.ClassButton;
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.record.InteractionListener;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileReader;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRootPane;
+import javax.swing.JScrollPane;
+import javax.swing.KeyStroke;
+import javax.swing.border.EmptyBorder;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+
+import bluej.Config;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+
+/**
+ * The window showing a library of supplied classes
+ * (with associated image and javadoc), from which
+ * you can select one to import into the current project.
+ *  
+ * @author neil
+ */
+public class ImportClassWindow extends JFrame
+{
+    // How much to indent each sub-folder in the class list 
+    private static final int INDENT_HIERARCHY = 20;
+    
+    private JComponent classList;
+    private JEditorPane htmlPane;
+    private File curSelection;
+    private File curSelectionImage;
+    private ButtonGroup buttonGroup;
+    private JLabel classPicture;
+    private JLabel classLabel;
+    private GreenfootFrame gfFrame;
+    private InteractionListener interactionListener;
+
+    public ImportClassWindow(GreenfootFrame gfFrame, InteractionListener interactionListener)
+    {
+        this.gfFrame = gfFrame;
+        this.interactionListener = interactionListener;
+        buttonGroup = new ButtonGroup();
+        buildUI();
+    }
+    
+    /**
+     * The ok action for this dialog, which sets the final selection
+     */
+    private class OkAction extends AbstractAction
+    {
+        public OkAction()
+        {
+            super(Config.getString("import.import"));
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+            setVisible(false);
+            importClass(curSelection, curSelectionImage);
+        }
+    }
+    
+    private void buildUI()
+    {
+        setTitle(Config.getString("import.dialogTitle"));
+        JPanel p = new JPanel();
+        p.setLayout(new BorderLayout(10, 0));
+        p.setBorder(new EmptyBorder(0, 0, 10, 0));
+        JPanel main = new JPanel();
+        main.setLayout(new BoxLayout(main, BoxLayout.Y_AXIS));
+        main.add(p);
+        main.setBorder(BorderFactory.createEmptyBorder(12,12,12,12));
+        setContentPane(main);
+        
+        ActionListener actionListener = new ActionListener() {
+            public void actionPerformed(ActionEvent actionEvent) {
+              setVisible(false);
+            }
+        };
+        KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+        main.registerKeyboardAction(actionListener, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
+        
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+        {
+            buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+            JButton okButton = new JButton(new OkAction());
+            getRootPane().setDefaultButton(okButton);
+
+            JButton cancelButton = new JButton(new AbstractAction(Config.getString("greenfoot.cancel")) {
+                public void actionPerformed(ActionEvent e)
+                {
+                    setVisible(false);                                                
+                }
+            });
+
+            DialogManager.addOKCancelButtons(buttonPanel, okButton, cancelButton);
+        }
+        main.add(buttonPanel);
+
+        classList = new JPanel();
+        classList.setLayout(new BoxLayout(classList, BoxLayout.Y_AXIS));
+        classList.setBackground(java.awt.Color.WHITE);
+        classList.setBorder(new EmptyBorder(5, 5, 5, 5));
+        
+        findAddImportableClasses(new File(Config.getGreenfootLibDir(), "common"), 0);
+                    
+        JScrollPane classScrollPane = new JScrollPane(classList) {
+            public Dimension getPreferredSize()
+            {
+                Dimension size = super.getPreferredSize();
+                // Always leave room for the vertical scroll bar to appear
+                // This stops a horizontal scroll bar getting added when the vertical one appears
+                size.width += getVerticalScrollBar().getWidth();
+                return size;
+            }
+            
+            public Dimension getMaximumSize()
+            {
+                return getPreferredSize();
+            }
+            
+        };
+        //setScrollIncrements(classScrollPane);
+        classScrollPane.setOpaque(false);
+        classScrollPane.getViewport().setOpaque(false);
+        classScrollPane.setBorder(BorderFactory.createEtchedBorder());
+        classScrollPane.setSize(classScrollPane.getPreferredSize());
+        p.add(classScrollPane, BorderLayout.WEST);
+                   
+        
+        htmlPane = new JEditorPane();
+        htmlPane.setDocument(new HTMLDocument());
+        htmlPane.setEditorKit(new HTMLEditorKit());
+        htmlPane.setEditable(false);
+        
+        JPanel rightPane = new JPanel();
+        rightPane.setLayout(new BorderLayout());
+        JPanel classInfo = new JPanel();
+        classInfo.setBorder(new EmptyBorder(10, 5, 10, 5));
+        classInfo.setLayout(new GridLayout(1, 2));
+        classLabel = new JLabel("", JLabel.CENTER);
+        classLabel.setFont(classLabel.getFont().deriveFont(24.0f));
+        classInfo.add(classLabel);
+        classPicture = new JLabel((String)null, JLabel.CENTER);
+        classInfo.add(classPicture);
+        rightPane.add(classInfo, BorderLayout.NORTH);
+        rightPane.add(new JScrollPane(htmlPane), BorderLayout.CENTER);
+        p.add(rightPane, BorderLayout.CENTER);
+
+        pack();
+        setSize(700, 550);
+        ((ImportableClassButton)buttonGroup.getElements().nextElement()).select();
+        ((ImportableClassButton)buttonGroup.getElements().nextElement()).setSelected(true);
+        
+        setLocation(gfFrame.getX() + 40, gfFrame.getY() + 40);
+    }
+   
+    /**
+     * Searches for the HTML file associated with the given class-name (aka file stem)
+     * 
+     * If found, shows it in htmlPane.
+     */
+    private void showHTML(String stem)
+    {
+        if (stem == null) {
+            htmlPane.setText("");
+            return;
+        }
+        
+        File htmlFile = new File(stem + ".html");
+        
+        if (!htmlFile.exists()) {
+            Debug.message("No HTML file found for class " + stem + "; looked for: " + htmlFile.getAbsolutePath());
+            htmlPane.setText("");
+            return;
+        }
+        
+        // We process the contents to replace references to ./resources/inherit.gif
+        // to our own copy, to avoid having to make lots of resources sub-directories in the
+        // common classes directory.
+        try {
+            BufferedReader br = new BufferedReader(new FileReader(htmlFile));
+            char[] buffer = new char[1024];
+            StringBuilder s = new StringBuilder();
+            int n;
+            do
+            {
+                n = br.read(buffer);
+                if (n != -1)
+                    s.append(buffer, 0, n);
+            }
+            while (n != -1);
+            
+            String processedContents = s.toString()
+               .replace("./resources/inherit.gif", new File(Config.getGreenfootLibDir(), "common/inherit.gif").toURI().toURL().toString())
+               //And, while I'm at it, fix that damn missing space:
+               .replace("</B><DT>extends", "</B><DT> extends")
+               ;
+            
+            
+            htmlPane.setText(processedContents);
+            htmlPane.setCaretPosition(0);
+            
+            //((HTMLDocument)htmlPane.getDocument()).setBase(new URL(fullURL));
+        }
+        catch (IOException e) {
+            Debug.reportError("Problem showing HTML for importable class " + stem, e);
+            htmlPane.setText("");
+        }
+    }
+    
+    private class ImportableClassButton extends ClassButton
+    {
+        private File file;
+        private String name;
+        
+        public ImportableClassButton(File file)
+        {
+            this.file = file;
+            name = GreenfootUtil.removeExtension(file.getName());
+            setText(name);
+            initUI();
+        }
+        
+        protected boolean isValidClass()
+        {
+            return true;
+        }
+
+        protected boolean isUncompiled()
+        {
+            return false;
+        }
+
+        @Override
+        protected void doubleClick()
+        {
+        }
+
+        @Override
+        public void select()
+        {
+            curSelection = file;
+            classLabel.setText(name);
+            File img = findImage(file);
+            curSelectionImage = img;
+            ImageIcon icon;
+            if (img == null)
+            {
+                icon = null;
+            }
+            else
+            {
+                icon = new ImageIcon(img.getAbsolutePath());
+                final int maxDim = 60;
+                if (Math.max(icon.getIconHeight(), icon.getIconWidth()) > maxDim)
+                {
+                    double scale = (double)maxDim / (double)Math.max(icon.getIconHeight(), icon.getIconWidth());
+                    icon.setImage(icon.getImage().getScaledInstance((int)(scale * icon.getIconWidth()), (int)(scale * icon.getIconHeight()), Image.SCALE_SMOOTH));
+                }
+            }
+            classPicture.setIcon(icon);
+            showHTML(GreenfootUtil.removeExtension(file.getAbsolutePath()));
+        }
+
+        @Override
+        public boolean deselect()
+        {
+            curSelection = null;
+            curSelectionImage = null;
+            classLabel.setText("");
+            classPicture.setIcon(null);
+            showHTML(null);
+            return false;
+        }
+
+        @Override
+        protected void maybeShowPopup(MouseEvent e)
+        {          
+        }
+    }
+    
+    //File dir = new File(Config.getGreenfootLibDir(), "common");
+    private void findAddImportableClasses(File dir, int indent)
+    {
+        File[] files = dir.listFiles(new FileFilter() {
+            @Override
+            public boolean accept(File pathname)
+            {
+                return pathname.getAbsolutePath().endsWith(".class") || pathname.getAbsolutePath().endsWith(".java") || pathname.isDirectory();
+            }
+        });
+        
+        if (files == null) //Problem finding classes
+            return;
+
+        // List all files before all directories:
+        
+        boolean hasAnyFiles = false;
+        for (File file : files) {
+            if (file.isFile()) {
+                ImportableClassButton button = new ImportableClassButton(file);
+                addWithIndent(indent, button);
+                buttonGroup.add(button);
+                hasAnyFiles = true;
+            }
+        }
+        
+        // Only indent if there is a class in the current category to be distinguished from:
+        if (hasAnyFiles)
+            indent += INDENT_HIERARCHY;
+        
+        for (File file : files) {
+            if (file.isDirectory()) {
+                JLabel label = new JLabel(file.getName());
+                label.setFont(label.getFont().deriveFont(16.0f));
+                addWithIndent(indent, label);
+                // Recurse to process sub-directories:
+                findAddImportableClasses(file, indent);
+            }
+        }
+    }
+    
+    /**
+     * Adds the given component to classList, with the given horizontal indent
+     */
+    private void addWithIndent(int indent, JComponent comp)
+    {
+        JPanel panel = new JPanel();
+        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
+        panel.add(Box.createHorizontalStrut(indent));
+        panel.add(comp);
+        panel.add(Box.createHorizontalGlue());
+        panel.setBackground(Color.WHITE);
+        panel.setMaximumSize(new Dimension(panel.getMaximumSize().width, panel.getPreferredSize().height));
+        classList.add(panel);
+    }
+    
+    /**
+     * Looks for an image that might be associated with the given class.
+     * 
+     * So given /foo/Crab.java or /foo/Crab.class, it looks (case insensitive) for /foo/crab.png, /foo/Crab.jpg, etc
+     */
+    private static File findImage(File classFile)
+    {
+        String[] extensions = ImageIO.getReaderFileSuffixes();
+        
+        File directory = classFile.getAbsoluteFile().getParentFile();
+        String stemName = GreenfootUtil.removeExtension(classFile.getAbsoluteFile().getName());
+        
+        File[] allFiles = directory.listFiles();
+        
+        if (allFiles == null)
+            return null;
+
+        for (File f : allFiles) {
+            for (String ext : extensions) {
+                if (f.getName().equalsIgnoreCase(stemName + "." + ext)) {
+                    return f;
+                }
+            }
+        }
+                
+        return null;
+    }
+    
+    private void importClass(File srcFile, File srcImage)
+    {
+        if (srcFile != null) {
+            String className = GreenfootUtil.removeExtension(srcFile.getName());
+            
+            ClassBrowser classBrowser = gfFrame.getClassBrowser();
+            GProject project = classBrowser.getProject();
+            
+            // Check if a class of the same name already exists in the project.
+            // Renaming would be too tricky, so just issue error and stop in that case:
+            for (GClass preexist : project.getDefaultPackage().getClasses(false)) {
+                if (preexist.getQualifiedName().equals(className)) {
+                    JOptionPane.showMessageDialog(gfFrame, "The current project already contains a class named " + className);
+                    return;
+                }
+            }
+            File destImage = null;
+            if (srcImage != null) {
+                destImage = new File(project.getImageDir(), srcImage.getName());
+                if (destImage.exists()) {
+                    JOptionPane.showMessageDialog(gfFrame, "The current project already contains an image file named " + srcImage.getName() + "; this file will NOT be replaced.");
+                }
+            }
+            
+            // Copy the java/class file cross:
+            File destFile = new File(project.getDir(), srcFile.getName());
+            GreenfootUtil.copyFile(srcFile, destFile);
+            
+            // We must reload the package to be able to access the GClass object:
+            project.getDefaultPackage().reload();
+            GClass gclass = project.getDefaultPackage().getClass(className);
+            
+            if (gclass == null) {
+                //TODO give an error
+                return;
+            }
+            
+            // Copy the image across and set it as the class image:
+            if (srcImage != null && destImage != null && !destImage.exists()) {
+                GreenfootUtil.copyFile(srcImage, destImage);
+                gclass.setClassProperty("image", destImage.getName());
+            }
+            
+            //Finally, update the class browser:
+            classBrowser.addClass(new ClassView(classBrowser, gclass, interactionListener));
+            classBrowser.updateLayout();
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/MessageDialog.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/MessageDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..6331532b745e3e7ee0a52fa3a15ff76fc3e251de
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/MessageDialog.java
@@ -0,0 +1,143 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dialog;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+
+import bluej.BlueJTheme;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+
+/**
+ * A message dialog presents the user with a message and an optional panel of
+ * buttons. To find out which buttons has been pressed a method is available
+ * that will show a modal dialog and return the button pressed.
+ * 
+ * @author Poul Henriksen
+ */
+public class MessageDialog extends EscapeDialog implements ActionListener
+{
+    private JButton[] buttons;
+    private JButton pressedButton;
+    
+    /**
+     * Creates a new dialog. The buttons will be placed right-justified at the
+     * bottom of the dialog, with the first item in the array to the left.
+     * 
+     * @param owner The parent dialog.
+     * @param message The message to display.
+     * @param title Title that goes in the window.
+     * @param width Width of the message in columns.
+     * @param buttons Array of buttons to display.
+     */
+    public MessageDialog(Dialog owner, String message, String title, int width, JButton[] buttons)
+    {
+        super(owner, title);
+        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+        createDialog(message, buttons, width);
+    }
+    /**
+     * Creates a new dialog. The buttons will be placed right-justified at the
+     * bottom of the dialog, with the first item in the array to the left.
+     * 
+     * @param owner The parent frame.
+     * @param message The message to display.
+     * @param title Title that goes in the window.
+     * @param width Width of the message in columns.
+     * @param buttons Array of buttons to display.
+     */
+    public MessageDialog(Frame owner, String message, String title, int width, JButton[] buttons)
+    {
+        super(owner, title);
+        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+        createDialog(message, buttons, width);
+    }
+    
+    private void createDialog(String message, JButton[] buttons, int width)
+    {
+        this.buttons = buttons;
+        JPanel contentPane = new JPanel(new BorderLayout());
+        setContentPane(contentPane);
+        contentPane.setBorder(BlueJTheme.dialogBorder);
+
+        WrappingMultiLineLabel messageLabel = new WrappingMultiLineLabel(message,width);
+        
+        contentPane.add(messageLabel, BorderLayout.CENTER);
+        
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5,5));
+        for(int i=0; i < buttons.length; i++) {
+            buttonPanel.add(buttons[i]);
+            buttons[i].addActionListener(this);
+        }
+        contentPane.add(buttonPanel, BorderLayout.SOUTH);
+  
+        pack();
+    }
+
+    
+    /**
+     * Displays the dialog until a button is pressed or the dialog is closed.
+     * @return The button that was used to close the dialog, or null if closed in another way.
+     */
+    public JButton displayModal()
+    {
+        setModal(true);  
+        DialogManager.centreDialog(this);
+        setVisible(true);
+        dispose();
+        return pressedButton;
+    }
+
+    /**
+     * Display the dialog (non-modal). 
+     */
+    public void display()
+    {
+        setModal(false);  
+        DialogManager.centreDialog(this);
+        setVisible(true);
+    }
+    /**
+     * Store the button pressed so that it can be returned. Close the dialog.
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+        JButton button = (JButton) e.getSource();
+        pressedButton = button;
+        for(int i=0; i < buttons.length; i++) {
+            buttons[i].removeActionListener(this);
+        }     
+        setVisible(false);
+        // We must NOT dispose here; otherwise, if the dialog is modal,
+        // setVisible(true) won't return (ever). JDK bug? (OpenJDK 1.6.0_23)
+        //   dispose();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/NewClassDialog.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/NewClassDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd99d9314f308fe306ca17f5ac198d4d77e8a29e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/NewClassDialog.java
@@ -0,0 +1,195 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import greenfoot.core.GPackage;
+import greenfoot.event.ValidityEvent;
+import greenfoot.event.ValidityListener;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.utility.EscapeDialog;
+
+/**
+ * Dialog that asks for the name of a new class. This is only used for non Actor
+ * classes.
+ * 
+ * @author Poul Henriksen
+ * @version $Id$
+ */
+public class NewClassDialog extends EscapeDialog
+{
+    JTextField classNameTextField;
+    private boolean okPressed = false;
+
+    /**
+     * Creates new dialog for creating a new class.
+     * 
+     * @param parent The parent frame
+     * @param pkg The package the class belongs to.
+     */
+    public NewClassDialog(JFrame parent, GPackage pkg)
+    {
+        super(parent, Config.getString("newclass.dialog.title"), true);
+
+        JPanel mainPanel = new JPanel();
+        setContentPane(mainPanel);
+        
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+        mainPanel.setBorder(BlueJTheme.generalBorder);
+
+        // help labels
+        JLabel helpLabel1 = GreenfootUtil.createHelpLabel();
+        JLabel helpLabel2 = GreenfootUtil.createHelpLabel();
+        helpLabel1.setText(Config.getString("newclass.dialog.help1"));
+        helpLabel2.setText(Config.getString("newclass.dialog.help2"));
+        helpLabel1.setAlignmentX(0.0f);
+        helpLabel2.setAlignmentX(0.0f);
+        mainPanel.add(helpLabel1);
+        mainPanel.add(helpLabel2);
+        mainPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        mainPanel.add(GreenfootUtil.createSpacer(GreenfootUtil.Y_AXIS, 2 * BlueJTheme.generalSpacingWidth));
+        
+        JLabel label = new JLabel(Config.getString("newclass.dialog.className"));
+        label.setAlignmentX(0.0f);
+        mainPanel.add(label);
+                
+        mainPanel.add(Box.createVerticalStrut(4));
+
+        classNameTextField = new JTextField();        
+        classNameTextField.setAlignmentX(0.0f);
+        Dimension classNameMax = classNameTextField.getMaximumSize();
+        classNameMax.height = classNameTextField.getPreferredSize().height;
+        classNameTextField.setMaximumSize(classNameMax);
+        mainPanel.add(classNameTextField);
+        
+        final JLabel errorMsgLabel = new JLabel();
+        errorMsgLabel.setAlignmentX(0.0f);
+        errorMsgLabel.setVisible(false);
+        errorMsgLabel.setForeground(Color.RED);
+        mainPanel.add(errorMsgLabel);
+        
+        // create the ok/cancel button panel
+        JPanel buttonPanel = new JPanel();
+
+        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
+
+        // push buttons over to the right using a glue component
+        buttonPanel.add(Box.createHorizontalGlue());
+
+        final JButton okButton = BlueJTheme.getOkButton();
+        okButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent evt)
+            {
+                ok();
+            }
+        });
+        okButton.setEnabled(false);
+
+        JButton cancelButton = BlueJTheme.getCancelButton();
+        cancelButton.setVerifyInputWhenFocusTarget(false);
+        cancelButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent evt)
+            {
+                cancel();
+            }
+        });
+        
+        if (Config.isMacOS()) {
+            buttonPanel.add(cancelButton);
+            buttonPanel.add(Box.createHorizontalStrut(BlueJTheme.generalSpacingWidth));
+            buttonPanel.add(okButton);
+        }
+        else {
+            buttonPanel.add(okButton);
+            buttonPanel.add(Box.createHorizontalStrut(BlueJTheme.generalSpacingWidth));
+            buttonPanel.add(cancelButton);
+        }
+
+        getRootPane().setDefaultButton(okButton);
+        buttonPanel.setAlignmentX(0.0f);
+
+        // Limit the growth of the button panel
+        Dimension buttonPanelMax = buttonPanel.getMaximumSize();
+        buttonPanelMax.height = buttonPanel.getPreferredSize().height;
+        buttonPanel.setMaximumSize(buttonPanelMax);
+        
+        ClassNameVerifier classNameVerifier = new ClassNameVerifier(classNameTextField, pkg);
+        classNameVerifier.addValidityListener(new ValidityListener(){
+            public void changedToInvalid(ValidityEvent e)
+            {
+                errorMsgLabel.setText(e.getReason());
+                errorMsgLabel.setVisible(true);
+                okButton.setEnabled(false);
+            }
+
+            public void changedToValid(ValidityEvent e)
+            {
+                errorMsgLabel.setVisible(false);
+                okButton.setEnabled(true);
+            }});
+        
+        mainPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        mainPanel.add(GreenfootUtil.createSpacer(GreenfootUtil.Y_AXIS,  2 * BlueJTheme.generalSpacingWidth));
+        mainPanel.add(Box.createVerticalGlue());
+        mainPanel.add(buttonPanel);
+        pack();
+
+        this.setLocationRelativeTo(parent);
+    }
+
+    private void ok()
+    {
+        okPressed = true;
+        dispose();
+    }
+
+    private void cancel()
+    {
+        okPressed = false;
+        dispose();
+    }
+
+    public String getClassName()
+    {
+        return classNameTextField.getText();
+    }
+
+    public boolean okPressed()
+    {
+        return okPressed;
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/SetPlayerDialog.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/SetPlayerDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..21a340cf6bc7f7c1cf0c8a51bf59feb4a239ef03
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/SetPlayerDialog.java
@@ -0,0 +1,130 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.utility.EscapeDialog;
+
+public class SetPlayerDialog extends EscapeDialog
+{
+    private String finalPlayerName; 
+    private JTextField playerNameTextField;
+    private JButton okButton;
+
+    public SetPlayerDialog(JFrame parent, String curPlayerName)
+    {
+        super(parent, Config.getString("playername.dialog.title"), true);
+        
+        finalPlayerName = curPlayerName; // By default, it will be unchanged
+
+        JPanel mainPanel = new JPanel();
+        setContentPane(mainPanel);
+        
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+        mainPanel.setBorder(BlueJTheme.generalBorder);
+
+        // help labels
+        JLabel helpLabel1 = GreenfootUtil.createHelpLabel();
+        helpLabel1.setText(Config.getString("playername.dialog.help"));
+        helpLabel1.setAlignmentX(0.0f);
+        mainPanel.add(helpLabel1);
+        mainPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        mainPanel.add(GreenfootUtil.createSpacer(GreenfootUtil.Y_AXIS, 2 * BlueJTheme.generalSpacingWidth));
+        
+        JLabel label = new JLabel(Config.getString("playername.dialog.playerName"));
+        label.setAlignmentX(0.0f);
+        mainPanel.add(label);
+                
+        mainPanel.add(Box.createVerticalStrut(4));
+
+        playerNameTextField = new JTextField();
+        playerNameTextField.setAlignmentX(0.0f);
+        Dimension playerNameMax = playerNameTextField.getMaximumSize();
+        playerNameMax.height = playerNameTextField.getPreferredSize().height;
+        playerNameTextField.setMaximumSize(playerNameMax);
+        mainPanel.add(playerNameTextField);
+                
+        // create the ok/cancel button panel
+        JPanel buttonPanel = new JPanel();
+
+        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
+
+        // push buttons over to the right using a glue component
+        buttonPanel.add(Box.createHorizontalGlue());
+
+        okButton = BlueJTheme.getOkButton();
+        okButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent evt)
+            {
+                ok();
+            }
+        });
+        
+        buttonPanel.add(okButton);
+        
+        getRootPane().setDefaultButton(okButton);
+        buttonPanel.setAlignmentX(0.0f);
+
+        // Limit the growth of the button panel
+        Dimension buttonPanelMax = buttonPanel.getMaximumSize();
+        buttonPanelMax.height = buttonPanel.getPreferredSize().height;
+        buttonPanel.setMaximumSize(buttonPanelMax);
+                
+        playerNameTextField.setText(curPlayerName);
+        
+        mainPanel.add(Box.createVerticalStrut(BlueJTheme.generalSpacingWidth));
+        mainPanel.add(GreenfootUtil.createSpacer(GreenfootUtil.Y_AXIS,  2 * BlueJTheme.generalSpacingWidth));
+        mainPanel.add(Box.createVerticalGlue());
+        mainPanel.add(buttonPanel);
+        pack();
+
+        this.setLocationRelativeTo(parent);
+    }
+
+    private void ok()
+    {
+        finalPlayerName = playerNameTextField.getText(); 
+        dispose();
+    }
+    public String getPlayerName()
+    {
+        return finalPlayerName;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/WorldCanvas.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/WorldCanvas.java
new file mode 100644
index 0000000000000000000000000000000000000000..39c4b562b7af143d5dfa6f726ee8de3b78ccd048
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/WorldCanvas.java
@@ -0,0 +1,392 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+import greenfoot.GreenfootImage;
+import greenfoot.ImageVisitor;
+import greenfoot.World;
+import greenfoot.WorldVisitor;
+import greenfoot.core.WorldHandler;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import javax.swing.JPanel;
+import javax.swing.Scrollable;
+import javax.swing.SwingConstants;
+
+/**
+ * The visual representation of the world.
+ * 
+ * @author Poul Henriksen
+ */
+public class WorldCanvas extends JPanel
+    implements  DropTarget, Scrollable
+{
+    private World world;
+    private DropTarget dropTargetListener;
+    /** The actor being dragged. Null if no dragging. */ 
+    private Actor dragActor;
+    /** The current location where the object is dragged - in pixel coordinates relative to this canvas. */
+    private Point dragLocation;
+    /** Image used when dragging new actors on the world. Includes the drop shadow.*/
+    private BufferedImage dragImage;
+    /** Preferred size (not counting insets) */
+    private Dimension size;
+    
+    public WorldCanvas(World world)
+    {
+        setWorld(world);
+        setBackground(Color.WHITE);
+        setOpaque(true);
+    }
+    
+    /**
+     * Sets the world that should be visualised by this canvas.
+     * Call only from the Swing event thread.
+     */
+    public void setWorld(World world)
+    {
+        this.world = world;
+        if (world != null) {
+            this.setSize(getPreferredSize());
+            revalidate();
+            repaint();
+        }
+        else {
+            // this.setSize(0, 0);
+        }
+    }
+
+    /**
+     * Set the last known world size. Affects the preferred size of the
+     * WorldCanvas.
+     */
+    public void setWorldSize(int xsize, int ysize)
+    {
+        if (world == null) {
+            size = new Dimension(xsize, ysize);
+        }
+    }
+    
+    /**
+     * Paints all the objects.
+     * 
+     * Must be synchronized on the World.lock.
+     */
+    public void paintObjects(Graphics2D g)
+    {
+        Set<Actor> objects = WorldVisitor.getObjectsListInPaintOrder(world);
+        int paintSeq = 0;
+        for (Iterator<Actor> iter = objects.iterator(); iter.hasNext();) {
+            Actor thing = iter.next();
+            int cellSize = WorldVisitor.getCellSize(world);
+
+            GreenfootImage image = ActorVisitor.getDisplayImage(thing);
+            if (image != null) {
+                ActorVisitor.setLastPaintSeqNum(thing, paintSeq++);
+
+                double halfWidth = image.getWidth() / 2.;
+                double halfHeight = image.getHeight() / 2.;
+
+                AffineTransform oldTx = null;
+                try {
+                    int ax = ActorVisitor.getX(thing);
+                    int ay = ActorVisitor.getY(thing);
+                    double xCenter = ax * cellSize + cellSize / 2.;
+                    int paintX = (int) Math.floor(xCenter - halfWidth);
+                    double yCenter = ay * cellSize + cellSize / 2.;
+                    int paintY = (int) Math.floor(yCenter - halfHeight);
+
+                    int rotation = ActorVisitor.getRotation(thing);
+                    if (rotation != 0) {
+                        // don't bother transforming if it is not rotated at
+                        // all.
+                        oldTx = g.getTransform();
+                        g.rotate(Math.toRadians(rotation), xCenter, yCenter);
+                    }
+
+                    ImageVisitor.drawImage(image, g, paintX, paintY, this, true);
+                }
+                catch (IllegalStateException e) {
+                    // We get this if the object has been removed from the
+                    // world. That can happen when interactively invoking a
+                    // method that removes an object from the world, while the
+                    // scenario is executing.
+                }
+
+                // Restore the old state of the graphics
+                if (oldTx != null) {
+                    g.setTransform(oldTx);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void paintComponent(Graphics g)
+    {
+        if (world == null) {
+            Color c = g.getColor();
+            g.setColor(getParent().getBackground());
+            g.fillRect(0, 0, getWidth(), getHeight());
+            g.setColor(c);
+            WorldHandler.getInstance().repainted();
+            return;
+        }
+        
+        // We need to sync, so that objects are not added and removed when we
+        // traverse the list.
+        // But, we only try to get the lock for a brief period to avoid
+        // deadlocks. A deadlock could otherwise happen if a modal dialog is
+        // created from the user code in one of the act() methods.
+        // We could do the sync only on the paintObjects, but that would mean
+        // that the background will be reset and no objects painted, resulting
+        // in a slightly broken look, if the user code is sleeping (with
+        // Thread.sleep).
+        try {
+            ReentrantReadWriteLock lock = WorldHandler.getInstance().getWorldLock();
+            int timeout = WorldHandler.READ_LOCK_TIMEOUT;
+            if (lock.readLock().tryLock(timeout, TimeUnit.MILLISECONDS)) {
+                try {
+                    Insets insets = getInsets();
+                    Graphics2D g2 = (Graphics2D) g;
+                    g.translate(insets.left, insets.top);
+                    paintBackground(g2);
+                    paintObjects(g2);
+                    paintDraggedObject(g2);
+                    WorldVisitor.paintDebug(world, g2);
+                    g.translate(-insets.left, -insets.top);
+                }
+                finally {
+                    lock.readLock().unlock();
+                    WorldHandler.getInstance().repainted();
+                }
+            }
+            else {
+                WorldHandler.getInstance().repainted(); // we failed, but notify waiters anyway
+                // (otherwise they keep waiting indefinitely...)
+            }
+        }
+        catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * If an object is being dragged, paint it.
+     */
+    private void paintDraggedObject(Graphics g)
+    {
+        if(dragImage != null) {
+            int x = (int) dragLocation.getX();
+            int y = (int) dragLocation.getY();
+            int xCell =  WorldVisitor.toCellFloor(world, x);
+            int yCell =  WorldVisitor.toCellFloor(world, y);
+            int cellSize = WorldVisitor.getCellSize(world);
+            x = (int) ((xCell + 0.5) * cellSize - dragImage.getWidth()/2);
+            y = (int) ((yCell + 0.5) * cellSize - dragImage.getHeight()/2);
+            
+            g.drawImage(dragImage, x, y, null);            
+        } 
+    }
+
+    /**
+     * Paint the world background. This takes tiling into account: the
+     * world image is painted either once or tiled onto this component.
+     */
+    public void paintBackground(Graphics2D g)
+    {
+        if (world != null) {
+            GreenfootImage backgroundImage = WorldVisitor.getBackgroundImage(world);
+            if (backgroundImage != null) {
+                ImageVisitor.drawImage(backgroundImage, g, 0, 0, this, true);
+            }
+            else {
+                Color oldColor = g.getColor();
+                g.setColor(getBackground());
+                g.fillRect(0, 0, this.getWidth(), this.getHeight());
+                g.setColor(oldColor);
+            }
+        }
+    }
+
+    @Override
+    public Dimension getMinimumSize()
+    {
+        return getPreferredSize();
+    }
+
+    @Override
+    public Dimension getPreferredSize()
+    {
+        if (world != null) {
+            size = new Dimension();
+            size.width = WorldVisitor.getWidthInPixels(world) ;
+            size.height = WorldVisitor.getHeightInPixels(world) ;
+            Insets insets = getInsets();
+            size.width += insets.left + insets.right;
+            size.height += insets.top + insets.bottom;
+            return size;
+        }
+        else if (size != null) {
+            return size;
+        }
+        else {
+            return super.getPreferredSize();
+        }
+    }
+    
+    public void setDropTargetListener(DropTarget dropTargetListener)
+    {
+        this.dropTargetListener = dropTargetListener;
+    }
+
+    @Override
+    public boolean drop(Object o, Point p)
+    {
+        Insets insets = getInsets();
+        Point p2 = new Point(p.x - insets.left, p.y - insets.top);
+        clearDragInfo();
+        if (dropTargetListener != null) {
+            return dropTargetListener.drop(o, p2);
+        }
+        else {
+            return false;
+        }
+    }
+
+    /**
+     * If it is a new actor, that has not been added to the world yet, the
+     * dragging is handled here.
+     */
+    public boolean drag(Object o, Point p)
+    {
+        Insets insets = getInsets();
+        Point p2 = new Point(p.x - insets.left, p.y - insets.top);
+        if(o instanceof Actor && ActorVisitor.getWorld((Actor) o) == null) {   
+            if(!getVisibleRect().contains(p)) {
+                return false;
+            }
+            if(o != dragActor) {
+                // It is the first time we are dragging this actor. Create the drag image.
+                dragActor = (Actor) o;          
+                dragImage = GreenfootUtil.createDragShadow(ActorVisitor.getDragImage(dragActor).getAwtImage());
+            }
+            dragLocation = p2;
+            repaint();
+            return true;            
+        }        
+        else if (dropTargetListener != null) {
+            return dropTargetListener.drag(o, p2);
+        }
+        else {        
+            return false;
+        }
+    }
+    
+    public void dragEnded(Object o)
+    {
+        clearDragInfo();
+        if (dropTargetListener != null) {
+            dropTargetListener.dragEnded(o);
+        }
+        
+    }
+
+    /** 
+     * End the drag by setting all the drag information to null. And request repaint to update the graphics.
+     */
+    private void clearDragInfo()
+    {
+        dragLocation = null;
+        dragActor = null;
+        dragImage = null;
+        repaint();
+    }
+
+    public Dimension getPreferredScrollableViewportSize()
+    {
+        return getPreferredSize();
+    }
+
+    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
+    {
+        int cellSize = world.getCellSize();
+        double scrollPos = 0;
+        if(orientation == SwingConstants.HORIZONTAL) {
+            //scrolling left
+            if(direction < 0) {
+                scrollPos = visibleRect.getMinX();
+               
+            }
+            //scrolling right
+            else if (direction > 0) {
+                scrollPos = visibleRect.getMaxX();
+            }
+        } else {
+            //scrolling up
+            if(direction < 0) {
+                scrollPos = visibleRect.getMinY();
+            }
+            //scrolling down
+            else if (direction > 0) {
+                scrollPos = visibleRect.getMaxY();
+            }
+        }
+        int increment = Math.abs((int) Math.IEEEremainder(scrollPos, cellSize));
+        if(increment == 0) {
+            increment = cellSize;
+        }
+      
+        return  increment;
+    }
+
+    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
+    {
+         return getScrollableUnitIncrement(visibleRect, orientation, direction);
+    }
+
+    public boolean getScrollableTracksViewportWidth()
+    {
+        return false;
+    }
+
+    public boolean getScrollableTracksViewportHeight()
+    {
+        return false;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/WrappingMultiLineLabel.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/WrappingMultiLineLabel.java
new file mode 100644
index 0000000000000000000000000000000000000000..4735b3e63d73174d321947e9c5ef76b22ab855ab
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/WrappingMultiLineLabel.java
@@ -0,0 +1,107 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui;
+
+import javax.swing.JLabel;
+
+import bluej.utility.MultiLineLabel;
+
+/**
+ * A label that wraps lines when they exceed a specified length. It wraps on
+ * word boundaries only.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class WrappingMultiLineLabel extends MultiLineLabel
+{
+    private int cols;
+
+    public WrappingMultiLineLabel(String text, int numCols)
+    {
+        super(null);
+        alignment = LEFT_ALIGNMENT;
+        cols = numCols;
+        addText(text);
+    }
+
+    public void setText(String text)
+    {
+        addText(text);
+    }
+
+    public void addText(String text)
+    {
+        if (text != null) {
+            // get user enforced line breaks
+            String strs[] = text.split("\n");
+
+            for (int i = 0; i < strs.length; i++) {
+                int lastIndex = 0;
+                int index = getLineBreakPoint(strs[i], lastIndex);
+                while (index > lastIndex) {
+                    addLabel(strs[i].substring(lastIndex, index).trim());
+                    lastIndex = index;
+                    index = getLineBreakPoint(strs[i], lastIndex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the next point at which to break the line, assuming that there was a
+     * break at lastIndex.
+     * 
+     * @param str The string
+     * @param lastIndex Only look at the string from this index onwards.
+     * @return The new index to break the line at. The end has been reached when
+     *         index==lastIndex
+     */
+    private int getLineBreakPoint(String str, int lastIndex)
+    {
+        int index = str.lastIndexOf(" ", lastIndex + cols);
+        // no new whitespace found.
+        if (index == lastIndex || index == -1) {
+            index = lastIndex + cols;
+        }
+        // truncate to stay within string bounds
+        if (index >= str.length()) {
+            index = str.length();
+        }
+        // if the rest of the string will fit in, just add that
+        int strLength = index - lastIndex;
+        int rest = str.length() - index;
+        if ((strLength + rest) < cols) {
+            index = str.length();
+        }
+        return index;
+    }
+
+    private void addLabel(String str)
+    {
+        if (str.equals(""))
+            str = " "; // To make empty lines
+        JLabel label = new JLabel(str);
+        label.setAlignmentX(alignment);
+        add(label);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowConnect.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowConnect.java
new file mode 100644
index 0000000000000000000000000000000000000000..171e45bc8744eb11512d0e93d1aad5f0ce338c25
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowConnect.java
@@ -0,0 +1,42 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+
+/**
+ * Graphics for the line part of an arrow. With a connector to the right.
+ *  | |__ | |
+ * 
+ * @author Poul Henriksen
+ */
+public class ArrowConnect extends ArrowElement
+{
+    public void paintComponent(Graphics g)
+    {
+        Dimension size = getSize();
+        g.drawLine(size.width / 2, 0, size.width / 2, size.height);
+        g.drawLine(size.width / 2, size.height / 2, size.width, size.height / 2);
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowConnectEnd.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowConnectEnd.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb6397417c82e14e4336644dfd19519fc9aa70a9
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowConnectEnd.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+
+/**
+ * Graphics for the end line part of an arrow. With a connector to the right.
+ *  | |__
+ * 
+ * @author Poul Henriksen
+ */
+public class ArrowConnectEnd extends ArrowElement
+{
+    public void paintComponent(Graphics g)
+    {
+        Dimension size = getSize();
+        g.drawLine(size.width / 2, 0, size.width / 2, size.height / 2);
+        g.drawLine(size.width / 2, size.height / 2, size.width, size.height / 2);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowElement.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..2efba9139b209a6d9efb666dc3fa5bb12d533d45
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowElement.java
@@ -0,0 +1,53 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+
+import javax.swing.JComponent;
+
+/**
+ * Superclass for all elements of an arrow. Takes care of preferred sizes.
+ *  ^ | |__ | |
+ * 
+ * @author mik
+ */
+public abstract class ArrowElement extends JComponent
+{
+    protected static final int ARROW_WIDTH = 14;
+    protected static final int ARROW_HEIGHT = 7;
+    
+    private static final Dimension minimumSize = new Dimension(ARROW_WIDTH + 8, ARROW_HEIGHT);
+
+    public abstract void paintComponent(Graphics g);
+
+    public Dimension getMinimumSize()
+    {
+        return minimumSize;
+    }
+
+    public Dimension getPreferredSize()
+    {
+        return minimumSize;
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowHead.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowHead.java
new file mode 100644
index 0000000000000000000000000000000000000000..e131c93030f187b9e4febf33d69c301f6807d2af
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowHead.java
@@ -0,0 +1,49 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Polygon;
+
+/**
+ * Graphics for the head of an arrow. With a connector to the right.
+ *  ^ | |__ | |
+ * 
+ * @author Poul Henriksen
+ * @version $Id: ArrowHead.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class ArrowHead extends ArrowElement
+{
+    public void paintComponent(Graphics g)
+    {
+        Dimension size = getSize();
+        Polygon arrow = new Polygon();
+        arrow.addPoint(size.width / 2, 0);
+        arrow.addPoint((size.width / 2) - ARROW_WIDTH / 2, ARROW_HEIGHT);
+        arrow.addPoint((size.width / 2) + ARROW_WIDTH / 2, ARROW_HEIGHT);
+
+        g.drawLine(size.width / 2, 0 + ARROW_HEIGHT, size.width / 2, size.height);
+        g.drawLine(size.width / 2, size.height / 2, size.width, size.height / 2);
+        g.drawPolygon(arrow);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowHeadEnd.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowHeadEnd.java
new file mode 100644
index 0000000000000000000000000000000000000000..bbac788573f6a228be51c01cf9964e0a8cc690d2
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowHeadEnd.java
@@ -0,0 +1,49 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Polygon;
+
+/**
+ * Graphics for the head of an arrow. With a connector to the right.
+ *  ^ | |__
+ * 
+ * @author Poul Henriksen
+ * @version $Id: ArrowHeadEnd.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class ArrowHeadEnd extends ArrowElement
+{
+    public void paintComponent(Graphics g)
+    {
+        Dimension size = getSize();
+        Polygon arrow = new Polygon();
+        arrow.addPoint(size.width / 2, 0);
+        arrow.addPoint((size.width / 2) - ARROW_WIDTH / 2, ARROW_HEIGHT);
+        arrow.addPoint((size.width / 2) + ARROW_WIDTH / 2, ARROW_HEIGHT);
+
+        g.drawLine(size.width / 2, 0 + ARROW_HEIGHT, size.width / 2, size.height / 2);
+        g.drawLine(size.width / 2, size.height / 2, size.width, size.height / 2);
+        g.drawPolygon(arrow);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowLine.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowLine.java
new file mode 100644
index 0000000000000000000000000000000000000000..608a0410dca9808f4f4b9546616e701be4f8d19c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ArrowLine.java
@@ -0,0 +1,40 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+
+/**
+ * Graphics for the head of an arrow. With a connector to the right.
+ * 
+ * @author Poul Henriksen
+ * @version $Id: ArrowLine.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class ArrowLine extends ArrowElement
+{
+    public void paintComponent(Graphics g)
+    {
+        Dimension size = getSize();
+        g.drawLine(size.width / 2, 0, size.width / 2, size.height);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassBrowser.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassBrowser.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d0e912a1e00d5a860a222a292f594420a4cd80f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassBrowser.java
@@ -0,0 +1,366 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import bluej.Config;
+import greenfoot.core.GProject;
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.classbrowser.ClassForest.TreeEntry;
+import greenfoot.gui.classbrowser.role.ActorClassRole;
+import greenfoot.gui.classbrowser.role.WorldClassRole;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JRootPane;
+import javax.swing.border.TitledBorder;
+
+/**
+ * 
+ * This is the component which has all the classes (from the project + the
+ * system classes) that is visible in UI. It is responsible for drawing and
+ * laying out the classes.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class ClassBrowser extends JPanel
+{
+    private ButtonGroup buttonGroup = new ButtonGroup();
+
+    private SelectionManager selectionManager = new SelectionManager();
+
+    private ClassForest worldClasses = new ClassForest();
+    private ClassForest greenfootClasses = new ClassForest();
+    private ClassForest otherClasses = new ClassForest();
+    
+    private GProject project;
+
+    private GreenfootFrame frame;
+
+    /**
+     * Construct a new ClassBrowser
+     */
+    public ClassBrowser(GProject project, GreenfootFrame frame)
+    {
+    	this.project = project;
+    	this.frame = frame;
+        setLayout(new BorderLayout());
+        setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
+        setBackground(Color.WHITE);
+
+        worldClasses = new ClassForest();
+        greenfootClasses = new ClassForest();
+        otherClasses = new ClassForest();
+    }
+
+    /**
+     * Add a new class to the class browser data structure, without updating
+     * the view on screen. The view can be explicitly updated later, using 
+     * updateLayout().
+     */
+    public void quickAddClass(ClassView classView)
+    {
+        if (classView.getRole() instanceof ActorClassRole) {
+            greenfootClasses.add(classView);
+        }
+        else if (classView.getRole() instanceof WorldClassRole) {           
+            worldClasses.add(classView);
+        }
+        else {
+            // everything else
+            otherClasses.add(classView);
+        }
+        buttonGroup.add(classView);
+        classView.addSelectionChangeListener(selectionManager);        
+    }
+    
+    /**
+     * Add a new class to the class browser.
+     * Call only from the Swing event thread.
+     */
+    public void addClass(ClassView classView)
+    {
+        quickAddClass(classView);
+        classView.select();
+        updateLayout();
+    }
+    
+    /**
+     * Remove a class from the browser and update the view on screen.
+     * 
+     * <br>
+     * Must be called from the event thread.
+     */
+    public void removeClass(ClassView classView) 
+    {
+    	// We have to remove the class view from the button group first;
+    	// otherwise it's deselecting the button doesn't work.
+        buttonGroup.remove(classView);
+        classView.deselect();
+
+        TreeEntry treeEntry = removeFromForest(classView);
+        List<TreeEntry> children = treeEntry.getChildren();
+        for (TreeEntry child : children) {
+            otherClasses.add(child);
+		}
+        
+        classView.removeSelectionChangeListener(selectionManager);
+        updateLayout();
+    }
+
+    private TreeEntry removeFromForest(ClassView classView)
+    {
+    	TreeEntry removedEntry = greenfootClasses.remove(classView);
+    	if(removedEntry == null) {
+    		removedEntry = worldClasses.remove(classView);
+    	}
+    	if(removedEntry == null) {
+    		removedEntry = otherClasses.remove(classView);
+    	}    	
+    	return removedEntry;
+    }
+    
+
+	/**
+     * Notify the class browser that a class has changed name
+     * @param classView  The classView of the class which name has named
+     * @param oldName    The original name of the class
+     */
+    public void renameClass(ClassView classView, String oldName)
+    {
+        greenfootClasses.rename(classView, oldName);
+        worldClasses.rename(classView, oldName);
+        otherClasses.rename(classView, oldName);
+    }
+    
+    /**
+     * Arrange and show the class views on screen.
+     * Call only from the Swing event thread.
+     */
+    public void updateLayout()
+    {
+        greenfootClasses.rebuild();
+        worldClasses.rebuild();
+        otherClasses.rebuild();
+        
+        this.removeAll();  // remove current components
+
+        // world Classes
+
+        JComponent worldClassPanel = createClassHierarchyComponent(worldClasses.getRoots(), false);
+
+        JPanel worldFrame = new JPanel();
+        ((FlowLayout)worldFrame.getLayout()).setAlignment(FlowLayout.LEFT);
+        worldFrame.setBackground(Color.WHITE);
+        worldFrame.add(worldClassPanel);
+        TitledBorder border = BorderFactory.createTitledBorder(null, Config.getString("browser.border.world"));
+        border.setTitleColor(Color.GRAY);
+        worldFrame.setBorder(border);
+
+        this.add(worldFrame, BorderLayout.NORTH);
+
+        // simulation classes
+
+        JComponent greenfootClassPanel = createClassHierarchyComponent(greenfootClasses.getRoots(), false);
+
+        if (greenfootClassPanel != null) {
+            JPanel objectFrame = new JPanel();
+            ((FlowLayout)objectFrame.getLayout()).setAlignment(FlowLayout.LEFT);
+            objectFrame.setBackground(Color.WHITE);
+            objectFrame.add(greenfootClassPanel);
+            border = BorderFactory.createTitledBorder(null, Config.getString("browser.border.actors"));
+            border.setTitleColor(Color.GRAY);
+            objectFrame.setBorder(border);
+
+            this.add(objectFrame, BorderLayout.CENTER);
+        }
+        
+        if (! otherClasses.getRoots().isEmpty()) {
+            JComponent otherClassPanel = createClassHierarchyComponent(otherClasses.getRoots(), false);
+            
+            if (otherClassPanel != null) {
+                JPanel objectFrame = new JPanel();
+                ((FlowLayout)objectFrame.getLayout()).setAlignment(FlowLayout.LEFT);
+                objectFrame.setBackground(Color.WHITE);
+                objectFrame.add(otherClassPanel);
+                border = BorderFactory.createTitledBorder(null, Config.getString("browser.border.others"));
+                border.setTitleColor(Color.GRAY);
+                objectFrame.setBorder(border);
+                
+                this.add(objectFrame, BorderLayout.SOUTH);
+            }
+        }
+        
+        // Don't know why I have to revalidate on the RootPane instead of just
+        // the class browser. But that is the only way to make it resize the
+        // class browser if a longer class name has been added.
+        // Poul 30/10/2006
+        JRootPane rootPane = getRootPane();
+        if (rootPane != null) {
+        	getRootPane().revalidate();
+        }
+    }
+
+
+    /**
+     * Creates a component with the class hierarchy. This method calls itself
+     * recursively.
+     * 
+     * @param roots
+     *            All the superclasses (classe hat are NOT subclasses)
+     * @param header
+     *            A header for specifying the types of classes in this
+     *            hierarchy.
+     * @return
+     */
+    private JComponent createClassHierarchyComponent(Collection<TreeEntry> roots,
+            boolean isRecursiveCall)
+    {
+        JComponent hierarchyPanel = new JPanel();
+        hierarchyPanel.setOpaque(false);
+        hierarchyPanel.setLayout(new BoxLayout(hierarchyPanel, BoxLayout.Y_AXIS));
+        
+        boolean isFirstSubclass = true; //whether it is the first subclass
+
+        for (Iterator<TreeEntry> iter = roots.iterator(); iter.hasNext();) {
+            JComponent classPanel = new JPanel();
+            classPanel.setOpaque(false);
+            classPanel.setLayout(new BoxLayout(classPanel, BoxLayout.X_AXIS));
+
+            ClassForest.TreeEntry element = iter.next();
+
+            if (!isRecursiveCall) {
+                // not recursive: we are at the greenfoot root - no arrows up
+            }
+            else if (isFirstSubclass && !iter.hasNext()) {
+                // first and last subclass: arrow head, no line to bottom
+                classPanel.add(new ArrowHeadEnd());
+            }
+            else if (isFirstSubclass) {
+                // first, but not last, subclass: arrow head with line down
+                classPanel.add(new ArrowHead());
+            }
+            else if (!iter.hasNext()) {
+                // last subclass: line end
+                classPanel.add(new ArrowConnectEnd());
+            }
+            else {
+                // subclass in middle: line to top and bottom
+                classPanel.add(new ArrowConnect());
+            }
+
+            JComponent classView = element.getData();
+            classPanel.add(classView);
+            JComponent flowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
+            flowPanel.add(classPanel);
+            flowPanel.setOpaque(false);
+            hierarchyPanel.add(flowPanel);
+            
+            List<TreeEntry> children = element.getChildren();
+            if(!children.isEmpty()) {
+                JComponent childPanel = new JPanel();
+                childPanel.setOpaque(false);
+                childPanel.setLayout(new BoxLayout(childPanel, BoxLayout.X_AXIS));
+
+                JComponent child = createClassHierarchyComponent(children, true);
+                if (iter.hasNext()) {
+                    childPanel.add(new ArrowLine());
+                }
+                else if (isRecursiveCall) {
+                    childPanel.add(new EmptySpace());
+                }
+                childPanel.add(child);
+                flowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
+                flowPanel.setOpaque(false);
+                flowPanel.add(childPanel);
+                hierarchyPanel.add(flowPanel);
+            }
+            
+            isFirstSubclass = false;
+        }
+
+        return hierarchyPanel;
+    }
+
+    /**
+     * Get the selection manager for this class browser.
+     */
+    public SelectionManager getSelectionManager()
+    {
+        return selectionManager;
+    }
+
+    /**
+     * Updates the layout of the ClassBrowser to make sure the given classView
+     * is displayed with the correct superclass and in the right section of the
+     * classbrowser.
+     * <p>
+     * Call updateLayout to make the changes visible.
+     * 
+     * @see #updateLayout()
+     * @param classView
+     */
+    public void consolidateLayout(ClassView classView)
+    {
+        // Only change the role if we have been initialised
+        if (greenfootClasses != null) {
+            // Remove it from the forest since it is in the wrong forest.
+
+            TreeEntry removed = removeFromForest(classView);
+
+            // Add it to the right forest.
+            if (classView.getRole() instanceof ActorClassRole) {
+                greenfootClasses.add(removed);
+            }
+            else if (classView.getRole() instanceof WorldClassRole) {
+                worldClasses.add(removed);
+            }
+            else {
+                // everything else
+                otherClasses.add(removed);
+            }
+        }      
+        updateLayout();
+    }
+    
+    public GProject getProject()
+    {
+    	return project;
+    }
+
+    /** 
+     * Get the parent frame of this class browser.
+     */
+    public GreenfootFrame getFrame()
+    {
+        return frame;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassButton.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassButton.java
new file mode 100644
index 0000000000000000000000000000000000000000..8cb56cbc32fbeb65e77d45f7f472a9336c363a13
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassButton.java
@@ -0,0 +1,201 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.JToggleButton;
+
+import bluej.utility.Utility;
+
+/**
+ * The drawing aspect of the class buttons in the class browser
+ * and the import-class dialog
+ * 
+ * @author neil
+ */
+public abstract class ClassButton extends JToggleButton implements MouseListener, Selectable
+{
+
+    private final Color classColour = new Color(245, 204, 155);
+    private static final Color stripeColor = new Color(152,152,152);
+    public static final Color[] shadowColours = { new Color(242, 242, 242), 
+                                                      new Color(211, 211, 211),
+                                                      new Color(189, 189, 189),
+                                                      new Color(83, 83, 83)
+                                                    };
+    private static final int SHADOW = 4;
+    private static final int GAP = 2;
+    private static final int SELECTED_BORDER = 3;
+   
+    // Sees if the class is valid
+    protected abstract boolean isValidClass();
+    // Sees if the class is uncompiled (and thus should be shaded)
+    protected abstract boolean isUncompiled();
+    // Called when the class button is double-clicked
+    protected abstract void doubleClick();
+    // Called when a popup should be shown (i.e. when the button is right-clicked/control-clicked)
+    protected abstract void maybeShowPopup(MouseEvent e);
+
+    protected void initUI()
+    {
+        this.addMouseListener(this);
+        this.setBorder(BorderFactory.createEmptyBorder(7, 8, 10, 11)); // top,left,bottom,right
+        Font font = getFont();
+        font = font.deriveFont(13.0f);
+        this.setFont(font);
+        // this.setFont(PrefMgr.getTargetFont());
+
+        setContentAreaFilled(false);
+        setFocusPainted(false);
+    }
+    
+    /**
+     * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
+     */
+    public void paintComponent(Graphics g)
+    {
+        // Sometimes there are still paint events pending when the gclass
+        // has been removed. We can check for that here.
+        if (isValidClass()) {
+            drawBackground(g);
+            super.paintComponent(g);
+            
+            drawShadow((Graphics2D) g);
+            drawBorders((Graphics2D) g);
+        }
+    }
+
+    private void drawBackground(Graphics g)
+    {
+        int height = getHeight() - SHADOW - GAP;
+        int width = getWidth() - 4;
+    
+        g.setColor(classColour);
+        g.fillRect(0, GAP, width, height);
+        
+        if(isUncompiled()) {
+            g.setColor(stripeColor);
+            Utility.stripeRect(g, 0, GAP, width, height, 8, 3);
+    
+            g.setColor(classColour);
+            g.fillRect(7, GAP+7, width-14, height-14);
+        }
+    }
+
+    /**
+     * Draw a 'shadow' appearance under and to the right of the target.
+     */
+    protected void drawShadow(Graphics2D g)
+    {
+        int height = getHeight() - SHADOW;
+        int width = getWidth() - 4;
+        
+        g.setColor(Color.WHITE);
+        g.fillRect(0, 0, width + 4, GAP);   // blank for gap above class
+        g.fillRect(0, height, 6, height + SHADOW);
+        g.fillRect(width, 0, width + 3, 10);
+        
+        // colorchange is expensive on mac, so draworder is by color, not position
+        g.setColor(shadowColours[3]);
+        g.drawLine(3, height, width, height);//bottom
+    
+        g.setColor(shadowColours[2]);
+        g.drawLine(4, height + 1, width, height + 1);//bottom
+        g.drawLine(width + 1, height + 2, width + 1, 3 + GAP);//right
+    
+        g.setColor(shadowColours[1]);
+        g.drawLine(5, height + 2, width + 1, height + 2);//bottom
+        g.drawLine(width + 2, height + 3, width + 2, 4 + GAP);//right
+    
+        g.setColor(shadowColours[0]);
+        g.drawLine(6, height + 3, width + 2, height + 3); //bottom
+        g.drawLine(width + 3, height + 3, width + 3, 5 + GAP); // right
+    }
+
+    /**
+     * Draw the borders of this target.
+     */
+    protected void drawBorders(Graphics2D g)
+    {
+        g.setColor(Color.BLACK);
+        int thickness = isSelected() ? SELECTED_BORDER : 1;
+        Utility.drawThickRect(g, 0, GAP, getWidth() - 4, getHeight() - SHADOW - GAP - 1, thickness);
+    }
+    
+    // Override's Component's method
+    public boolean isFocusable()
+    {
+        return false;
+    }
+
+    /**
+     * Mouse-click on this class view. Chek for double-click and handle.
+     */
+    public void mouseClicked(MouseEvent e)
+    {
+        if (e.getClickCount() > 1 && ((e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0)) {
+            doubleClick();
+        }
+    }
+
+    public void mouseEntered(MouseEvent e)
+    { }
+
+    public void mouseExited(MouseEvent e)
+    { }
+
+    /**
+     * The mouse was pressed on the component. Do what you have to do.
+     */
+    public void mousePressed(MouseEvent e)
+    {
+        select();
+        maybeShowPopup(e);
+    }
+
+    /**
+     * Selects the component after you've released the mouse.
+     *
+     * Copies the mousePressed behaviour, to handle Windows behaviour
+     * where a right-click is not considered a mousePressed event.
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+        select();
+        maybeShowPopup(e);
+    }
+
+    /**
+     *  Clears the UI for this ClassView
+     */
+    protected void clearUI()
+    {
+        this.removeAll();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassForest.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassForest.java
new file mode 100644
index 0000000000000000000000000000000000000000..891b61d1f31e212776f526f10f6d5299c5497623
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassForest.java
@@ -0,0 +1,254 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import greenfoot.util.GreenfootUtil;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * A forest of trees. The roots are sorted alphabetically on their keys
+ * 
+ * @author Poul Henriksen
+ * @version $Id: ClassForest.java 8232 2010-09-02 10:06:20Z nccb $
+ */
+public class ClassForest
+{
+    public static class TreeEntry
+        implements Comparable<TreeEntry>
+    {
+        private List<TreeEntry> children = new ArrayList<TreeEntry>();
+        private ClassView data;
+        private String key;
+
+        public TreeEntry(ClassView data, String key)
+        {
+            this.data = data;
+            this.key = key;
+        }
+
+        public void addChild(TreeEntry child)
+        {
+            if(this.equals(child)) {
+                throw new IllegalArgumentException(" Cannot add TreeEntry as a child of itself: " + this);
+            }
+            List<TreeEntry> childsChildren = child.getChildren();
+            for (TreeEntry treeEntry : childsChildren) {
+                if(this.equals(treeEntry)) {
+                    // found a cycle, just return and don't add it.
+                    // Should not be able to happen since it is checked in GClass
+                    System.err.println("ClassForest found Cycle between: " + key + " and " + child);
+                    return;
+                }
+            }
+            children.add(child);
+        }
+        
+        public void removeChildren()
+        {
+            children.clear();
+        }
+
+        public List<TreeEntry> getChildren()
+        {
+            return children;
+        }
+
+       
+        public String toString()
+        {
+            StringBuffer str = new StringBuffer();
+            for (Iterator<TreeEntry> iter = children.iterator(); iter.hasNext();) {
+                TreeEntry element = iter.next();
+                str.append(" " + element.toString());
+            }
+            return key + "(" + str + " )";
+        }
+
+        private String getKey()
+        {
+            return key;
+        }
+
+        public ClassView getData()
+        {
+            return data;
+        }
+
+        public int compareTo(TreeEntry o)
+        {
+            String name1 = this.getKey();
+            String name2 = o.getKey();
+            return name1.compareTo(name2);
+        }
+        
+        public boolean equals(Object o) 
+        {
+            if(o instanceof TreeEntry) {
+                TreeEntry other = (TreeEntry) o;                
+                return getKey().equals(other.getKey());
+            }
+            return false;
+        }
+        
+        public int hashCode() 
+        {
+            return getKey().hashCode();
+        }
+
+        public void rename(String newKey)
+        {
+            this.key = newKey;
+        }
+    }
+
+    private SortedSet<TreeEntry> roots = new TreeSet<TreeEntry>();
+    private Map<String, TreeEntry> treeEntryMap = new LinkedHashMap<String, TreeEntry>();
+    
+    public ClassForest()
+    { }
+
+    /**
+     * Get the root classes of this ClassForest (i.e. classes which have no
+     * parent classes).
+     */
+    public Set<TreeEntry> getRoots()
+    {
+        return roots;
+    }
+
+    public String toString()
+    {
+        StringBuffer str = new StringBuffer();
+        for (Iterator<TreeEntry> iter = roots.iterator(); iter.hasNext();) {
+            str.append(iter.next());
+        }
+        return str.toString();
+    }
+    
+    /**
+     * Add a new class to this forest. After adding classes, before
+     * the forest can be displayed, the rebuild() method must be called.
+     */
+    public synchronized void add(ClassView cls)
+    {
+        String name =  cls.getClassName();
+        TreeEntry entry = new TreeEntry(cls, name);
+        treeEntryMap.put(name, entry);
+    }
+
+	public void add(TreeEntry entry) {
+		treeEntryMap.put(entry.getKey(), entry);
+		List<TreeEntry> children = entry.getChildren();
+		for (TreeEntry treeEntry : children) {
+		    add(treeEntry);
+		}
+	}
+
+	/**
+	 * Remove a class from this forest, including all its children if it has
+	 * any. Returns the removed TreeEntry.
+	 */
+    public synchronized TreeEntry remove(ClassView cls)
+    {        
+        String name =  cls.getClassName();
+        TreeEntry removedEntry = treeEntryMap.remove(name);
+        if (removedEntry != null) {
+            // Make sure to update the key in the entry if it has changed.
+            String oldName = removedEntry.getKey();
+            if(oldName != name) {
+                removedEntry.rename(name);                
+            }
+			List<TreeEntry> children = removedEntry.getChildren();
+			for (TreeEntry child : children) {
+				remove(child.getData());	
+			}
+		}
+
+		return removedEntry;
+    }
+    
+    /**
+     * Rename a class in this forest
+     * @param cls      The existing class view (with new name)
+     * @param oldName  The original name
+     */
+    public synchronized void rename(ClassView cls, String oldName)
+    {
+        TreeEntry entry = treeEntryMap.remove(oldName);
+        if (entry != null) {
+            String newName = cls.getClassName();
+            entry.rename(newName);
+            treeEntryMap.put(newName, entry);
+        }
+    }
+
+    /**
+     * Rebuild the forest from the classes in the entry map.
+     * This method must be called after adding new elements.
+     */
+    public synchronized void rebuild() 
+    {
+        roots = new TreeSet<TreeEntry>();
+        Collection<TreeEntry> values = treeEntryMap.values();
+
+        for (Iterator<TreeEntry> iter = values.iterator(); iter.hasNext();) {
+            TreeEntry entry = iter.next();
+            entry.removeChildren();
+        }
+
+        for (Iterator<TreeEntry> iter = values.iterator(); iter.hasNext();) {
+            TreeEntry entry = iter.next();
+            addEntryToTree(entry.getData());
+        }
+    }
+    
+    
+    /**
+     * Add an entry from this forest properly into the tree structure.
+     */
+    private void addEntryToTree(ClassView clsView)
+    {
+        String superName = clsView.getSuperclass();
+        TreeEntry child = treeEntryMap.get(clsView.getClassName());
+        if(superName == null || superName.equals("")) {
+            roots.add(child);
+        } else {
+            superName = GreenfootUtil.extractClassName(superName);
+            TreeEntry parent = treeEntryMap.get(superName);
+            if(parent != null) {
+                parent.addChild(child);
+            } else {
+                //We couldn't find the superclass, so we just add it as a root
+                roots.add(child);
+            }             	
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassView.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassView.java
new file mode 100644
index 0000000000000000000000000000000000000000..4642410e30e7614ba5a75ad2f498d499101575e5
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/ClassView.java
@@ -0,0 +1,449 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import greenfoot.core.GClass;
+import greenfoot.core.GPackage;
+import greenfoot.core.GProject;
+import greenfoot.core.GreenfootMain;
+import greenfoot.core.Simulation;
+import greenfoot.core.WorldHandler;
+import greenfoot.event.ActorInstantiationListener;
+import greenfoot.gui.classbrowser.role.ActorClassRole;
+import greenfoot.gui.classbrowser.role.ClassRole;
+import greenfoot.gui.classbrowser.role.NormalClassRole;
+import greenfoot.gui.classbrowser.role.WorldClassRole;
+import greenfoot.gui.input.mouse.LocationTracker;
+import greenfoot.platforms.ide.GreenfootUtilDelegateIDE;
+import greenfoot.record.InteractionListener;
+
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.JPopupMenu;
+import javax.swing.JRootPane;
+
+import bluej.Config;
+import bluej.utility.DialogManager;
+
+/**
+ * A class visualisation.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class ClassView extends ClassButton
+    implements Selectable
+{
+    GClass gClass;
+    private ClassRole role;
+    ClassBrowser classBrowser;
+    JPopupMenu popupMenu;
+    private String superclass; //Holds the current superclass. Used to determine wether the superclass has changed.
+    private InteractionListener interactionListener;
+        
+    /**
+     * Creates a new ClassView with the role determined from gClass.
+     */
+    public ClassView(ClassBrowser classBrowser, GClass gClass, InteractionListener interactionListener)
+    {
+        this.classBrowser = classBrowser;
+        this.interactionListener = interactionListener;
+        init(gClass);
+    }    
+    
+    /**
+     * Check whether this class is a core class (can't be removed or have
+     * image set).
+     */
+    public boolean isCoreClass()
+    {
+        return gClass.isActorClass() || gClass.isWorldClass();
+    }
+    
+    /**
+     * Updates this ClassView to reflect a change in super class.
+     * 
+     * <p>Will also update the UI, but can be called from any thread.
+     */
+    public void updateSuperClass()
+    {
+        String superClassGuess = getSuperclass();
+        if (superClassGuess == null || superClassGuess.equals(superclass)) {
+            // If super class has not changed, we do not want to update
+            // anything.
+            return;
+        }
+        else {
+            superclass = getSuperclass();
+        }
+
+        if (classBrowser != null) {
+            // If we are in a classBrowser, tell it to update the location
+            // of this classview in the tree.
+            classBrowser.consolidateLayout(ClassView.this);
+        }
+    }
+
+    /**
+     * Determines the role of this class based on the backing GClass.
+     */
+    private ClassRole determineRole(GProject project)
+    {
+        ClassRole classRole = null;
+        if (gClass.isActorClass()) {
+            classRole = new ActorClassRole(project);
+        }
+        else if (gClass.isWorldClass()) {
+            classRole = new WorldClassRole(project);
+        }
+        else if (gClass.isActorSubclass()) {
+            classRole = new ActorClassRole(project);
+        }
+        else if (gClass.isWorldSubclass()) {
+            classRole = new WorldClassRole(project);
+        }
+        else {
+            // everything else
+            classRole = NormalClassRole.getInstance();
+        }
+        return classRole;
+    }
+
+    private void init(GClass gClass)
+    {
+        this.gClass = gClass;
+        gClass.setClassView(this);
+        
+        superclass = getSuperclass();
+        
+        initUI();
+        
+        update();
+    }
+
+        
+    /**
+     * Return the real Java class that this class view represents.
+     */
+    public Class<?> getRealClass()
+    {
+        return gClass.getJavaClass();
+    }
+
+    public GClass getGClass()
+    {
+        return gClass;
+    }
+
+    public JPopupMenu getPopupMenu()
+    {
+        if (popupMenu == null) {
+            popupMenu = role.createPopupMenu(classBrowser, this, interactionListener);
+            popupMenu.setInvoker(this);
+        }
+        return popupMenu;
+    }
+
+    /**
+     * Sets the role of this ClassLabel. Does not update UI.
+     * 
+     * @param role
+     */
+    private void setRole(ClassRole role)
+    {
+        WorldHandler.getInstance().removeWorldListener(this.role);
+        this.role = role;
+        WorldHandler.getInstance().addWorldListener(this.role);
+    }
+
+    /**
+     * Rebuild the UI of this ClassView from scratch.
+     */
+    private void update()
+    {
+        clearUI();
+        setRole(determineRole(classBrowser.getProject()));
+        role.buildUI(this, gClass);
+        
+        // Popup menu needs to be re-built
+        popupMenu = null;
+        
+        updateSuperClass();
+    }
+
+    /**
+     * Get the class role for this class view.  
+     */
+    public ClassRole getRole()
+    {
+        return role;
+    }
+
+    public String getQualifiedClassName()
+    {
+        return gClass.getQualifiedName();
+    }
+
+    /**
+     * Get the (non-qualified) name  of the class represented by this ClassView.
+     */
+    public String getClassName()
+    {
+        return gClass.getName();
+    }
+
+    /*
+     * @see greenfoot.gui.classbrowser.Selectable#select()
+     */
+    public void select()
+    {
+        this.setSelected(true);
+        fireSelectionChangeEvent();
+    }
+
+    /*
+     * @see greenfoot.gui.classbrowser.Selectable#deselect()
+     */
+    public boolean deselect()
+    {
+        if (isSelected()) {
+            setSelected(false);
+            fireSelectionChangeEvent();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Creates an instance of this class. The default constructor is used. This
+     * method is used for creating instances when clicking on the world.
+     */
+    public void createInstance()
+    {
+        Simulation.getInstance().runLater(new Runnable() {
+            @Override
+            public void run()
+            {
+                Class<?> realClass = getRealClass();
+                try {
+                    if (realClass == null) {
+                        return;
+                    }
+                    
+                    Constructor<?> constructor = realClass.getConstructor(new Class[]{});
+                    constructor.setAccessible(true);
+
+                    Object newObject = Simulation.newInstance(constructor);
+                    interactionListener.createdActor(newObject, new String[0], null);
+                    ActorInstantiationListener invocationListener = GreenfootMain.getInstance().getInvocationListener();
+                    if(invocationListener != null) {
+                        invocationListener.localObjectCreated(newObject, LocationTracker.instance().getMouseButtonEvent());
+                    }
+                    return;
+                }
+                catch (LinkageError le) {
+                    // This could be NoClassDefFound or similar. It really means the
+                    // class needs to be recompiled.
+                    le.printStackTrace();
+                }
+                catch (NoSuchMethodException e) {
+                    // This might happen if there is no default constructor
+                    // e.printStackTrace();
+                    // TODO prevent this by checking for the constructor beforehand (before
+                    // this method is called)
+                }
+                catch (IllegalArgumentException e) {
+                    // Shouldn't happen - we pass the correct arguments always
+                }
+                catch (InstantiationException e) {
+                    e.printStackTrace();
+                }
+                catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                }
+                catch (InvocationTargetException e) {
+                    Throwable cause = e.getCause();
+                    if (cause != null) {
+                        // Filter the stack trace. Take it from the first point
+                        // at which code from this class was being executed.
+                        StackTraceElement [] strace = cause.getStackTrace();
+                        for (int i = strace.length; i > 0; i--) {
+                            if (strace[i-1].getClassName().equals(realClass.getName())) {
+                                StackTraceElement [] newStrace = new StackTraceElement[i];
+                                System.arraycopy(strace, 0, newStrace, 0, i);
+                                cause.setStackTrace(newStrace);
+                                break;
+                            }
+                        }
+                        cause.printStackTrace();
+                    }
+                    else {
+                        e.printStackTrace();
+                    }
+                }
+
+                return;
+            }
+        });
+    }
+
+    public GClass createSubclass(String className)
+    {
+        try {
+            //get the default package which is the one containing the user
+            // code.
+            GProject proj = gClass.getPackage().getProject();
+            GPackage pkg = proj.getDefaultPackage();
+            //write the java file as this is required to exist
+            File dir = proj.getDir();
+            File newJavaFile = new File(dir, className + ".java");
+            String superClassName = getClassName();            
+            GreenfootUtilDelegateIDE.getInstance().createSkeleton(className, superClassName, newJavaFile,
+                    role.getTemplateFileName(), proj.getCharsetName());
+            
+            GClass newClass = pkg.newClass(className, false);
+            //We know what the superclass should be, so we set it.
+            newClass.setSuperclassGuess(this.getQualifiedClassName());
+            return newClass;
+        }
+        catch (IOException ioe) {
+            DialogManager.showErrorText(this,
+                    Config.getString("greenfoot.cannotCreateClass") +
+                    ": " + ioe.getLocalizedMessage());
+        }
+        return null;
+    }
+        
+    /**
+     * Removes this class.
+     * <br>
+     * Must be called from the event thread.
+     */
+    public void remove()
+    {
+        WorldHandler.getInstance().removeWorldListener(this.role);
+        role.remove();
+        classBrowser.removeClass(this);
+        gClass.remove();
+        gClass = null;
+    }
+
+    /**
+     * Get the super class for this class.
+     * 
+     */
+    public String getSuperclass()
+    {
+        return gClass.getSuperclassGuess();
+    }
+
+
+    protected void fireSelectionChangeEvent()
+    {
+        // Guaranteed to return a non-null array
+        Object[] listeners = listenerList.getListenerList();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length - 2; i >= 0; i -= 2) {
+            if (listeners[i] == SelectionListener.class) {
+                ((SelectionListener) listeners[i + 1]).selectionChange(this);
+            }
+        }
+    }
+
+    /**
+     * Add a changeListener to listen for changes.
+     * 
+     * @param l
+     *            Listener to add
+     */
+    public void addSelectionChangeListener(SelectionListener l)
+    {
+        listenerList.add(SelectionListener.class, l);
+    }
+
+    /**
+     * Remove a changeListener.
+     * 
+     * @param l
+     *            Listener to remove
+     */
+    public void removeSelectionChangeListener(SelectionListener l)
+    {
+        listenerList.remove(SelectionListener.class, l);
+    }
+
+
+    /**
+     * Notify the class view that the underlying class has changed name.
+     * @param oldName  The original name of the class
+     */
+    public void nameChanged(String oldName)
+    {
+        classBrowser.renameClass(this, oldName);
+        updateView();
+    }
+    
+    /**
+     * Rebuild the UI of this ClassView from scratch.
+     */
+    public void updateView()
+    {
+        update();
+
+        JRootPane rootPane = getRootPane();
+        if(rootPane != null) {
+            getRootPane().revalidate();
+        }
+    }
+
+    
+    protected boolean isValidClass()
+    {
+        return gClass != null;
+    }
+    
+    protected boolean isUncompiled()
+    {
+        return !gClass.isCompiled();
+    }
+    
+    protected void doubleClick()
+    {
+        gClass.edit();
+    }
+
+    protected void maybeShowPopup(MouseEvent e)
+    {
+        if (e.isPopupTrigger()) {
+            getPopupMenu().show(e.getComponent(), e.getX(), e.getY());
+        }
+    }
+
+    public void setPopupMenu(JPopupMenu popupMenu)
+    {
+        this.popupMenu = popupMenu;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/EmptySpace.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/EmptySpace.java
new file mode 100644
index 0000000000000000000000000000000000000000..b142263035b9868abef8274cfcbedd9760c0abcf
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/EmptySpace.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import java.awt.Graphics;
+
+/**
+ * Graphics for arrow drawing. Emprt space, same size as other arrow elements.
+ * 
+ * @author mik
+ * @version $Id: EmptySpace.java 8232 2010-09-02 10:06:20Z nccb $
+ */
+public class EmptySpace extends ArrowElement
+{
+    public void paintComponent(Graphics g)
+    {
+//        Dimension size = getSize();
+//        g.drawLine(0, 0, size.width, size.height);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/Selectable.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/Selectable.java
new file mode 100644
index 0000000000000000000000000000000000000000..ccf001712dd05062188fc31bc56a6c15248c7cfd
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/Selectable.java
@@ -0,0 +1,35 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+/**
+ * @author Poul Henriksen
+ * @version $Id: Selectable.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public interface Selectable
+{
+    public boolean isSelected();
+
+    public void select();
+
+    public boolean deselect();
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/SelectionListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/SelectionListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..67a32876398e91e9a3f7eae26d6a0ffec543a2a3
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/SelectionListener.java
@@ -0,0 +1,34 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import java.util.EventListener;
+
+/**
+ * @author Poul Henriksen
+ * @version $Id: SelectionListener.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public interface SelectionListener
+    extends EventListener
+{
+    public void selectionChange(Selectable source);
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/SelectionManager.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/SelectionManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..b44a549b77cd1804cb432643cab5c02a5be26cde
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/SelectionManager.java
@@ -0,0 +1,93 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser;
+
+import javax.swing.event.EventListenerList;
+
+/**
+ * The SelectionManager manages notification of selection changes from a group
+ * of selectable components to a list of listeners.
+ *
+ * At any time, there is (at most) one selected component, and when the selected 
+ * component changes, all listeners are notified.
+ *
+ * @author Poul Henriksen
+ * @version $Id: SelectionManager.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class SelectionManager
+    implements SelectionListener
+{
+    Selectable selected = null;
+    private EventListenerList listenerList = new EventListenerList();
+
+    public Object getSelected()
+    {
+        return selected;
+    }
+
+    protected void fireSelectionChangeEvent(Selectable selectable)
+    {
+        // Guaranteed to return a non-null array
+        Object[] listeners = listenerList.getListenerList();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length - 2; i >= 0; i -= 2) {
+            if (listeners[i] == SelectionListener.class) {
+                ((SelectionListener) listeners[i + 1]).selectionChange(selectable);
+            }
+        }
+    }
+
+    /**
+     * Add a changeListener to listen for changes in this LanguagePack.
+     * ChangeEvents are fired when the file is saved.
+     * 
+     * @param l
+     *            Listener to add
+     */
+    public void addSelectionChangeListener(SelectionListener l)
+    {
+        listenerList.add(SelectionListener.class, l);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see dk.sdu.mip.dit.ui.classbrowser.SelectionListener#selectionChange(dk.sdu.mip.dit.ui.classbrowser.Selectable)
+     */
+    public void selectionChange(Selectable source)
+    {
+        if (source == selected) {
+            if (! source.isSelected()) {
+                selected = null;
+                fireSelectionChangeEvent(selected);
+            }
+        }
+        else {
+            if (source.isSelected()) {
+                selected = source;
+                fireSelectionChangeEvent(selected);
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/ActorClassRole.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/ActorClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..efe69d8eef5962f0383a1008cdeb24e8d58e815a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/ActorClassRole.java
@@ -0,0 +1,121 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser.role;
+
+import greenfoot.actions.SelectImageAction;
+import greenfoot.actions.ShowApiDocAction;
+import greenfoot.core.GProject;
+import greenfoot.event.WorldEvent;
+import greenfoot.record.InteractionListener;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.Action;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+
+import bluej.Config;
+
+/**
+ * A role for Actor classes 
+ * 
+ * @author Poul Henriksen
+ */
+public class ActorClassRole extends ImageClassRole
+{
+    protected final Color envOpColour = new Color(152,32,32);
+
+    private String template = "actorclass.tmpl";
+
+    private static final String newline = System.getProperty("line.separator");
+    public static final String imports = "import greenfoot.*;  // (World, Actor, GreenfootImage, and Greenfoot)" + newline;
+    
+    private List<Action> constructorItems = new ArrayList<Action>();
+    private boolean enableConstructors = false;
+    
+    public ActorClassRole(GProject project)
+    {
+        super(project);
+    }
+    
+    /*
+     * Need to overide this method in order to delay the invocation of the
+     * constructor until the object is placed into the world.
+     */
+    @Override
+    public List<Action> createConstructorActions(Class<?> realClass, GProject project,
+            InteractionListener interactionListener)
+    {
+        List<Action> realActions = super.createConstructorActions(realClass, project, interactionListener);
+        constructorItems = new ArrayList<Action>();
+        for (Action realAction : realActions) {
+            Action tempAction = createDragProxyAction(realAction);
+            tempAction.setEnabled(enableConstructors);
+            constructorItems.add(tempAction);
+        }
+ 
+        return constructorItems;
+    }
+        
+    @Override
+    public void addPopupMenuItems(JPopupMenu menu, boolean coreClass)
+    {
+        if (!coreClass) {
+            menu.add(createMenuItem(new SelectImageAction(classView, this)));
+        }
+        else {
+            menu.add(createMenuItem(new ShowApiDocAction(Config.getString("show.apidoc"), "greenfoot/Actor.html")));
+        }
+    }
+
+    @Override
+    public String getTemplateFileName()
+    {
+        return template;
+    }
+
+    @Override
+    public void worldCreated(WorldEvent e) {
+        enableConstructors = true;
+        SwingUtilities.invokeLater(new Thread() {
+            public void run() {
+                for (Action action : constructorItems) {
+                    action.setEnabled(true);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void worldRemoved(WorldEvent e) {
+        enableConstructors = false;
+        SwingUtilities.invokeLater(new Thread() {
+            public void run() {
+                for (Action action : constructorItems) {
+                    action.setEnabled(false);
+                }
+            }
+        });
+    }   
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/ClassRole.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/ClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6acb9e2b975a29ac13cc372fd66e4c18c7bc439
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/ClassRole.java
@@ -0,0 +1,225 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser.role;
+
+import greenfoot.actions.EditClassAction;
+import greenfoot.actions.InspectClassAction;
+import greenfoot.actions.NewSubclassAction;
+import greenfoot.actions.RemoveClassAction;
+import greenfoot.core.GClass;
+import greenfoot.core.GProject;
+import greenfoot.core.GreenfootMain;
+import greenfoot.core.WorldHandler;
+import greenfoot.core.WorldInvokeListener;
+import greenfoot.event.WorldEvent;
+import greenfoot.event.WorldListener;
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.classbrowser.ClassBrowser;
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.localdebugger.LocalClass;
+import greenfoot.record.InteractionListener;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.Action;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import bluej.Config;
+import bluej.debugmgr.ConstructAction;
+import bluej.debugmgr.inspector.InspectorManager;
+import bluej.debugmgr.objectbench.ObjectBenchInterface;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.Debug;
+import bluej.views.ConstructorView;
+import bluej.views.MethodView;
+import bluej.views.View;
+import bluej.views.ViewFilter;
+
+
+/**
+ * A class role in Greenfoot. There are different roles for actors, worlds, and
+ * "normal" classes.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public abstract class ClassRole implements WorldListener
+{
+    protected final static Dimension iconSize = new Dimension(16, 16);
+    
+    private final Color envOpColour = new Color(152,32,32);
+    
+    /**
+     * Set the text and icon of a ClassView as appropriate for the given class
+     */
+    public abstract void buildUI(ClassView classView, GClass rClass);
+
+    /**
+     * Get the name for the template file used to create the initial source for a new class.
+     */
+    public abstract String getTemplateFileName();
+
+    /**
+     * Create a list of actions for invoking the constructors of the given class
+     */
+    public List<Action> createConstructorActions(Class<?> realClass, GProject project,
+            InteractionListener interactionListener)
+    {
+        View view = View.getView(realClass);
+        List<Action> actions = new ArrayList<Action>();
+        ConstructorView[] constructors = view.getConstructors();
+
+        for (int i = 0; i < constructors.length; i++) {
+            try {
+                ConstructorView m = constructors[constructors.length - i - 1];
+
+                ViewFilter filter = new ViewFilter(ViewFilter.INSTANCE | ViewFilter.PUBLIC);
+                if (!filter.accept(m))
+                    continue;
+
+                ObjectBenchInterface ob = WorldHandler.getInstance().getObjectBench();
+                GreenfootFrame frame = GreenfootMain.getInstance().getFrame();
+                InspectorManager inspectorManager = frame.getInspectorManager();
+                
+                WorldInvokeListener invocListener = new WorldInvokeListener(frame, realClass, ob,
+                        inspectorManager, interactionListener, project);
+
+                String prefix = "new ";
+                Action callAction = new ConstructAction(m, invocListener, prefix + m.getLongDesc());
+                actions.add(callAction);
+            }
+            catch (Exception e) {
+                Debug.reportError("Exception accessing methods: " + e);
+                e.printStackTrace();
+            }
+        }
+        return actions;
+    }
+    
+    /**
+     * Create the popup menu for the given class
+     */
+    public JPopupMenu createPopupMenu(ClassBrowser classBrowser, ClassView classView,
+            InteractionListener interactionListener)
+    {
+        GClass gClass = classView.getGClass();
+        JPopupMenu popupMenu = new JPopupMenu();
+        GProject project = null;
+        project = gClass.getPackage().getProject();
+
+        Class<?> realClass = gClass.getJavaClass();
+        if (realClass != null) {
+
+            // Constructors
+            if (!java.lang.reflect.Modifier.isAbstract(realClass.getModifiers())) {
+                List<Action> constructorItems = createConstructorActions(realClass, project, interactionListener);
+
+                boolean hasEntries = false;
+                for (Action callAction : constructorItems) {
+                    JMenuItem item = popupMenu.add(callAction);
+                    item.setFont(PrefMgr.getPopupMenuFont());
+                    hasEntries = true;
+                }
+
+                if (hasEntries) {
+                    popupMenu.addSeparator();
+                }
+            }
+
+            // Static methods
+            ViewFilter filter = new ViewFilter(ViewFilter.STATIC | ViewFilter.PUBLIC);
+            View view = View.getView(realClass);
+            MethodView[] allMethods = view.getAllMethods();
+
+            ObjectBenchInterface ob = WorldHandler.getInstance().getObjectBench();
+            GreenfootFrame frame = GreenfootMain.getInstance().getFrame();
+            InspectorManager inspectorManager = frame.getInspectorManager();
+            
+            WorldInvokeListener invocListener = new WorldInvokeListener(frame, realClass, ob,
+                    inspectorManager, interactionListener, project);
+            if (bluej.pkgmgr.target.role.ClassRole.createMenuItems(popupMenu, allMethods, filter, 0,
+                    allMethods.length, "", invocListener)) {
+                popupMenu.addSeparator();
+            }
+        }
+
+
+        if (!classView.isCoreClass()) {
+            
+            if (gClass.hasSourceCode()) {
+                popupMenu.add(createMenuItem(new EditClassAction(classBrowser)));
+            }
+
+            addPopupMenuItems(popupMenu, false);
+
+            if (classView.getRealClass() != null) {
+                popupMenu.add(createMenuItem(new InspectClassAction(new LocalClass(classView.getRealClass()), null,
+                        classBrowser.getFrame().getInspectorManager(), classBrowser.getFrame())));
+            }
+
+            popupMenu.add(createMenuItem(new RemoveClassAction(classView, classBrowser.getFrame())));
+        }
+        else {
+            addPopupMenuItems(popupMenu, true);
+        }
+        
+        popupMenu.addSeparator();
+        popupMenu.add(createMenuItem(new NewSubclassAction(classView, classBrowser, interactionListener)));
+
+        return popupMenu;
+    }
+    
+    protected JMenuItem createMenuItem(Action action)
+    {
+        JMenuItem item = new JMenuItem(action);
+        item.setFont(PrefMgr.getPopupMenuFont());
+        item.setForeground(envOpColour);
+        return item;
+    }
+    
+    /**
+     * Add any role-specific menu items to the given popup menu
+     * @param menu  The meny to add the menu items to
+     * @param coreClass  Whether the class is a "core" class (Actor, World) or not
+     */
+    public void addPopupMenuItems(JPopupMenu menu, boolean coreClass)
+    {
+        // default implementation does nothing
+    }
+
+    public void worldCreated(WorldEvent e) {
+        // Do nothing - only want to handle this for actors
+    }
+
+    public void worldRemoved(WorldEvent e) {
+        // Do nothing - only want to handle this for actors
+    }
+
+    /**
+     * Called when this role is being removed. Do any cleanup that is needed here.
+     */
+    public abstract void remove();
+    
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/ImageClassRole.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/ImageClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..a0d0db475d7d33b85182323ca953b5c66e8405c1
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/ImageClassRole.java
@@ -0,0 +1,177 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009, 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser.role;
+
+import greenfoot.GreenfootImage;
+import greenfoot.actions.DragProxyAction;
+import greenfoot.core.GClass;
+import greenfoot.core.GProject;
+import greenfoot.core.ObjectDragProxy;
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.Image;
+import java.util.Hashtable;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ImageIcon;
+
+
+/**
+ * Base class for class roles with associated images.
+ * 
+ * @author Davin McCall
+ */
+public abstract class ImageClassRole extends ClassRole
+{
+    protected GClass gClass;
+    protected ClassView classView;
+    protected GProject project;
+    private static Hashtable<GClass, ImageIcon> imageIcons = new Hashtable<GClass, ImageIcon>();
+    
+    public ImageClassRole(GProject project)
+    {
+    	this.project = project;
+    }
+    
+    @Override
+    public void buildUI(ClassView classView, GClass gClass)
+    {
+        this.gClass = gClass;
+        this.classView = classView;
+        classView.setText(gClass.getName());
+        changeImage();
+    }
+
+    @Override
+    public String getTemplateFileName()
+    {
+        // TODO Auto-generated method stub
+        return null;
+    }
+    
+    /**
+     * Gets the image for this simulation class if one is available
+     * 
+     * @return The image, or null if no image can be found
+     */
+    private static Image getImage(GClass gClass)
+    {
+        GreenfootImage gfImage = getGreenfootImage(gClass);
+        if (gfImage != null) {
+            return gfImage.getAwtImage();
+        }
+        else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns a class in the given class' class hierarchy that has an image set.
+     */
+    private static GClass getClassThatHasImage(GClass gclass) 
+    {
+        while (gclass != null) {
+            String className = gclass.getQualifiedName();
+            GreenfootImage gfImage = null;
+            GProject project = gclass.getPackage().getProject();
+            gfImage = project.getProjectProperties().getImage(className);
+            if (gfImage != null) {
+                break;
+            }
+            gclass = gclass.getSuperclass();
+        }
+        return gclass;
+    }
+    
+    protected static GreenfootImage getGreenfootImage(GClass gclass)
+    {
+        gclass = getClassThatHasImage(gclass);
+
+        if(gclass == null) {
+            return null;
+        }
+        
+        String className = gclass.getQualifiedName();
+        GProject project = gclass.getPackage().getProject();
+        return project.getProjectProperties().getImage(className);
+    }
+    
+    private ImageIcon getImageIcon() {
+        GClass gCls = getClassThatHasImage(gClass);
+        ImageIcon icon = imageIcons.get(gCls);
+        if (icon == null) {
+            Image image = getImage(gCls);
+            Image scaledImage = GreenfootUtil.getScaledImage(image, iconSize.width, iconSize.height);
+            icon = new ImageIcon(scaledImage);
+            imageIcons.put(gCls, icon);     
+        }
+        return icon;
+    }
+
+    public ObjectDragProxy createObjectDragProxy()
+    {
+        GreenfootImage greenfootImage = getGreenfootImage(gClass);
+        Action dropAction = new AbstractAction() {
+            public void actionPerformed(java.awt.event.ActionEvent arg0) {
+                classView.createInstance();
+            }
+        };
+        ObjectDragProxy object = new ObjectDragProxy(greenfootImage, dropAction);
+        return object;
+    }
+
+    protected Action createDragProxyAction(Action realAction)
+    {
+        GreenfootImage greenfootImage = getGreenfootImage(gClass);
+        return new DragProxyAction(greenfootImage, realAction);
+    }
+
+    /**
+     * Notification that a new image has been selected for this class.
+     */
+    public void changeImage()
+    {
+        project.getProjectProperties().removeCachedImage(classView.getClassName());             
+        Image image = getImage(gClass);
+        if (image != null) {
+            Image scaledImage = GreenfootUtil.getScaledImage(image,iconSize.width, iconSize.height);
+            ImageIcon icon = getImageIcon();
+            icon.setImage(scaledImage);
+            classView.setIcon(icon);
+        } 
+        else {
+            classView.setIcon(null);
+        }
+        //resets the pop up menu to ensure that a new one is created when next it is requested
+        //this is required because the constructor action images are out of date because of the
+        //image change
+        classView.setPopupMenu(null);
+    }
+
+    @Override    
+    public void remove() 
+    {
+        imageIcons.remove(gClass);        
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/NormalClassRole.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/NormalClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..51c595c91da7e8a09905de91e2198dd23ded37ea
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/NormalClassRole.java
@@ -0,0 +1,75 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser.role;
+
+import greenfoot.core.GClass;
+import greenfoot.gui.classbrowser.ClassView;
+
+/**
+ * Role for a "normal" (non-Actor, non-World) class.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: NormalClassRole.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class NormalClassRole extends ClassRole
+{
+    private static NormalClassRole instance;
+
+    private String template = "stdclass.tmpl";
+    
+    /**
+     * Get the (singleton) instance of NormalClassRole.
+     */
+    public static NormalClassRole getInstance()
+    {
+        if (instance == null) {
+            instance = new NormalClassRole();
+        }
+        
+        return instance;
+    }
+    
+    private NormalClassRole()
+    {
+        // Nothing to do.
+    }
+    
+    public void buildUI(ClassView classView, GClass gClass)
+    {
+        classView.setIcon(null);
+        classView.setText(gClass.getQualifiedName());
+    }
+
+    @Override
+    public String getTemplateFileName()
+    {
+        return template;
+    }
+
+    @Override
+    public void remove()
+    {
+       //do nothing
+    }
+
+    
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/WorldClassRole.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/WorldClassRole.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7001e32fbd3f4365b10cb4e86a7c41a95669ca1
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/classbrowser/role/WorldClassRole.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.classbrowser.role;
+
+import greenfoot.actions.SelectImageAction;
+import greenfoot.actions.ShowApiDocAction;
+import greenfoot.core.GProject;
+
+import javax.swing.JPopupMenu;
+
+import bluej.Config;
+
+/**
+ * A role for world classes.
+ * 
+ * @author Poul Henriksen
+ */
+public class WorldClassRole extends ImageClassRole
+{
+    private final static String template = "worldclass.tmpl";
+    
+    public WorldClassRole(GProject project)
+    {
+    	super(project);
+    }
+    
+    @Override
+    public String getTemplateFileName()
+    {
+        return template;
+    }
+    
+    @Override
+    public void addPopupMenuItems(JPopupMenu menu, boolean coreClass)
+    {
+        if (! coreClass) {
+            menu.add(createMenuItem(new SelectImageAction(classView, this)));
+        }
+        else {
+            menu.add(createMenuItem(new ShowApiDocAction(Config.getString("show.apidoc"), "greenfoot/World.html")));
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportAppPane.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportAppPane.java
new file mode 100644
index 0000000000000000000000000000000000000000..f86cd751af8fedeb68e68e6c1c26769faa4ef587
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportAppPane.java
@@ -0,0 +1,171 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.export;
+
+import greenfoot.util.FileChoosers;
+
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import javax.swing.JOptionPane;
+
+/**
+ * Export dialog pane for exporting to a standalone application.
+ * 
+ * @author Michael Kolling
+ */
+public class ExportAppPane extends ExportPane
+{
+    public static final String FUNCTION = "APP";
+    
+    private static final String helpLine1 = Config.getString("export.app.help");
+    private static final String exportLocationLabelText = Config.getString("export.app.location");
+    
+    private JTextField targetDirField;
+    
+    /** Creates a new instance of ExportAppPane */
+    public ExportAppPane(String scenarioName, File defaultExportDir) 
+    {
+        super();
+        File targetFile = new File(defaultExportDir, scenarioName + ".jar");
+        makePane(targetFile);
+    }
+    
+    /**
+     * Return the directory where the scenario should be exported.
+     */
+    public String getExportName()
+    {
+        return targetDirField.getText();
+    }
+    
+    /**
+     * Build the component.
+     */
+    private void makePane(final File targetFile)
+    {
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+        setBorder(BlueJTheme.dialogBorder);
+        setBackground(backgroundColor);
+
+
+        targetDirField = new JTextField(targetFile.toString(), 26);
+        targetDirField.setEditable(false);
+
+        JLabel helpText1 = new JLabel(helpLine1);
+        add(helpText1);
+
+        add(Box.createVerticalStrut(10));
+
+        JPanel inputPanel = new JPanel();
+        {
+            inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS));
+            inputPanel.setAlignmentX(LEFT_ALIGNMENT);
+            inputPanel.setBackground(backgroundColor);
+
+            inputPanel.add(Box.createVerticalStrut(5));
+
+            JPanel exportLocationPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+            {
+                exportLocationPanel.setBackground(backgroundColor);
+                JLabel exportLocationLabel = new JLabel(exportLocationLabelText);
+                exportLocationPanel.add(exportLocationLabel);
+
+                exportLocationPanel.add(targetDirField);
+
+                JButton browse = new JButton(Config.getString("export.app.browse"));
+                exportLocationPanel.add(browse);
+                browse.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent e) { getFileName(targetFile); }
+                });                    
+            }
+            exportLocationPanel.setAlignmentX(LEFT_ALIGNMENT);
+            inputPanel.add(exportLocationPanel);
+            inputPanel.add(Box.createVerticalStrut(5));
+
+            inputPanel.add(lockScenario);
+        }
+
+        add(inputPanel);
+    }
+    
+    /**
+     * Get a user-chosen file name via a file system browser.
+     * Set the pane's text field to the selected file.
+     */
+    private void getFileName(File targetFile)
+    {
+        File file = FileChoosers.getFileName(this, targetFile, Config.getString("export.app.choose"));
+        if(file != null) {
+            String newName = file.getPath();
+            if(!newName.endsWith(".jar")) {
+                if(! newName.toLowerCase().endsWith(".jar")) {
+                    newName += ".jar";
+                }
+                else {
+                    newName = newName.substring(0, newName.length()-".jar".length());
+                    newName += ".jar";
+                }
+            }
+            targetDirField.setText(newName);
+            if(file.exists()) {
+                String message = newName + " already exists. Overwrite?";
+                String title = "Warning";
+                int result = JOptionPane.showConfirmDialog(this, message, title, JOptionPane.YES_NO_OPTION);
+                if(result==JOptionPane.NO_OPTION) {
+                    getFileName(targetFile);
+                    return;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void activated()
+    {
+        // Nothing special to do here
+    }    
+    
+    @Override
+    public boolean prePublish()
+    {
+        // Nothing special to do here   
+        return true;
+    }
+    
+    @Override
+    public void postPublish(boolean success)
+    {
+        // Nothing special to do here       
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportCompileDialog.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportCompileDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..d24de98df2e3f222e49e84f777ae5ba5a674c875
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportCompileDialog.java
@@ -0,0 +1,188 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.export;
+
+import greenfoot.actions.CompileAllAction;
+import greenfoot.core.GProject;
+import greenfoot.event.CompileListener;
+import greenfoot.gui.*;
+
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.WindowConstants;
+
+import rmiextension.wrappers.event.RCompileEvent;
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+import java.awt.Dialog;
+import java.awt.Frame;
+
+/**
+ * Dialog to be used when the project is not compiled and an export is
+ * attempted. The dialog will ask the user to compile all classes. 
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class ExportCompileDialog extends EscapeDialog 
+        implements CompileListener
+{
+    private String helpLine = Config.getString("export.compile.help");
+    private boolean ok;
+    private GProject project;
+    
+    /**
+     * Creates a new dialog. This dialog should listen for compile events.
+     */
+    public ExportCompileDialog(Dialog parent, GProject project)
+    {
+        super(parent, Config.getString("export.compile.notCompiled"), true);
+        this.project = project;
+        makeDialog();
+    }
+    
+
+    /**
+     * Creates a new dialog. This dialog should listen for compile events.
+     */
+    public ExportCompileDialog(Frame parent, GProject project)
+    {
+        super(parent, Config.getString("export.compile.notCompiled"), true);
+        this.project = project;
+        makeDialog();
+    }
+    
+
+    /**
+     * Show this dialog and return true if everything was compiled, false otherwise.
+     */
+    public boolean display()
+    {
+        ok = false;
+        setVisible(true);  // returns after Compiled All or Cancel, which set 'ok'
+        return ok;
+    }
+    
+    /**
+     * Create the dialog interface.
+     */
+    private void makeDialog()
+    {
+        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+
+        JPanel mainPanel = new JPanel();
+        {
+            mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+            mainPanel.setBorder(BlueJTheme.dialogBorder);
+
+            WrappingMultiLineLabel helpText = new WrappingMultiLineLabel(helpLine, 60);
+            mainPanel.add(helpText);
+
+
+            mainPanel.add(Box.createVerticalStrut(BlueJTheme.dialogCommandButtonsVertical));
+
+
+            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+            {
+                buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                JButton compileButton = new JButton(new CompileAllAction(project));
+
+                JButton cancelButton = BlueJTheme.getCancelButton();
+                cancelButton.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent evt) { doCancel(); }                
+                });
+
+                buttonPanel.add(compileButton);
+                buttonPanel.add(cancelButton);
+
+                getRootPane().setDefaultButton(compileButton);
+            }
+
+            mainPanel.add(buttonPanel);
+        }
+
+        getContentPane().add(mainPanel);
+        pack();
+
+        DialogManager.centreDialog(this);
+    }
+    
+
+    /**
+     * Close action when Cancel is pressed.
+     */
+    private void doCancel()
+    {
+        ok = false;
+        dispose();
+    }
+    
+    
+    /**
+     * Close action when everything is compiled.
+     */
+    private void doOk()
+    {
+        ok = true;
+        dispose();        
+    }
+    
+    @Override
+    public void compileError(RCompileEvent event)
+    {
+    }
+    
+    @Override
+    public void compileFailed(RCompileEvent event)
+    {
+        doCancel();
+    }
+
+    @Override
+    public void compileStarted(RCompileEvent event)
+    {
+
+    }
+
+    @Override
+    public void compileSucceeded(RCompileEvent event)
+    {
+        if(project.isCompiled()) {
+            doOk();
+        }
+    }
+    
+    @Override
+    public void compileWarning(RCompileEvent event)
+    {
+        
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportDialog.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d4a293a11d4a3e17bfcc4efd106c3b9d4790a25
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportDialog.java
@@ -0,0 +1,494 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.export;
+
+import greenfoot.core.GClass;
+import greenfoot.core.GProject;
+import greenfoot.core.WorldHandler;
+import greenfoot.export.Exporter;
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.MessageDialog;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.SwingUtilities;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+import bluej.utility.Utility;
+
+/**
+ * A dialog allowing the user to export a scenario in a variety of ways.
+ */
+public class ExportDialog extends EscapeDialog
+        implements TabbedIconPaneListener
+{
+    // Internationalisation
+    private static final String dialogTitle = Config.getApplicationName() + ": "
+        + Config.getString("export.dialog.title");
+
+    private static final String noWorldDialogTitle = Config.getString("export.noworld.dialog.title");
+    private static final String noWorldDialogMsg = Config.getString("export.noworld.dialog.msg");
+    private static final String noZeroArgConsTitle = Config.getString("export.noconstructor.dialog.title");
+    private static final String noZeroArgConsMsg = Config.getString("export.noconstructor.dialog.msg");
+    
+    private Frame parent;
+    private GProject project;
+    private JPanel contentPane;
+    private final JProgressBar progressBar = new JProgressBar();
+    private final JLabel progressLabel = new JLabel();
+    private JButton continueButton;
+    private JButton closeButton;
+    private HashMap<String, ExportPane> panes;
+    private ExportPane selectedPane;
+    private String selectedFunction;
+    private int progress;
+    /** Has the dialog been made visible previously? */
+    private boolean haveBeenVisible;
+
+    private TabbedIconPane tabbedPane;
+
+    public ExportDialog(GreenfootFrame parent)
+    {
+        super(parent, dialogTitle, false);
+        this.parent = parent;
+        
+        project = parent.getProject();
+        
+        File projectDir = project.getDir();
+        
+        createPanes(project, projectDir.getParentFile());
+        makeDialog();
+    }
+
+    /**
+     * Show this dialog.
+     */
+    public void display()
+    {
+        if (!project.isCompiled())  {
+            boolean isCompiled = showCompileDialog(project);
+            if(!isCompiled) {               
+                return;         // Cancel export
+            }
+        }
+        String lastWorldClassName = project.getLastWorldClassName();
+        GClass lastWorldClass = lastWorldClassName == null ? null
+                : project.getDefaultPackage().getClass(lastWorldClassName);
+        if (lastWorldClass == null) {
+            JButton[] buttons = new JButton[]{new JButton(Config.getString("greenfoot.continue"))};
+            MessageDialog errorDialog = new MessageDialog(parent, noWorldDialogMsg, noWorldDialogTitle, 50 , buttons);
+            errorDialog.display();
+            return;
+        }
+
+        // Check that a zero-argument constructor is available
+        boolean haveNoArgConstructor = false;
+        try {
+            Class<?> realClass = lastWorldClass.getJavaClass();
+            Constructor<?> [] cons = realClass.getConstructors();
+            for (Constructor<?> con : cons) {
+                if (con.getParameterTypes().length == 0) {
+                    haveNoArgConstructor = true;
+                    break;
+                }
+            }
+        }
+        catch (LinkageError le) {}
+        
+        if (! haveNoArgConstructor) {
+            JButton[] buttons = new JButton[]{new JButton(Config.getString("greenfoot.continue"))};
+            MessageDialog errorDialog = new MessageDialog(parent, noZeroArgConsMsg, noZeroArgConsTitle, 50 , buttons);
+            errorDialog.display();
+            return;
+        }
+        
+        final ExportPublishPane publishPane = (ExportPublishPane) panes.get(ExportPublishPane.FUNCTION);
+        
+        BufferedImage snapShot = WorldHandler.getInstance().getSnapShot();
+        if(snapShot != null) {
+            publishPane.setImage(snapShot);
+        }        
+        clearStatus();
+        
+        if (selectedPane == null) {
+            String preferredPane = Config.getPropString("greenfoot.lastExportPane", ExportPublishPane.FUNCTION);
+            showPane(preferredPane, false);
+        }
+        
+        if (! haveBeenVisible) {
+            pack();
+            DialogManager.centreDialog(this);
+            haveBeenVisible = true;
+        }
+
+        setVisible(true);  // returns after OK or Cancel, which set 'ok'
+    }
+
+    /**
+     * Display or hide the progress bar and status text. If 'showProgress' is 
+     * true, an indeterminate progress bar is shown, otherwise hidden. 
+     * If 'text' is null, the text is hidden, otherwise shown.
+     *
+     * setProgress can be invoked from a worker thread.
+     */
+    public void setProgress(final boolean showProgress, final String text)
+    {
+        SwingUtilities.invokeLater(new Runnable() { public void run() { 
+            progressBar.setVisible(showProgress);
+            if (! showProgress) {
+                progressBar.setIndeterminate(true);
+            }
+            if(text == null) {
+                progressLabel.setVisible(false);
+            }
+            else {
+                progressLabel.setText(text);
+                progressLabel.setVisible(true);
+            }
+        }});
+    }
+
+    /**
+     * Set the text for the export/share button.
+     */
+    public void setExportButtonText(String s)
+    {
+        continueButton.setText(s);
+    }
+    
+    /**
+     * Close action when OK is pressed.
+     */
+    private void doOK()
+    {
+        if(!project.isCompiled()) {
+            boolean isCompiled = showCompileDialog(project);
+            if(!isCompiled) {               
+                return;  // Cancel export
+            }
+        }
+        doExport();
+    }
+
+    /**
+     * Close action when Cancel is pressed.
+     */
+    private void doClose()
+    {
+        setVisible(false);
+    }
+
+    /**
+     * The export button was pressed. Do the exporting now.
+     */
+    private void doExport()
+    {
+        if(selectedPane.prePublish()) {
+            ExportThread expThread = new ExportThread();
+            enableButtons(false);
+            expThread.start();
+        }
+    }
+    /**
+     * A separate thread to execute the actual exporting.
+     */
+    class ExportThread extends Thread {
+        public void run() 
+        {
+            try {
+                String function = getSelectedFunction();
+                ExportPane pane = getSelectedPane();
+
+                Exporter exporter = Exporter.getInstance();
+
+                if(function.equals(ExportPublishPane.FUNCTION)) {
+                    exporter.publishToWebServer(project, (ExportPublishPane)pane, ExportDialog.this);
+                }
+                if(function.equals(ExportWebPagePane.FUNCTION)) {
+                    exporter.makeWebPage(project, (ExportWebPagePane)pane, ExportDialog.this);
+                }
+                if(function.equals(ExportAppPane.FUNCTION)) {
+                    exporter.makeApplication(project, (ExportAppPane)pane, ExportDialog.this);
+                }
+            }
+            finally {
+                SwingUtilities.invokeLater(new Runnable() {
+                    public void run()
+                    {
+                        enableButtons(true);
+                    }
+                });
+            }
+        }
+    }
+
+    /**
+     * Clear the status text, but only if we are not in the middle of a task.
+     */
+    private void clearStatus()
+    {
+        if(!progressBar.isVisible()) {
+            progressLabel.setVisible(false);
+        }
+    }
+    
+    /**
+     * Return the identifier for the specific export function selected.
+     */
+    private String getSelectedFunction()
+    {
+        return selectedFunction;
+    }
+
+    /**
+     * Return the identifier for the specific export function selected.
+     */
+    private ExportPane getSelectedPane()
+    {
+        return selectedPane;
+    }
+    
+    /**
+     * Enable or disable the dialogue buttons.
+     */
+    private void enableButtons(boolean enable)
+    {
+        continueButton.setEnabled(enable);
+        closeButton.setEnabled(enable);
+    }
+    
+    // === TabbedIconPaneListener interface ===
+    
+    /** 
+     * Called when the selection of the tabs changes.
+     */
+    public void tabSelected(String function)
+    {
+        showPane(function, true);
+    }
+
+    // === end of TabbedIconListener interface ===
+
+    /** 
+     * Called when the selection of the tabs changes.
+     */
+    private void showPane(String function, boolean saveAsDefault)
+    {
+        ExportPane chosenPane = panes.get(function);
+        if(chosenPane != selectedPane) {
+            if(selectedPane != null) {
+                contentPane.remove(selectedPane);
+            }
+            continueButton.setText(Config.getString("export.dialog.export"));
+            chosenPane.activated();
+            contentPane.add(chosenPane, BorderLayout.CENTER);
+            selectedPane = chosenPane;
+            selectedFunction = function;
+            clearStatus();
+            pack();
+            if (saveAsDefault) {
+                Config.putPropString("greenfoot.lastExportPane", function);
+            }
+        }
+    }
+    
+    /**
+     * Create all the panes that should appear as part of this dialogue.
+     */
+    private void createPanes(GProject project, File defaultExportDir)
+    {
+        panes = new HashMap<String, ExportPane>();
+        panes.put(ExportPublishPane.FUNCTION, new ExportPublishPane(project, this));
+        panes.put(ExportWebPagePane.FUNCTION, new ExportWebPagePane(project.getName(), defaultExportDir));
+        panes.put(ExportAppPane.FUNCTION, new ExportAppPane(project.getName(), defaultExportDir));
+        
+        fixSizes(panes);
+        
+    }
+
+    /**
+     * Create the dialog interface.
+     * @param defaultExportDir The default place to export to.
+     */
+    private void makeDialog()
+    {
+        String preferredPane = Config.getPropString("greenfoot.lastExportPane",
+                                                    ExportPublishPane.FUNCTION);
+
+        contentPane = (JPanel) getContentPane();
+        
+        contentPane.setLayout(new BorderLayout());
+        contentPane.setBorder(null);
+        contentPane.setBackground(new Color(220, 220, 220));
+        
+        tabbedPane = new TabbedIconPane(preferredPane);
+        tabbedPane.setListener(this);
+        contentPane.add(tabbedPane, BorderLayout.NORTH);
+
+        JPanel bottomPanel = new JPanel(new BorderLayout(12, 12));
+        {
+            bottomPanel.setBorder(BlueJTheme.dialogBorder);
+            //bottomPanel.setBackground(backgroundColor);
+
+            progressBar.setIndeterminate(true);
+            progressBar.setVisible(false);
+            Dimension size = progressBar.getPreferredSize();
+            size.width = 100;
+            progressBar.setPreferredSize(size);
+            bottomPanel.add(progressBar, BorderLayout.WEST);
+            
+            progressLabel.setVisible(false);
+            bottomPanel.add(progressLabel, BorderLayout.CENTER);
+            
+            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+            {
+                //buttonPanel.setBackground(backgroundColor);
+                buttonPanel.setAlignmentX(LEFT_ALIGNMENT);
+
+                continueButton = new JButton(Config.getString("export.dialog.continue"));
+                continueButton.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent evt) { doOK(); }                
+                });
+
+                closeButton = BlueJTheme.getCloseButton();
+                closeButton.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent evt) { doClose(); }                
+                });
+
+                if (Config.isMacOS()) {
+                    buttonPanel.add(closeButton);
+                    buttonPanel.add(continueButton);
+                }
+                else {
+                    buttonPanel.add(continueButton);
+                    buttonPanel.add(closeButton);
+                }
+
+                getRootPane().setDefaultButton(continueButton);
+            }
+            bottomPanel.add(buttonPanel, BorderLayout.EAST);
+        }
+
+        contentPane.add(bottomPanel, BorderLayout.SOUTH);
+        
+        DialogManager.centreDialog(this);
+    }
+
+    /**
+     * Set the preferred width for all tabs to the widest of the tabs.
+     */
+    private void fixSizes(HashMap<String, ExportPane> panes) 
+    {
+        int maxWidth = 0;
+        
+        for(ExportPane pane : panes.values()) {
+            Dimension size = pane.getPreferredSize();
+            maxWidth = Math.max(size.width, maxWidth);
+        }
+        
+        for(ExportPane pane : panes.values()) {
+            Dimension size = pane.getPreferredSize();
+            size.width = maxWidth;
+            pane.setPreferredSize(size);
+        }
+    }
+
+    /**
+     * Inform the user that some classes aren't compiled, and give the option to compile them.
+     */
+    private boolean showCompileDialog(GProject project)
+    {
+        ExportCompileDialog dlg; 
+        if(this.isVisible()) {
+           dlg = new ExportCompileDialog(this, project);
+        }
+        else {
+            dlg = new ExportCompileDialog(parent, project);
+        }
+        
+        project.addCompileListener(dlg);
+        boolean compiled = dlg.display();
+        project.removeCompileListener(dlg);
+        
+        return compiled;
+    }
+
+    /**
+     * Tell this dialog that the publish (to the Gallery) has finished and whether it was successful.
+     */
+    public void publishFinished(boolean success, String msg)
+    {
+        selectedPane.postPublish(success);
+        setProgress(false, msg);
+        if (success) {
+            Utility.openWebBrowser(Config.getPropString("greenfoot.gameserver.address") + "/home");
+        }
+    }
+    
+    /**
+     * We now know the upload size.
+     */
+    public void gotUploadSize(int bytes)
+    {
+        progressBar.setMinimum(0);
+        progressBar.setMaximum(bytes);
+        progressBar.setValue(0);
+        progress = 0;
+        progressBar.setIndeterminate(false);
+    }
+    
+    /**
+     * The upload is progressing, a certain number of bytes were just transmitted.
+     * @param bytes  The number of bytes just transmitted
+     */
+    public void progressMade(int bytes)
+    {
+        progress += bytes;
+        progressBar.setValue(progress);
+    }
+
+    /**
+     * Selects the pane with the gallery export
+     */
+    public void selectGalleryPane()
+    {
+        tabbedPane.select(ExportPublishPane.FUNCTION);
+        showPane(ExportPublishPane.FUNCTION, false);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportPane.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportPane.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f6fa099f53d65c8d1b9fc80f166fd21c9db5b9b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportPane.java
@@ -0,0 +1,87 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+
+package greenfoot.gui.export;
+
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+
+import bluej.Config;
+import java.awt.Color;
+
+/**
+ * ExportPane is a superclass for all changing panes that can appear 
+ * in the Export dialogue.
+ *
+ * @author Michael Kolling
+ */
+public abstract class ExportPane extends JPanel
+{
+    private static final String lockText = Config.getString("export.lock.label");
+    private static final String lockDescription = Config.getString("export.lock.description");
+    protected static final Color backgroundColor = new Color(220, 220, 220);
+
+    protected JCheckBox lockScenario;
+
+    /**
+     * Create a an export pane for export to web pages.
+     */
+    public ExportPane()
+    {
+        lockScenario = new JCheckBox(lockText, false);
+        lockScenario.setSelected(true);
+        lockScenario.setAlignmentX(LEFT_ALIGNMENT);
+        lockScenario.setToolTipText(lockDescription);
+        lockScenario.setOpaque(false);
+    }
+
+    /**
+     * This method will be called when this pane is activated (about to be
+     * shown/visible)
+     */
+    public abstract void activated();
+    
+    /**
+     * This method will be called when the user is about to export the scenario
+     * with information from this pane. Will be called from the swing event
+     * thread and will not publish until this method returns.
+     * 
+     * @return Whether to continue publishing. Continues if true, cancels if false.
+     */
+    public abstract boolean prePublish();  
+    
+    /**
+     * This method will be called when the scenario has been published with the
+     * information from this pane.
+     * 
+     * @param success Whether the publish was successfull
+     */
+    public abstract void postPublish(boolean success);
+
+    /**
+     * Return true if the user wants to lock the scenario.
+     */
+    public boolean lockScenario()
+    {
+        return lockScenario.isSelected();
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportPublishPane.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportPublishPane.java
new file mode 100644
index 0000000000000000000000000000000000000000..3dc08329d63a6870229f83b1d595cea672d2ded7
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportPublishPane.java
@@ -0,0 +1,895 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.export;
+
+import greenfoot.core.GProject;
+import greenfoot.export.mygame.ExistingScenarioChecker;
+import greenfoot.export.mygame.MyGameClient;
+import greenfoot.export.mygame.ScenarioInfo;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.InputVerifier;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.border.Border;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.apache.commons.httpclient.ConnectTimeoutException;
+
+import bluej.Config;
+import bluej.utility.Debug;
+import bluej.utility.MiksGridLayout;
+import bluej.utility.SwingWorker;
+
+/**
+ * Pane used for exporting to Greenfoot Gallery
+ * 
+ * @author Michael Kolling
+ * @author Poul Henriksen
+ */
+public class ExportPublishPane extends ExportPane implements ChangeListener
+{
+    public static final int IMAGE_WIDTH = 120;
+    public static final int IMAGE_HEIGHT = 70;
+
+    public static final String FUNCTION = "PUBLISH";
+    private static final Color background = new Color(166, 188, 202);
+    private static final Color headingColor = new Color(40, 75, 125);
+    private static final String serverURL = ensureTrailingSlash(Config.getPropString("greenfoot.gameserver.address",
+            "http://www.greenfoot.org/"));
+    private static final String createAccountUrl = Config.getPropString("greenfoot.gameserver.createAccount.address",
+            "http://www.greenfoot.org/users/new");
+    private static final String serverName = Config.getPropString("greenfoot.gameserver.name", "Greenfoot Gallery");
+
+    private static final String helpLine1 = Config.getString("export.publish.help") + " " + serverName;
+    private static final String WITH_SOURCE_TAG = "with-source";
+
+    private JComponent leftPanel;
+    private JPanel titleAndDescPanel;
+    private JPanel infoPanel;
+    private JTextField titleField;
+    private JTextField shortDescriptionField;
+    private JTextArea descriptionArea;
+    private JTextArea updateArea;
+    private JTextField urlField;
+    private JTextField userNameField;
+    private JPasswordField passwordField;
+    private ImageEditPanel imagePanel;
+    private JCheckBox includeSource;
+    private JCheckBox keepScenarioScreenshot;
+
+    private SwingWorker commonTagsLoader;
+    private JCheckBox[] popTags = new JCheckBox[7];
+    private JTextArea tagArea;
+    private GProject project;
+    private boolean firstActivation = true;
+
+    private ScenarioInfo publishedScenarioInfo;
+    private String publishedUserName;
+
+    private ExistingScenarioChecker scenarioChecker;
+    private Font font;
+    private boolean isUpdate = false;
+    private ExportDialog exportDialog;
+
+    /** Creates a new instance of ExportPublishPane */
+    public ExportPublishPane(GProject project, ExportDialog exportDialog)
+    {
+        super();
+        this.project = project;
+        this.exportDialog = exportDialog;
+        makePane();
+    }
+
+    /**
+     * Get the image that is to be used as icon for this scenario.
+     * 
+     * @return The image, or null if it couldn't be created.
+     */
+    public BufferedImage getImage()
+    {
+        return imagePanel.getImage();
+    }
+
+    /**
+     * Set the screenshot image.
+     */
+    public void setImage(BufferedImage snapShot)
+    {
+        imagePanel.setImage(snapShot);
+        imagePanel.repaint();
+    }
+
+    /**
+     * Get the scenario title, specified in the title field.
+     */
+    public String getTitle()
+    {
+        if (titleField!=null)
+        {
+            return titleField.getText();
+        }
+        return null;
+    }
+
+    /**
+     * Return the short description string.
+     */
+    public String getShortDescription()
+    {
+        return shortDescriptionField.getText();
+    }
+
+    /**
+     * Return the description string.
+     */
+    public String getDescription()
+    {
+        return descriptionArea.getText();
+    }
+
+    /**
+     * Return the URL.
+     */
+    public String getURL()
+    {
+        return urlField.getText();
+    }
+
+    /**
+     * Return the user name.
+     */
+    public String getUserName()
+    {
+        return userNameField.getText();
+    }
+    
+    /**
+     * Return the changes to update string (if applicable)
+     */
+    public String getUpdateDescription()
+    {
+        if (updateArea!=null){
+            return updateArea.getText();
+        }
+        return null;
+    }
+
+    /**
+     * Return the password.
+     */
+    public String getPassword()
+    {
+        return new String(passwordField.getPassword());
+    }
+
+    /**
+     * True if the source code should be included.
+     */
+    public boolean includeSourceCode()
+    {
+        return includeSource.isSelected();
+    }
+
+    private void setHasSource(boolean hasSource)
+    {
+        includeSource.setSelected(hasSource);
+    }
+    
+    /**
+     * True if the screenshot should *not* be overwritten; false if it should
+     */
+    public boolean keepSavedScenarioScreenshot()
+    {
+        if (isUpdate && keepScenarioScreenshot != null) {
+            return keepScenarioScreenshot.isSelected();
+        }
+        return false;
+    }
+
+    private void setLocked(boolean locked)
+    {
+        lockScenario.setSelected(locked);
+    }
+
+    private void setTags(List<String> tags)
+    {
+        StringBuilder newTags = new StringBuilder();
+        boolean isFirstNewTag = true;;
+        for (Iterator<String> iterator = tags.iterator(); iterator.hasNext();) {
+            String tag = iterator.next();
+            if(WITH_SOURCE_TAG.equals(tag)) {
+                // we never want the with-source tag to show up.
+                continue;
+            }
+            boolean isPopTag = false;
+            for (int i = 0; i < popTags.length; i++) {
+                JCheckBox popTag = popTags[i];
+                if (popTag.getText().equals(tag)) {
+                    popTag.setSelected(true);
+                    isPopTag = true;
+                    break;
+                }
+            }
+            if (!isPopTag) {
+                if (!isFirstNewTag) {
+                    // Only insert newline if it is not the first new tag
+                    newTags.append(System.getProperty("line.separator"));
+                }
+                isFirstNewTag = false;
+                newTags.append(tag);
+            }
+        }
+        tagArea.setText(newTags.toString());
+    }
+
+    private void setUrl(String url)
+    {
+        urlField.setText(url);
+    }
+
+    private void setLongDescription(String longDescription)
+    {
+        descriptionArea.setText(longDescription);
+    }
+
+    private void setShortDescripton(String shortDescription)
+    {
+        shortDescriptionField.setText(shortDescription);
+    }
+
+    private void setTitle(String title)
+    {
+        titleField.setText(title);
+    }
+
+    private void setUserName(String name)
+    {
+        userNameField.setText(name);
+    }
+
+    /**
+     * Build the component.
+     */
+    private void makePane()
+    {
+        font = (new JLabel()).getFont().deriveFont(Font.ITALIC, 11.0f);
+        
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+        setBorder(BorderFactory.createEmptyBorder(12, 12, 0, 12));
+        setBackground(backgroundColor);
+       
+        add(getHelpBox());
+        add(Box.createVerticalStrut(12));
+
+        infoPanel = new JPanel(new BorderLayout(22, 18));
+        {
+            infoPanel.setAlignmentX(LEFT_ALIGNMENT);
+            infoPanel.setBackground(background);
+
+            Border border = BorderFactory.createCompoundBorder(BorderFactory.createLoweredBevelBorder(), BorderFactory
+                    .createEmptyBorder(12, 22, 12, 22));
+            infoPanel.setBorder(border);
+
+            JLabel text = new JLabel(Config.getString("export.publish.info") + " " + serverName, SwingConstants.CENTER);
+            text.setForeground(headingColor);
+            infoPanel.add(text, BorderLayout.NORTH);
+
+            createScenarioDisplay();
+            infoPanel.add(leftPanel, BorderLayout.CENTER);            
+            infoPanel.add(getTagDisplay(), BorderLayout.EAST);
+        }
+
+        add(infoPanel);
+        add(Box.createVerticalStrut(16));       
+        add(getLoginPanel());
+        add(Box.createVerticalStrut(10));
+    }
+    
+    /**
+     * Creates a login panel with a username and password and a create account option
+     * @return Login panel Component
+     */
+    private JComponent getLoginPanel()
+    {
+        JComponent loginPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 8, 4));
+
+        loginPanel.setBackground(background);
+        loginPanel.setAlignmentX(LEFT_ALIGNMENT);
+        Border border = BorderFactory.createCompoundBorder(BorderFactory.createLoweredBevelBorder(),
+                BorderFactory.createEmptyBorder(12, 12, 12, 12));
+        loginPanel.setBorder(border);
+
+        JLabel text = new JLabel(Config.getString("export.publish.login"));
+        text.setForeground(headingColor);
+        text.setVerticalAlignment(SwingConstants.TOP);
+        loginPanel.add(text);
+
+        text = new JLabel(Config.getString("export.publish.username"), SwingConstants.TRAILING);
+        text.setFont(font);
+        loginPanel.add(text);
+        userNameField = new JTextField(10);
+        userNameField.setInputVerifier(new InputVerifier() {
+            @Override
+            public boolean verify(JComponent input)
+            {
+                String text = userNameField.getText();
+                return text.length() > 0;
+            }
+        });
+        userNameField.addFocusListener(new FocusAdapter() {
+            @Override
+            public void focusLost(FocusEvent e)
+            {
+                checkForExistingScenario();
+            }
+        });
+        loginPanel.add(userNameField);
+        text = new JLabel(Config.getString("export.publish.password"), SwingConstants.TRAILING);
+        text.setFont(font);
+        loginPanel.add(text);
+        passwordField = new JPasswordField(10);
+        loginPanel.add(passwordField);
+
+        JLabel createAccountLabel = new JLabel(Config.getString("export.publish.createAccount"));
+        {
+            createAccountLabel.setBackground(background);
+
+            createAccountLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+            GreenfootUtil.makeLink(createAccountLabel, createAccountUrl);
+        }
+        loginPanel.add(createAccountLabel);
+        return loginPanel;
+    }
+    
+    /**
+     * Build a help box with a link to appropriate help
+     * @return help box
+     */
+    private Box getHelpBox()
+    {
+        Box helpBox = new Box(BoxLayout.X_AXIS);
+        helpBox.setAlignmentX(LEFT_ALIGNMENT);
+        JLabel helpText1 = new JLabel(helpLine1 + " (");
+        helpBox.add(helpText1);
+        JLabel serverLink = new JLabel(serverURL);
+        GreenfootUtil.makeLink(serverLink, serverURL);
+        helpBox.add(serverLink);
+        helpBox.add(new JLabel(")"));
+        return helpBox;
+    }
+
+    /**
+     * Set the tags in the UI from the given list (null if the server couldn't be contacted or
+     * didn't respond as expected).
+     * 
+     * <p>Should be called from event thread
+     */
+    private void setPopularTags(List<String> tags)
+    {
+        if (tags == null) {
+            // Couldn't get the tags list.
+            popTags[0].setText("Unavailable");
+            for (int i = 1; i < popTags.length; i++) {
+                popTags[i].setText("");
+            }
+            return;
+        }
+        
+        int minLength = popTags.length < tags.size() ? popTags.length : tags.size();
+        for (int i = 0; i < minLength; i++) {
+            JCheckBox checkBox = popTags[i];
+            checkBox.setText(tags.get(i));
+            checkBox.setEnabled(true);
+            setTags(getTags());
+        }
+        
+        // Clear any remaining checkboxes.
+        for (int i = minLength; i < popTags.length; i++) {
+            popTags[i].setText("");
+        }
+    }
+
+    /**
+     * Returns a list of the tags that the user chose for this scenario.
+     */
+    public List<String> getTags()
+    {
+        List<String> tagList = new LinkedList<String>();
+
+        for (int i = 0; i < popTags.length; i++) {
+            JCheckBox checkBox = popTags[i];
+            if (checkBox.isSelected()) {
+                tagList.add(checkBox.getText());
+            }
+        }
+
+        String currentTags = tagArea.getText().trim();
+        String[] tags = currentTags.split("\\s");
+        for (int i = 0; i < tags.length; i++) {
+            String tag = tags[i].trim();
+            if (!tag.equals("")) {
+                tagList.add(tag);
+            }
+        }
+        
+        if(includeSourceCode() && !tagList.contains(WITH_SOURCE_TAG)) {
+            tagList.add(WITH_SOURCE_TAG);
+        } else if (!includeSourceCode()){
+            tagList.remove(WITH_SOURCE_TAG);
+        }
+        return tagList;
+    }
+
+    /**
+     * Attempts to load details already stored for this scenario at previous
+     * publish.
+     * 
+     * Must be called from the event thread.
+     */
+    private void loadStoredScenarioInfo()
+    {
+        ScenarioInfo info = new ScenarioInfo();
+        if (info.load(project.getProjectProperties())) {
+            setTitle(info.getTitle());
+            setShortDescripton(info.getShortDescription());
+            setLongDescription(info.getLongDescription());
+            setUrl(info.getUrl());
+            setTags(info.getTags());
+            setLocked(info.isLocked());
+            setHasSource(info.getHasSource());
+            setUpdate(true);
+        }
+    }
+
+    /**
+     * Update the display according to whether this is an update of an existing scenario,
+     * or an upload of a new scenario.
+     */
+    private void updateScenarioDisplay()
+    {
+        removeLeftPanel();
+        createScenarioDisplay();
+        infoPanel.add(leftPanel, BorderLayout.CENTER);
+        boolean enableImageControl = !isUpdate || !keepScenarioScreenshot.isSelected();
+        imagePanel.enableImageEditPanel(enableImageControl);
+        revalidate();
+    }
+
+    /**
+     * Updates the given scenarioInfo with the current values typed into the
+     * dialog.
+     */
+    private void updateInfoFromFields(ScenarioInfo scenarioInfo)
+    {
+        scenarioInfo.setTitle(getTitle());
+        scenarioInfo.setShortDescription(getShortDescription());
+        scenarioInfo.setLongDescription(getDescription());
+        scenarioInfo.setUrl(getURL());
+        scenarioInfo.setTags(getTags());
+        scenarioInfo.setLocked(lockScenario());
+        scenarioInfo.setHasSource(includeSourceCode());
+        scenarioInfo.setUpdateDescription(getUpdateDescription());
+    }
+
+    private void checkForExistingScenario()
+    {
+        String userName = getUserName();
+        String title = getTitle();
+
+        // First check if everything is ready and bail out if it is not.
+        if (userName == null || userName.equals("")) {
+            return;
+        }
+        if (title == null || title.equals("")) {
+            return;
+        }
+
+        if (scenarioChecker == null) {
+            scenarioChecker = new ExistingScenarioChecker() {
+
+                @Override
+                public void scenarioExistenceCheckFailed(Exception reason)
+                {
+                    // Don't do anything. Failure could be due to proxy requiring authentication,
+                    // or network disconnection.
+                }
+
+                @Override
+                public void scenarioExistenceChecked(ScenarioInfo info)
+                {
+                    if (info != null) {
+                        setUpdate(true);
+                    }
+                    else {
+                        setUpdate(false);
+                    }
+                }
+            };
+        }
+        scenarioChecker.startScenarioExistenceCheck(serverURL, userName, title);
+    }
+
+    /**
+     * The first time this pane is activated we fetch the popular tags from the
+     * server (if possible).
+     * 
+     * <p>And we load previously used values if they are stored.
+     */
+    @Override
+    public void activated()
+    {
+        if (firstActivation) {
+            firstActivation = false;
+            
+            setUserName(Config.getPropString("publish.username", ""));
+            loadStoredScenarioInfo();
+            checkForExistingScenario();
+            
+            commonTagsLoader = new SwingWorker() {
+                @SuppressWarnings("unchecked")
+                @Override
+                public void finished()
+                {
+                    List<String> l = (List<String>) getValue();
+                    setPopularTags(l);
+                }
+
+                @Override
+                public Object construct()
+                {
+                    MyGameClient client = new MyGameClient(null);
+                    List<String> tags = null;
+                    try {
+                        String hostAddress = serverURL;
+                        if (!hostAddress.endsWith("/")) {
+                            hostAddress += "/";
+                        }
+                        // We add one to the number, because WITH_SOURCE is
+                        // likely to be among them and we then will filter it
+                        // out.
+                        tags = client.getCommonTags(hostAddress, popTags.length + 1);
+                        if(tags.contains(WITH_SOURCE_TAG)) {
+                            tags.remove(WITH_SOURCE_TAG);
+                        } else {
+                            if (! tags.isEmpty()) {
+                                tags.remove(tags.size() - 1);
+                            }
+                        }
+                    }
+                    catch (ConnectTimeoutException ctoe) { }
+                    catch (UnknownHostException e) {
+                        Debug.reportError("Error while publishing scenario", e);
+                    }
+                    catch (IOException e) {
+                        Debug.reportError("Error while publishing scenario", e);
+                    }
+                    return tags;
+                }
+            };
+            commonTagsLoader.start();
+        }
+        
+        String updateText;
+        if (isUpdate) {
+            updateText = Config.getString("export.dialog.update") ;
+        }
+        else {
+            updateText = Config.getString("export.dialog.share");
+        }
+         
+        exportDialog.setExportButtonText(updateText);
+    }
+
+    @Override
+    public boolean prePublish()
+    {
+        publishedScenarioInfo = new ScenarioInfo();
+        updateInfoFromFields(publishedScenarioInfo);
+        publishedUserName = userNameField.getText();
+        return true;
+    }
+
+    @Override
+    public void postPublish(boolean success)
+    {
+        if (success) {
+            publishedScenarioInfo.store(project.getProjectProperties());
+            Config.putPropString("publish.username", publishedUserName);
+            setUpdate(true);
+        }
+    }
+    
+    /**
+     * Make sure a host name ends with a slash.
+     */
+    public static String ensureTrailingSlash(String hostname)
+    {
+        if (hostname.endsWith("/")) {
+            return hostname;
+        }
+        else {
+            return hostname + "/";
+        }
+    }
+    
+    /**
+     * Creates the scenario information display including information such as title, description, url.
+     * For an update (isUpdate = true), the displayed options are slightly different.
+     */
+    private void createScenarioDisplay()
+    {
+        leftPanel = new Box(BoxLayout.Y_AXIS);
+        JLabel text;
+        MiksGridLayout titleAndDescLayout = new MiksGridLayout(6, 2, 8, 8);
+        titleAndDescLayout.setVerticallyExpandingRow(3);
+
+        titleAndDescPanel = new JPanel(titleAndDescLayout);
+        titleAndDescPanel.setBackground(background);
+
+        if (imagePanel == null) {
+            imagePanel = new ImageEditPanel(IMAGE_WIDTH, IMAGE_HEIGHT);
+            imagePanel.setBackground(background);
+        }
+
+        Box textPanel = new Box(BoxLayout.Y_AXIS);
+        {
+            text = new JLabel(Config.getString("export.publish.image1"));
+            text.setAlignmentX(Component.RIGHT_ALIGNMENT);
+            text.setFont(font);
+            textPanel.add(text);
+            text = new JLabel(Config.getString("export.publish.image2"));
+            text.setAlignmentX(Component.RIGHT_ALIGNMENT);
+            text.setFont(font);
+            textPanel.add(text);
+        }
+        titleAndDescPanel.add(textPanel);
+        titleAndDescPanel.add(imagePanel);
+        
+        if (isUpdate) {
+            text = new JLabel(Config.getString("export.snapshot.label"), SwingConstants.TRAILING);
+            text.setFont(font);
+            titleAndDescPanel.add(text);
+            
+            keepScenarioScreenshot = new JCheckBox();
+            keepScenarioScreenshot.setSelected(true);
+            // "keep screenshot" defaults to true, therefore the image panel should be disabled
+            imagePanel.enableImageEditPanel(false);
+            keepScenarioScreenshot.setName(Config.getString("export.publish.keepScenario"));
+            keepScenarioScreenshot.setOpaque(false);
+            keepScenarioScreenshot.addChangeListener(this);
+            titleAndDescPanel.add(keepScenarioScreenshot);  
+        }
+
+        text = new JLabel(Config.getString("export.publish.title"), SwingConstants.TRAILING);
+        text.setFont(font);
+        titleAndDescPanel.add(text);
+        
+        String title = project.getName();
+        if (getTitle() != null) {
+           title = getTitle();
+        }
+        titleField = new JTextField(title);
+        titleField.setInputVerifier(new InputVerifier() {
+            @Override
+            public boolean verify(JComponent input)
+            {
+                String text = titleField.getText();
+                return text.length() > 0;
+            }
+        });
+        titleField.addFocusListener(new FocusAdapter() {
+            @Override
+            public void focusLost(FocusEvent e)
+            {
+                checkForExistingScenario();
+            }
+        });
+        titleAndDescPanel.add(titleField);
+        
+        // If there is an update a "changes" description area is shown.
+        // If not there a short description and long description area are shown.
+        if (isUpdate) {
+            JLabel updateLabel = new JLabel(Config.getString("export.publish.update"), SwingConstants.TRAILING);
+            updateLabel.setVerticalAlignment(SwingConstants.TOP);
+            updateLabel.setFont(font);
+         
+            updateArea = new JTextArea();
+            updateArea.setRows(6);
+            updateArea.setLineWrap(true);
+            updateArea.setWrapStyleWord(true);
+            JScrollPane updatePane = new JScrollPane(updateArea);
+            
+            titleAndDescPanel.add(updateLabel);
+            titleAndDescPanel.add(updatePane);
+            titleAndDescLayout.setVerticallyExpandingRow(4);
+        }
+        else {
+            text = new JLabel(Config.getString("export.publish.shortDescription"), SwingConstants.TRAILING);
+            text.setFont(font);
+            shortDescriptionField = new JTextField();
+            titleAndDescPanel.add(text);
+            titleAndDescPanel.add(shortDescriptionField);
+            text = new JLabel(Config.getString("export.publish.longDescription"), SwingConstants.TRAILING);
+            text.setVerticalAlignment(SwingConstants.TOP);
+            text.setFont(font);
+            
+            descriptionArea = new JTextArea();
+            descriptionArea.setRows(6);
+            descriptionArea.setLineWrap(true);
+            descriptionArea.setWrapStyleWord(true);
+            JScrollPane description = new JScrollPane(descriptionArea);
+            titleAndDescPanel.add(text);
+            titleAndDescPanel.add(description);
+        }
+
+        text = new JLabel(Config.getString("export.publish.url"), SwingConstants.TRAILING);
+        text.setFont(font);
+        titleAndDescPanel.add(text);
+
+        urlField = new JTextField();
+        titleAndDescPanel.add(urlField);
+
+        leftPanel.add(titleAndDescPanel, BorderLayout.SOUTH);
+        
+        JComponent sourceAndLockPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 8, 0));
+        {
+            sourceAndLockPanel.setBackground(background);
+            includeSource = new JCheckBox(Config.getString("export.publish.includeSource"));
+            includeSource.setOpaque(false);
+            includeSource.setSelected(false);
+            includeSource.setFont(font);
+            sourceAndLockPanel.add(includeSource);
+            lockScenario.setFont(font);
+            sourceAndLockPanel.add(lockScenario);
+            sourceAndLockPanel.setMaximumSize(sourceAndLockPanel.getPreferredSize());
+        }
+
+        leftPanel.add(sourceAndLockPanel, BorderLayout.SOUTH);
+    }
+    
+    /**
+     * Removes the scenario information display
+     */
+    private void removeLeftPanel()
+    {
+        leftPanel.removeAll();
+        infoPanel.remove(leftPanel);
+    }
+    
+    /**
+     * Creates the tag display with popular tags and an option to add tags
+     */
+    private JComponent getTagDisplay ()
+    {
+        JComponent tagPanel = new JPanel(new MiksGridLayout(3, 1, 8, 8));
+        {
+            tagPanel.setBackground(background);
+            JComponent popPanel = new JPanel(new MiksGridLayout(8, 1, 8, 0));
+            popPanel.setBackground(background);
+            JLabel popLabel = new JLabel(Config.getString("export.publish.tags.popular"), SwingConstants.LEADING);
+            popLabel.setFont(font);
+            popPanel.add(popLabel);
+            for (int i = 0; i < popTags.length; i++) {
+                JCheckBox popTag = new JCheckBox(Config.getString("export.publish.tags.loading"));
+                popTag.setBackground(background);
+                popTag.setFont(font);
+                popTag.setEnabled(false);
+                popTags[i] = popTag;
+                popPanel.add(popTag);
+            }
+
+            tagPanel.add(popPanel);
+
+            Box textPanel = new Box(BoxLayout.Y_AXIS);
+            {
+                JLabel additionalLabel = new JLabel(Config.getString("export.publish.tags.additional1"),
+                        SwingConstants.LEADING);
+                additionalLabel.setFont(font);
+                textPanel.add(additionalLabel);
+
+                JLabel additionalLabel2 = new JLabel(Config.getString("export.publish.tags.additional2"),
+                        SwingConstants.CENTER);
+                additionalLabel2.setFont(font);
+                textPanel.add(additionalLabel2);
+            }
+            tagPanel.add(textPanel);
+
+            tagArea = new JTextArea();
+            tagArea.setRows(3);
+            JScrollPane tagScroller = new JScrollPane(tagArea);
+            tagPanel.add(tagScroller);
+        }
+        return tagPanel;
+    }
+
+    /**
+     * Of interest is the state of the keep scenario checkbox as that
+     * determines whether the image panel is enabled or disabled
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+        if (e.getSource().equals(keepScenarioScreenshot)){
+            if (keepScenarioScreenshot.isSelected())
+            {
+                imagePanel.enableImageEditPanel(false);
+            }
+            else {
+                imagePanel.enableImageEditPanel(true);
+            }
+        }
+        
+    }
+
+    /**
+     * Returns true if it is an update and false if it is a first export
+     */
+    public boolean isUpdate()
+    {
+        return isUpdate;
+    }
+
+    /**
+     * Specify whether this scenario will be updated, or is a new export.
+     */
+    private void setUpdate(boolean isUpdate)
+    {
+        if (this.isUpdate != isUpdate) {
+            this.isUpdate = isUpdate;
+            if (isUpdate) {
+                String updateText = Config.getString("export.dialog.update");
+                exportDialog.setExportButtonText(updateText);
+            }
+            else {
+                String exportText = Config.getString("export.dialog.share");
+                exportDialog.setExportButtonText(exportText);
+            }
+            updateScenarioDisplay();
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportWebPagePane.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportWebPagePane.java
new file mode 100644
index 0000000000000000000000000000000000000000..158278f19e8d9bdccb1d1a2d1e196a4fcbb8831d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ExportWebPagePane.java
@@ -0,0 +1,154 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+/*
+ * ExportWebPagePane.java
+ *
+ * @author Michael Kolling
+ * @version $Id: ExportWebPagePane.java 8919 2011-05-05 05:12:13Z davmac $
+ */
+
+package greenfoot.gui.export;
+
+import greenfoot.util.FileChoosers;
+
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+
+public class ExportWebPagePane extends ExportPane
+{
+    public static final String FUNCTION = "WEB";
+    
+    private static final String helpLine1 = Config.getString("export.web.help");
+    private static final String exportLocationLabelText = Config.getString("export.web.exportLocation");
+
+    private JTextField targetDirField;
+
+    /** 
+     * Create a an export pane for export to web pages.
+     */
+    public ExportWebPagePane(String scenarioName, File defaultExportDir) 
+    {
+        super();
+        File exportDir = new File(defaultExportDir, scenarioName + "-export");
+
+        if (exportDir.exists()) {
+            exportDir.delete();
+        }
+        
+        makePane(exportDir);
+    }
+    
+    /**
+     * Return the directory where the scenario should be exported.
+     */
+    public String getExportLocation()
+    {
+        return targetDirField.getText();
+    }
+
+    /**
+     * Build the component.
+     */
+    private void makePane(final File defaultDir)
+    {
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+        setBorder(BlueJTheme.dialogBorder);
+        setBackground(backgroundColor);
+
+        targetDirField = new JTextField(defaultDir.toString(), 24);
+        targetDirField.setEditable(false);
+
+        JLabel helpText1 = new JLabel(helpLine1);
+        add(helpText1);
+
+        add(Box.createVerticalStrut(10));
+
+        JPanel inputPanel = new JPanel();
+        {
+            inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS));
+            inputPanel.setAlignmentX(LEFT_ALIGNMENT);
+            inputPanel.setBackground(backgroundColor);
+
+            inputPanel.add(Box.createVerticalStrut(5));
+
+            JPanel exportLocationPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+            {
+                exportLocationPanel.setBackground(backgroundColor);
+                JLabel exportLocationLabel = new JLabel(exportLocationLabelText);
+                exportLocationPanel.add(exportLocationLabel);
+
+                exportLocationPanel.add(targetDirField);
+
+                JButton browse = new JButton(Config.getString("export.web.browse"));
+                exportLocationPanel.add(browse);
+                browse.addActionListener(new ActionListener() {
+                    public void actionPerformed(ActionEvent e)
+                    {
+                        File file = FileChoosers.getFileName(ExportWebPagePane.this, defaultDir,
+                                                              Config.getString("export.web.choose"));
+                        if(file != null) {
+                            targetDirField.setText(file.getPath());
+                        }
+                    }
+                });                    
+            }
+            exportLocationPanel.setAlignmentX(LEFT_ALIGNMENT);
+            inputPanel.add(exportLocationPanel);
+            inputPanel.add(Box.createVerticalStrut(4));
+
+            inputPanel.add(lockScenario);
+        }
+
+        add(inputPanel);
+    }
+
+    @Override
+    public void activated()
+    {
+        // Nothing special to do here        
+    }   
+    
+    @Override
+    public boolean prePublish()
+    {
+        // Nothing special to do here   
+        return true;
+    }
+    
+    @Override
+    public void postPublish(boolean success)
+    {
+        // Nothing special to do here       
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ImageEditCanvas.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ImageEditCanvas.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a7ee96bd55393e17f945b1a9d922ed53cabd7e6
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ImageEditCanvas.java
@@ -0,0 +1,206 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.export;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+
+import javax.swing.JPanel;
+
+/**
+ * Component that shows an image and supplies methods for scaling and cropping the view.
+ * 
+ * @author Poul Henriksen
+ */
+public class ImageEditCanvas extends JPanel
+{
+    /** Original image */
+    private BufferedImage image;
+
+    /** Size of this component as specified by client */
+    private Dimension size;
+
+    /** Location in the original image that should be in the center of the view */
+    private double x;
+    /** Location in the original image that should be in the center of the view */
+    private double y;
+    /** Current factor to scale image with */
+    private double scaleFactor = 1;
+    /** Minimum scale factor */
+    private double minScaleFactor;
+    /**
+     * Threshold for which to snap to initial position (only if scale factor is
+     * the initial size)
+     */
+    int snapThreshold = 7;
+
+    /**
+     * Create a new image canvas.
+     * 
+     * @param width
+     *            Width of this component.
+     * @param height
+     *            Height of this component.
+     * @param image
+     *            The image to manipulate.
+     */
+    public ImageEditCanvas(int width, int height, java.awt.image.BufferedImage image)
+    {
+        this.size = new Dimension(width, height);
+        setOpaque(false);
+        setImage(image);
+    }
+
+    /**
+     * Set the distance form which snapping should start. Only used when the
+     * image is scaled to the same size as the desired size.
+     * 
+     */
+    public void setSnapThreshold(int threshold)
+    {
+        this.snapThreshold = threshold;
+    }
+
+    /**
+     * Set the image that should be shown on this canvas.
+     */
+    public void setImage(java.awt.image.BufferedImage image)
+    {
+        this.image = image;
+        if (image != null) {
+            double minScaleFactorX = size.getWidth() / (double) image.getWidth();
+            double minScaleFactorY = size.getHeight() / (double) image.getHeight();
+            minScaleFactor = minScaleFactorX < minScaleFactorY ? minScaleFactorX : minScaleFactorY;
+            if (minScaleFactor > 1) {
+                minScaleFactor = 1;
+            }
+        }
+    }
+
+    public void paintComponent(Graphics g)
+    {
+        super.paintComponent(g);
+        paintImage(g);
+    }
+
+    /**
+     * Paints the image with the current scale and offset.
+     */
+    public void paintImage(Graphics g)
+    {
+        if (image != null) {
+            Graphics2D g2 = (Graphics2D) g;
+            AffineTransform oldTx = g2.getTransform();
+
+            // Snap if size fits
+            double xSnapped = x;
+            double ySnapped = y; 
+            if (Math.abs(scaleFactor - minScaleFactor) < .0000001) {
+                double xs = (image.getWidth() / 2 + xSnapped) * scaleFactor;
+                double ys = (image.getHeight() / 2 + ySnapped) * scaleFactor;
+                if (Math.abs(xs) < snapThreshold && Math.abs(ys) < snapThreshold) {
+                    xSnapped = -image.getWidth() / 2;
+                    ySnapped = -image.getHeight() / 2;
+                }
+            }
+
+            // Scale around center of canvas
+            g2.translate(size.width / 2, size.height / 2);
+            g2.scale(scaleFactor, scaleFactor);
+            g2.translate(xSnapped, ySnapped);
+
+            g2.drawImage(image, 0, 0, null);
+            g2.setTransform(oldTx);
+        }
+    }
+
+    /**
+     * Scale and move the image so that it fits within the size of the canvas.
+     */
+    public void fit()
+    {
+        x = (int) (-image.getWidth() / 2.) ;
+        y = (int) (-image.getHeight() / 2.) ;
+      
+        setScale(minScaleFactor);
+    }
+
+    /**
+     * Move the image.
+     */
+    public void move(int dx, int dy)
+    {
+        // Divide by scaleFactor since we want the location in the original
+        // image.
+        x += dx / scaleFactor;
+        y += dy / scaleFactor;
+        repaint();
+    }
+
+    /**
+     * Return the current scale factor.
+     */
+    public double getScale()
+    {
+        return scaleFactor;
+    }
+
+    /**
+     * Set the current scale factor. Will not allow the image to become
+     * smaller than the component.
+     * 
+     * @param scaleFactor
+     *            1 is real size of the image
+     */
+    public void setScale(double scaleFactor)
+    {
+        this.scaleFactor = scaleFactor;
+        if (scaleFactor < minScaleFactor) {
+            this.scaleFactor = minScaleFactor;
+        }
+        repaint();
+    }
+
+    /**
+     * Returns the minimum scaling that will be allowed. The minimum scaling is
+     * usually set so that the scaled size of the image is not smaller than the
+     * canvas size.
+     * 
+     */
+    public double getMinimumScale()
+    {
+        return minScaleFactor;
+    }
+
+    public Dimension getMaximumSize()
+    {
+        return size;
+    }
+
+    public Dimension getPreferredSize()
+    {
+        return size;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ImageEditPanel.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ImageEditPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..dfe4da35149cd5d4ebd60b4a2ffac2526920381f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ImageEditPanel.java
@@ -0,0 +1,275 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009, 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.export;
+
+import greenfoot.util.GraphicsUtilities;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * Panel that lets you manipulate an image by zooming (with slider or
+ * mouse wheel) and moving (by dragging with the mouse).
+ * 
+ * @author Poul Henriksen
+ */
+public class ImageEditPanel extends JPanel
+    implements MouseMotionListener, MouseListener, MouseWheelListener
+{
+    /** Canvas for the image we are controlling. */
+    private ImageEditCanvas imageCanvas;
+    /** Last position where mouse was dragged. */
+    private int lastX;
+    /** Last position where mouse was dragged. */
+    private int lastY;
+
+    /** Slider for zooming*/
+    private JSlider zoomSlider;
+
+    /** Width of the image view */
+    private int width;
+    /** Height of the image view */
+    private int height;
+    
+    /** Label used for the slider. */
+    private JLabel bigLabel;
+    /** Label used for the slider. */
+    private JLabel smallLabel;
+    
+    /** Whether to enable dragging / zooming, when we have an image */
+    private boolean enableImageControls = true;
+    /** Whether we actually have an image in the edit canvas */
+    private boolean haveImage;
+    
+    /**
+     * Construct a new image edit panel for an image with the specified height and width.
+     */
+    public ImageEditPanel(int width, int height)
+    {
+        this.width = width;
+        this.height = height;
+        setPreferredSize(new Dimension(width + 2, height + 2));
+        buildUI();
+    }
+    
+    /**
+     * Set the image to be manipulated.
+     */
+    public void setImage(BufferedImage snapShot)
+    {
+        double oldMinScale = imageCanvas.getMinimumScale();
+        imageCanvas.setImage(snapShot); 
+        double newMinScale = imageCanvas.getMinimumScale();            
+        if(!haveImage || Math.abs(newMinScale - oldMinScale) > .0000001 ) {
+            // Only re-fit scaling if there was a change in size.
+            imageCanvas.fit();
+            adjustSlider();    
+        } 
+        if (!haveImage) {
+            haveImage = true;
+            enableImageEditPanel(enableImageControls);
+        }
+    }
+    
+    /**
+     * Compose the user interface components.
+     */
+    private void buildUI()
+    {
+        setOpaque(false);
+        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+        imageCanvas = new ImageEditCanvas(width, height, null);
+        imageCanvas.addMouseMotionListener(this);
+        imageCanvas.addMouseListener(this);
+        imageCanvas.addMouseWheelListener(this);
+        imageCanvas.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+      
+        zoomSlider = new JSlider(JSlider.VERTICAL);
+        zoomSlider.setOpaque(false);
+        
+        // Create labels for slider
+        try {
+            URL url = new File(GreenfootUtil.getGreenfootLogoPath()).toURI().toURL();
+            BufferedImage iconImage = GraphicsUtilities.loadCompatibleImage(url);
+            bigLabel = new JLabel(new ImageIcon(iconImage.getScaledInstance(-1, 15, Image.SCALE_DEFAULT)));
+            smallLabel = new JLabel(new ImageIcon(iconImage.getScaledInstance(-1, 10, Image.SCALE_DEFAULT)));
+            zoomSlider.setPaintLabels(true);
+        }
+        catch (MalformedURLException e1) {
+            e1.printStackTrace();
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+        
+        adjustSlider();
+        
+        Dimension maxSize = zoomSlider.getMaximumSize();
+        maxSize.height = imageCanvas.getMaximumSize().height;
+        zoomSlider.setMaximumSize(maxSize);
+        
+        zoomSlider.addChangeListener(new ChangeListener() {
+            public void stateChanged(ChangeEvent e)
+            {
+                JSlider source = (JSlider) e.getSource();
+                int scale = source.getValue();
+                imageCanvas.setScale(scale / 100.);
+            }
+        });
+        // Panel that contains the border so that borders are not drawn on our
+        // canvas, but just outside it.
+        Box border = new Box(BoxLayout.LINE_AXIS);
+        border.setBorder(BorderFactory.createLineBorder(Color.BLACK));
+        border.add(imageCanvas);
+        
+        add(Box.createHorizontalGlue());
+        add(border);
+        add(zoomSlider);
+        add(Box.createHorizontalGlue());
+
+    }
+
+    private void adjustSlider()
+    {
+        int min = (int) (imageCanvas.getMinimumScale() * 100);
+        int max = 100;
+        int scale = (int) (imageCanvas.getScale() * 100);
+        zoomSlider.setMinimum(min);
+        zoomSlider.setMaximum(max);        
+        zoomSlider.setValue(scale);
+        Dictionary<Integer, JLabel> labels = new Hashtable<Integer, JLabel>();
+        labels.put(zoomSlider.getMinimum(), smallLabel);
+        labels.put(zoomSlider.getMaximum(), bigLabel);
+        zoomSlider.setLabelTable(labels);
+        zoomSlider.repaint();
+    }
+
+    public void mouseDragged(MouseEvent e)
+    {
+        if (!imageCanvas.isEnabled()){
+            return;
+        }
+        if ( (e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) != 0) {
+            imageCanvas.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+            int dx = e.getX() - lastX;
+            int dy = e.getY() - lastY;
+            imageCanvas.move(dx, dy);
+            lastX = e.getX();
+            lastY = e.getY();
+        }
+    }
+
+    public void mouseMoved(MouseEvent e)
+    {}
+
+    public void mouseClicked(MouseEvent e)
+    {}
+
+    public void mouseEntered(MouseEvent e)
+    {}
+
+    public void mouseExited(MouseEvent e)
+    {}
+
+    public void mousePressed(MouseEvent e)
+    {
+        if (!imageCanvas.isEnabled()){
+            return;   
+        }
+        if (e.getButton() == MouseEvent.BUTTON1) {
+            lastX = e.getX();
+            lastY = e.getY();
+        }
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+        if (!imageCanvas.isEnabled()){
+            return;
+        } 
+        if (e.getButton() == MouseEvent.BUTTON1) {
+            imageCanvas.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+        }
+    }
+
+    public void mouseWheelMoved(MouseWheelEvent e)
+    {
+        if (!imageCanvas.isEnabled()){
+            return;
+        }      
+        int scroll = e.getUnitsToScroll();
+        zoomSlider.setValue(zoomSlider.getValue() - scroll);
+    }
+
+    /**
+     * Get the image created by this image panel or null if none exists.
+     */
+    public BufferedImage getImage()
+    {
+        if (!haveImage) {
+            return null;
+        }
+        BufferedImage newImage = GraphicsUtilities.createCompatibleImage(width, height);
+        Graphics2D g = newImage.createGraphics();
+        imageCanvas.paintImage(g);
+        g.dispose();
+        return newImage;
+    }
+    
+    /**
+     * Sets the slider and the image canvas to be enabled/disabled 
+     */
+    public void enableImageEditPanel (boolean enabled)
+    {
+        enableImageControls = enabled;
+        if (!enabled || haveImage) {
+            zoomSlider.setEnabled(enabled);
+            imageCanvas.setEnabled(enabled);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/LeftRightBorder.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/LeftRightBorder.java
new file mode 100644
index 0000000000000000000000000000000000000000..3517c16406a09c0de37fa4780d0fb14e3fafcb73
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/LeftRightBorder.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.export;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import javax.swing.border.LineBorder;
+
+/*
+ * Custom Border class to draw just the left and right sides of a lin border.
+ *
+ * @author Michael Kolling
+ * @version $Id: LeftRightBorder.java 6216 2009-03-30 13:41:07Z polle $
+ */
+
+public class LeftRightBorder extends LineBorder
+{
+    
+    /**
+     * Create a left-right border with width 1 and the given color.
+     */
+    public LeftRightBorder(Color col)
+    {
+        super(col);
+    }
+
+    /**
+     * Paints the border only on the left and right sides.
+     */
+    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
+        Color oldColor = g.getColor();
+
+        g.setColor(getLineColor());
+        g.drawLine(x, y, x, height-1);
+        g.drawLine(width-1, y, width-1, height-1);
+        g.setColor(oldColor);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ProxyAuthDialog.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ProxyAuthDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..695f14c6d346bded0afe5528cadd7022ebb73082
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/ProxyAuthDialog.java
@@ -0,0 +1,151 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.export;
+
+import java.awt.LayoutManager;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.utility.DBox;
+import bluej.utility.DialogManager;
+import bluej.utility.MiksGridLayout;
+
+/**
+ * Display a "proxy authentication required" dialog, prompting for username and password.
+ * 
+ * @author Davin McCall
+ */
+public class ProxyAuthDialog extends JDialog
+{
+    private JTextField usernameField;
+    private JTextField passwordField;
+    
+    private int result;
+    public static final int OK = 0;
+    public static final int CANCEL = 1;
+    
+    /**
+     * Construct a new proxy authentication dialog
+     */
+    public ProxyAuthDialog(Window parentWindow)
+    {
+        super(parentWindow, ModalityType.APPLICATION_MODAL);
+        setTitle(Config.getString("export.publish.proxyAuth"));
+        buildUI();
+        DialogManager.centreDialog(this);
+    }
+    
+    /**
+     * Get the result - either OK or CANCEL.
+     */
+    public int getResult()
+    {
+        return result;
+    }
+
+    /**
+     * Get the username entered by the user.
+     */
+    public String getUsername()
+    {
+        return usernameField.getText();
+    }
+    
+    /**
+     * Get the password entered by the user.
+     */
+    public String getPassword()
+    {
+        return passwordField.getText();
+    }
+    
+    /**
+     * Build the user interface
+     */
+    private void buildUI()
+    {
+        JPanel contentPane = new JPanel();
+        setContentPane(contentPane);
+        
+        contentPane.setBorder(BlueJTheme.generalBorder);
+        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
+        
+        JLabel msgLabel = new JLabel(Config.getString("export.publish.needProxyAuth"));
+        msgLabel.setAlignmentX(0.0f);
+        contentPane.add(msgLabel);
+        
+        contentPane.add(Box.createVerticalStrut(BlueJTheme.componentSpacingLarge));
+        
+        LayoutManager lm = new MiksGridLayout(2, 2, BlueJTheme.componentSpacingSmall, BlueJTheme.componentSpacingSmall);
+        JPanel authPanel = new JPanel(lm);
+        
+        authPanel.add(new JLabel(Config.getString("export.publish.username")));
+        usernameField = new JTextField(20);
+        authPanel.add(usernameField);
+        
+        authPanel.add(new JLabel(Config.getString("export.publish.password")));
+        passwordField = new JTextField(20);
+        authPanel.add(passwordField);
+        
+        JButton okButton = new JButton(Config.getString("okay"));
+        okButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+                result = OK;
+                dispose();
+            }
+        });
+        
+        JButton cancelButton = new JButton(Config.getString("cancel"));
+        cancelButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+                result = CANCEL;
+                dispose();
+            }
+        });
+        
+        DBox buttonBox = new DBox(DBox.X_AXIS, BlueJTheme.commandButtonSpacing, BlueJTheme.commandButtonSpacing, 0.5f);
+        
+        buttonBox.add(Box.createHorizontalGlue());
+        DialogManager.addOKCancelButtons(buttonBox, okButton, cancelButton);
+        
+        contentPane.add(authPanel);
+        contentPane.add(buttonBox);
+        getRootPane().setDefaultButton(okButton);
+        
+        pack();
+    }    
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/TabbedIconPane.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/TabbedIconPane.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c64c0c5a8a1a5b4dbe30e07342869b6048e6798
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/TabbedIconPane.java
@@ -0,0 +1,180 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.export;
+
+/*
+ * Class TabbedIconPane is a component that holds a few mutually exclusive
+ * selectable icons - a bit like a JTabbedPane.
+ *
+ * Currently hardcoded for one set of icons. Could be generalised if needed.
+ *
+ * @author Michael Kolling
+ * @version $Id: TabbedIconPane.java 8827 2011-04-04 10:08:45Z nccb $
+ */
+
+import bluej.Config;
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.ImageIcon;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.SwingConstants;
+import javax.swing.border.Border;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+
+public class TabbedIconPane extends JPanel
+        implements ActionListener
+{
+    private static final Color backgroundColor = new Color(250, 250, 250);
+    private static final Color selectedColor = new Color(220, 220, 220);
+    private static final Color lineColor = new Color(180, 180, 180);
+    private static final Border emptyBorder = new EmptyBorder(4, 10, 4, 10);
+    private static final Border selectedBorder = new CompoundBorder(new LeftRightBorder(lineColor), 
+                                                    new EmptyBorder(3, 9, 3, 9));
+                
+    private JRadioButton selected;
+    private TabbedIconPaneListener listener;
+    private Map<String, JRadioButton> buttons = new HashMap<String, JRadioButton>();
+    
+    /**
+     * Creates a new instance of TabbedIconPane.
+     */
+    public TabbedIconPane(String initialSelect) 
+    {
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+        this.setBackground(backgroundColor);
+        add(makeButtonRow(initialSelect));
+        //add(new JSeparator());
+    }
+    
+    /**
+     * Attach a (single) listener to this pane.
+     */
+    public void setListener(TabbedIconPaneListener listener)
+    {
+        this.listener = listener;
+    }
+    
+    /**
+     * Make the row of toggle/radio buttons along the top of the dialogue.
+     */
+    private JPanel makeButtonRow(String initialSelect)
+    {
+        JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0,0));
+        
+        panel.setBorder(null);
+        panel.setBackground(backgroundColor);
+
+        ButtonGroup group = new ButtonGroup();
+
+        makeButton(Config.getString("export.icontab.publish"), "export-publish", ExportPublishPane.FUNCTION, initialSelect, group, panel);
+        makeButton(Config.getString("export.icontab.webpage"), "export-webpage", ExportWebPagePane.FUNCTION, initialSelect, group, panel);
+        makeButton(Config.getString("export.icontab.application"), "export-app", ExportAppPane.FUNCTION, initialSelect, group, panel);
+
+        return panel;
+    }
+    
+    /**
+     * Make one of the buttons to go into this component.
+     */
+    private JRadioButton makeButton(String text, String iconName, String command, 
+                                    String selectCommand, ButtonGroup group, JPanel parent)
+    {
+        URL iconFile = this.getClass().getClassLoader().getResource(iconName + ".png");
+        ImageIcon icon = null;
+        if(iconFile != null) {
+            icon = new ImageIcon(iconFile);
+        }
+        JRadioButton toggle = new JRadioButton(text, icon);
+        toggle.setHorizontalTextPosition(SwingConstants.CENTER);
+        toggle.setVerticalTextPosition(SwingConstants.BOTTOM);
+        toggle.setActionCommand(command);
+        toggle.addActionListener(this);
+        toggle.setOpaque(false);
+        buttons.put(command, toggle);
+
+        JPanel panel = new JPanel();
+        panel.setBackground(backgroundColor);
+        panel.setBorder(emptyBorder);
+        panel.add(toggle);
+        parent.add(panel);
+        
+        if(command.equals(selectCommand)) {
+            toggle.setSelected(true);
+            select(toggle);
+        }
+        return toggle;
+    }
+    
+    /**
+     * Directly selects the given button without informing the listener
+     */
+    public void select(String function)
+    {
+        JRadioButton button = buttons.get(function);
+        if (button != null) {
+            deselect(selected);
+            select(button);
+        }
+    }
+    
+    /**
+     * A tab in this tabbed pane has been selected.
+     */
+    public void actionPerformed(ActionEvent e) 
+    {
+        deselect(selected);
+        JRadioButton button = (JRadioButton)e.getSource();
+        select(button);
+        listener.tabSelected(e.getActionCommand());
+    }
+
+    /**
+     * Decorate the given button so that it appears selected.
+     */
+    private void select(JRadioButton button)
+    {
+        JPanel parent = (JPanel)button.getParent();
+        parent.setBackground(selectedColor);
+        parent.setBorder(selectedBorder);
+        selected = button;
+    }
+
+    /**
+     * Decorate the given button so that it appears deselected.
+     */
+    private void deselect(JRadioButton button)
+    {
+        JPanel parent = (JPanel)button.getParent();
+        parent.setBackground(backgroundColor);
+        parent.setBorder(emptyBorder);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/TabbedIconPaneListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/TabbedIconPaneListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e5cfc3df4e025682eca01fa787f3bceba19a77b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/export/TabbedIconPaneListener.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+/*
+ * TabbedIconPaneListener - a listener to tab selection changes in the
+ * TabbedIconPane.
+ *
+ * @author Michael Kolling
+ * @version $Id: TabbedIconPaneListener.java 6216 2009-03-30 13:41:07Z polle $
+ */
+
+package greenfoot.gui.export;
+
+public interface TabbedIconPaneListener 
+{
+    /** 
+     * Called when the selection of the tabs changes.
+     * 'name' is the NAME of the selected tab.
+     */
+    void tabSelected(String name);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/GreenfootImageLibPanel.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/GreenfootImageLibPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..203bf9273e86a3b652c2a91161e10ca98b02a956
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/GreenfootImageLibPanel.java
@@ -0,0 +1,88 @@
+/*
+ This file is part of the Greenfoot program.
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ This file is subject to the Classpath exception as provided in the
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.images;
+
+import greenfoot.util.GreenfootUtil;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+
+/**
+ * 
+ * Component that shows selectors for images in the Greenfoot library of images.
+ * 
+ * @author Poul Henriksen
+ */
+public class GreenfootImageLibPanel extends Box
+{
+    public GreenfootImageLibPanel(ImageCategorySelector categorySelector, ImageLibList imageList)
+    {
+        super(BoxLayout.X_AXIS);
+        
+        // Category panel
+        {
+            Box piPanel = new Box(BoxLayout.Y_AXIS);        
+    
+            JLabel piLabel = new JLabel(Config.getString("imagelib.categories"));
+            piLabel.setAlignmentX(0.0f);
+            piPanel.add(piLabel);
+    
+    
+            JScrollPane jsp = new JScrollPane(categorySelector);
+    
+            jsp.setBorder(Config.normalBorder);
+            jsp.setViewportBorder(BorderFactory.createLineBorder(categorySelector.getBackground(), 4));
+            jsp.setAlignmentX(0.0f);
+    
+            piPanel.add(jsp);
+            add(piPanel);             
+    
+            add(GreenfootUtil.createSpacer(GreenfootUtil.X_AXIS, BlueJTheme.componentSpacingSmall));
+        }
+         
+        // Image panel
+        {
+            Box piPanel = new Box(BoxLayout.Y_AXIS);
+    
+            JLabel piLabel = new JLabel(Config.getString("imagelib.images"));
+            piLabel.setAlignmentX(0.0f);
+            piPanel.add(piLabel);
+    
+            JScrollPane jsp = new JScrollPane();
+    
+            jsp.getViewport().setView(imageList);
+    
+            jsp.setBorder(Config.normalBorder);
+            jsp.setViewportBorder(BorderFactory.createLineBorder(imageList.getBackground(), 4));
+            jsp.setAlignmentX(0.0f);
+    
+            piPanel.add(jsp);
+            add(piPanel);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageCategorySelector.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageCategorySelector.java
new file mode 100644
index 0000000000000000000000000000000000000000..383d23ac94acad57666aa056c0fced29a9492911
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageCategorySelector.java
@@ -0,0 +1,228 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.images;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.io.File;
+import java.io.FileFilter;
+import java.util.Arrays;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.DefaultListModel;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+/**
+ * A list which allows selecting image categories. The categories
+ * available are determined by scanning a directory for subdirectories.
+ * Selecting a category will make a corresponding ImageLibList show
+ * the contents of that category.
+ * 
+ * @author davmac
+ */
+public class ImageCategorySelector extends JList
+    implements ListSelectionListener
+{
+    private ImageLibList imageLibList;
+    
+    /**
+     * The expected number of categories. Our preferred scrollport
+     * size is set to be large enough to show this many categories.
+     */
+    private static int NUMBER_OF_CATEGORIES = 10;
+    
+    private int preferredHeight;
+    
+    /**
+     * Construct an ImageCategorySelector to show categories from the
+     * given directory.
+     * 
+     * @param categoryDir  The directory containing the categories
+     *                     (subdirectories)
+     */
+    public ImageCategorySelector(File categoryDir)
+    {
+        DefaultListModel listModel = new DefaultListModel();
+        setModel(listModel);
+        setLayoutOrientation(JList.VERTICAL);
+        setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        setCellRenderer(new MyCellRenderer());
+        addListSelectionListener(this);
+        
+        FileFilter filter = new FileFilter() {
+            public boolean accept(File path)
+            {
+                // Show directories only
+                return path.isDirectory();
+            }
+        };
+        
+        File [] imageFiles = categoryDir.listFiles(filter);
+        if (imageFiles == null) {
+            return;
+        }
+        
+        Arrays.sort(imageFiles);
+
+        for (int i = 0; i < imageFiles.length; i++) {
+            listModel.addElement(imageFiles[i]);
+            if (i == (NUMBER_OF_CATEGORIES - 1)) {
+                preferredHeight = getPreferredSize().height;
+            }
+        }
+        
+        if (preferredHeight == 0) {
+            preferredHeight = getPreferredSize().height;
+        }
+    }
+
+    /**
+     * Set the ImageLibList to be associated with this category selector.
+     * When a category is selected, the associated ImageLibList will be
+     * made to show images from the category.
+     * 
+     * @param imageLibList  The ImageLibList to associate with this category
+     *                      selector
+     */
+    public void setImageLibList(ImageLibList imageLibList)
+    {
+        this.imageLibList = imageLibList;
+    }
+    
+    /**
+     * Get the currently selected image directory.
+     */
+    public File getSelectedDirectory()
+    {
+        return (File) getSelectedValue();
+    }
+
+    /* (non-Javadoc)
+     * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
+     */
+    public void valueChanged(ListSelectionEvent e)
+    {
+        if (imageLibList != null) {
+            File selected = getSelectedDirectory();
+            if (selected != null) {
+                imageLibList.setDirectory(selected);
+            }
+        }
+    }
+    
+    private static class MyCellRenderer extends Box
+    implements ListCellRenderer
+    {
+        private static final String iconFile = "openRight.png"; 
+        private static final Icon openRightIcon = new ImageIcon(ImageCategorySelector.class.getClassLoader().getResource(iconFile));
+        
+        private JLabel categoryNameLabel;
+        private JLabel iconLabel;
+        
+        public MyCellRenderer()
+        {
+            super(BoxLayout.X_AXIS);
+
+            iconLabel = new JLabel(openRightIcon);
+            Dimension iconSize = iconLabel.getPreferredSize();
+            // Set maximum size on the icon label so that the category
+            // name label uses up all the extra space
+            iconLabel.setMaximumSize(iconSize);
+            
+            categoryNameLabel = new JLabel(" ");
+            // name label height the same as the icon height (for selection painting)
+            Dimension preferredSize = categoryNameLabel.getPreferredSize();
+            preferredSize.height = iconSize.height;
+            categoryNameLabel.setPreferredSize(preferredSize);
+            
+            add(categoryNameLabel);
+            add(iconLabel);
+        }
+        
+        public Component getListCellRendererComponent(
+                JList list,
+                Object value,            // value to display
+                int index,               // cell index
+                boolean isSelected,      // is the cell selected
+                boolean cellHasFocus)    // the list and the cell have the focus
+        {
+            File entry = (File) value;
+            
+            categoryNameLabel.setText(entry.getName());
+            categoryNameLabel.setFont(list.getFont());
+            
+            // Mess with sizes to make sure the name label fills as
+            // much space as possible, pushing the icon over to the
+            // right.
+            Dimension size = categoryNameLabel.getPreferredSize();
+            size.width = Integer.MAX_VALUE;
+            categoryNameLabel.setMaximumSize(size);
+            
+            // Set foreground and background colors according to 
+            // selection status.
+            Box item = this;
+            Color foregroundColor, backgroundColor;
+            if (isSelected) {
+                backgroundColor = list.getSelectionBackground();
+                foregroundColor = list.getSelectionForeground();
+            }
+            else {
+                backgroundColor = list.getBackground();
+                foregroundColor = list.getForeground();
+            }
+            categoryNameLabel.setBackground(backgroundColor);
+            categoryNameLabel.setForeground(foregroundColor);
+            iconLabel.setBackground(backgroundColor);
+            iconLabel.setForeground(foregroundColor);
+            categoryNameLabel.setOpaque(isSelected);
+            iconLabel.setOpaque(isSelected);
+            
+            item.setEnabled(list.isEnabled());
+            item.setFont(list.getFont());
+            item.setOpaque(true);
+            return item;
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see javax.swing.Scrollable#getPreferredScrollableViewportSize()
+     */
+    public Dimension getPreferredScrollableViewportSize()
+    {
+        // Limit the preferred viewport width to the preferred width
+        Dimension d = super.getPreferredScrollableViewportSize();
+        Dimension preferredSize = getPreferredSize();
+        
+        d.height = Math.max(d.height, preferredHeight);
+        d.width = Math.min(d.width, preferredSize.width);
+        return d;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageFilePreview.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageFilePreview.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fe93337691f0cb1b8833a874657c0fb49a5649f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageFilePreview.java
@@ -0,0 +1,124 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.images;
+
+import bluej.Config;
+import greenfoot.util.GraphicsUtilities;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+
+/**
+ * An image preview box accessory for a file chooser
+ * 
+ * @author Davin McCall
+ * @version $Id: ImageFilePreview.java 8238 2010-09-02 11:04:59Z nccb $
+ */
+public class ImageFilePreview extends JLabel
+    implements PropertyChangeListener
+{
+    private ImageIcon blankPreview;
+    
+    public ImageFilePreview(JFileChooser chooser)
+    {
+        int dpi = Toolkit.getDefaultToolkit().getScreenResolution();
+        int width = dpi * 2;
+        int height = dpi * 2;
+
+        BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(width, height);
+        Graphics2D graphics = image.createGraphics();
+        FontMetrics fontMetrics = graphics.getFontMetrics();
+        Rectangle2D stringBounds = fontMetrics.getStringBounds(Config.getString("imagelib.file.noPreview"), graphics);
+        int ypos = (int)(height - stringBounds.getHeight()) / 2 + fontMetrics.getAscent();
+        int xpos = (int)(width - stringBounds.getWidth()) / 2;
+        graphics.setColor(Color.BLACK);
+        graphics.drawString(Config.getString("imagelib.file.noPreview"), xpos, ypos);
+        blankPreview = new ImageIcon(image);
+        setIcon(blankPreview);
+        
+        graphics.dispose();
+        chooser.addPropertyChangeListener(this);
+        chooser.setAccessory(this);
+    }
+    
+    public void propertyChange(PropertyChangeEvent evt)
+    {
+        boolean update = false;
+        String prop = evt.getPropertyName();
+        File file = null;
+
+        //If the directory changed, don't show an image.
+        if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(prop)) {
+            update = true;
+
+        //If a file became selected, find out which one.
+        } else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(prop)) {
+            file = (File) evt.getNewValue();
+            update = true;
+        }
+
+        //Update the preview accordingly.
+        if (update) {
+            int dpi = Toolkit.getDefaultToolkit().getScreenResolution();
+            int width = dpi * 2;
+            int height = dpi * 2;
+            
+            if (file != null) {
+                try {
+                    BufferedImage image = ImageIO.read(file);
+                    if (image != null) {
+                        Image scaledImage = GreenfootUtil.getScaledImage(image, width, height);
+                        Icon icon = new ImageIcon(scaledImage);
+                        setIcon(icon);
+                    }
+                    else {
+                        file = null;
+                    }
+                }
+                catch (IOException ioe) {
+                    file = null;
+                }
+            }
+            
+            // No file is selected, or a non-image file selected.
+            if (file == null) {
+                setIcon(blankPreview);
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageFilter.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..53575e99541f4755fe5e8b2ed7a61ddcb465428c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageFilter.java
@@ -0,0 +1,79 @@
+/*
+ This file is part of the Greenfoot program.
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ This file is subject to the Classpath exception as provided in the
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.images;
+
+import java.io.File;
+import javax.imageio.ImageIO;
+import javax.swing.filechooser.FileFilter;
+
+
+/**
+ * A filter used to just display image files understood by all the currently
+ * registered readers.
+ * @author Michael Berry (mjrb4)
+ * @version 09/07/09
+ */
+public class ImageFilter extends FileFilter
+{
+
+    /**
+     * Decide whether or not the file should be accepted by the ImageFilter.
+     * All currently registered image files as well as directories should be
+     * accepted.
+     * @param f the file or directory to check for acceptance
+     * @return true if the file is accepted in the filter, false otherwise
+     */
+    public boolean accept(File f)
+    {
+        if(f.isDirectory()) {
+            return true;
+        }
+        for(String s : ImageIO.getReaderFileSuffixes()) {
+            if(getExtension(f).equalsIgnoreCase(s)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Get the description of this ImageFilter.
+     */
+    public String getDescription()
+    {
+        return "Images";
+    }
+
+    /**
+     * Get the extension of a file.
+     * @see http://java.sun.com/docs/books/tutorial/uiswing/examples/components/FileChooserDemo2Project/src/components/Utils.java
+     */
+    private String getExtension(File f) {
+        String ext = "";
+        String s = f.getName();
+        int i = s.lastIndexOf('.');
+
+        if (i > 0 &&  i < s.length() - 1) {
+            ext = s.substring(i+1).toLowerCase();
+        }
+        return ext;
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageLibFrame.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageLibFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e21fdcb2fb4d716f4bf0deefe612c7f6d509741
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageLibFrame.java
@@ -0,0 +1,753 @@
+/*
+ This file is part of the Greenfoot program.
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ This file is subject to the Classpath exception as provided in the
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.images;
+
+import greenfoot.actions.BrowseImagesAction;
+import greenfoot.core.GClass;
+import greenfoot.core.GPackage;
+import greenfoot.core.GProject;
+import greenfoot.event.ValidityEvent;
+import greenfoot.event.ValidityListener;
+import greenfoot.gui.ClassNameVerifier;
+import greenfoot.gui.classbrowser.ClassView;
+import greenfoot.gui.images.ImageLibList.ImageListEntry;
+import greenfoot.util.ExternalAppLauncher;
+import greenfoot.util.GraphicsUtilities;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import javax.swing.Timer;
+
+import javax.imageio.ImageIO;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JTextField;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.EscapeDialog;
+import bluej.utility.FileUtility;
+
+/**
+ * A (modal) dialog for selecting a class image. The image can be selected from either the
+ * project image library, or the greenfoot library, or an external location.
+ *
+ * @author Davin McCall
+ */
+public class ImageLibFrame extends EscapeDialog implements ListSelectionListener, WindowListener
+{
+    /** Label displaying the currently selected image. */
+    private JLabel imageLabel;
+    private JLabel imageTextLabel;
+    private GClass gclass;
+    private GProject proj;
+    /** The default image icon - the greenfoot logo */
+    private Icon defaultIcon;
+    private JScrollPane imageScrollPane;
+    
+    private ImageLibList projImageList;
+    private ImageLibList greenfootImageList;
+    private Action okAction;
+
+    private File selectedImageFile;
+    private File projImagesDir;
+
+    public static final int OK = 0;
+    public static final int CANCEL = 1;
+    private int result = CANCEL;
+
+    private JTextField classNameField;
+    
+    /** Menu items that are in the drop down button,
+     *  which we want to alter the enabled state of. */
+    private JMenuItem editItem;
+    private JMenuItem duplicateItem;
+    private JMenuItem deleteItem;
+
+    private Timer refreshTimer;
+    
+    /** Suffix used when creating a copy of an existing image (duplicate) */
+    private static final String COPY_SUFFIX = "Copy"; //TODO move to labels
+    
+    /** JPopupMenu icon */
+    private static final String DROPDOWN_ICON_FILE = "menu-button.png";
+    
+    /** A watcher that goes notified when an image is selected, to allow for previewing. May be null */
+    private ImageSelectionWatcher selectionWatcher;
+
+    /**
+     * Construct an ImageLibFrame for changing the image of an existing class.
+     *
+     * @param owner      The parent frame
+     * @param classView  The ClassView of the existing class
+     */
+    public ImageLibFrame(JFrame owner, ClassView classView, ImageSelectionWatcher watcher)
+    {
+        super(owner, Config.getString("imagelib.title") + " " + classView.getClassName(), true);
+
+        this.selectionWatcher = watcher;
+        this.gclass = classView.getGClass();
+        this.proj = gclass.getPackage().getProject();
+        defaultIcon = getPreviewIcon(new File(GreenfootUtil.getGreenfootLogoPath()));
+
+        buildUI(proj, false);       
+    }
+
+    /**
+     * Construct an ImageLibFrame to be used for creating a new class.
+     *
+     * @param owner        The parent frame
+     * @param superClass   The superclass of the new class
+     */
+    public ImageLibFrame(JFrame owner, GClass superClass)
+    {
+        super(owner, Config.getString("imagelib.newClass"), true);
+        this.gclass = superClass;
+        this.proj = gclass.getPackage().getProject();
+        defaultIcon = getClassIcon(superClass, getPreviewIcon(new File(GreenfootUtil.getGreenfootLogoPath())));
+        
+        buildUI(proj, true);        
+    }
+
+    private void buildUI(GProject project, final boolean includeClassNameField)
+    {
+        this.addWindowListener(this);
+        JPanel contentPane = new JPanel();
+        this.setContentPane(contentPane);
+        contentPane.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
+        contentPane.setBorder(BlueJTheme.dialogBorder);
+
+        // int spacingSmall = BlueJTheme.componentSpacingSmall;
+        int spacingLarge = BlueJTheme.componentSpacingLarge;
+
+        okAction = getOkAction();
+
+        // Class details - name, current icon
+        contentPane.add(buildClassDetailsPanel(includeClassNameField, project.getDefaultPackage()));
+
+        // Image selection panels - project and greenfoot image library
+        {
+            Box imageSelPanels = new Box(BoxLayout.X_AXIS);
+
+            // Project images panel
+            {
+                Box piPanel = new Box(BoxLayout.Y_AXIS);
+
+                JLabel piLabel = new JLabel(Config.getString("imagelib.projectImages"));
+                piLabel.setAlignmentX(0.0f);
+                piPanel.add(piLabel);
+
+                imageScrollPane = new JScrollPane();
+
+                File projDir = project.getDir();
+                projImagesDir = new File(projDir, "images");
+                projImageList = new ImageLibList(projImagesDir, false, this);
+                imageScrollPane.getViewport().setView(projImageList);
+
+                imageScrollPane.setBorder(Config.normalBorder);
+                imageScrollPane.setViewportBorder(BorderFactory.createLineBorder(projImageList.getBackground(), 4));
+                imageScrollPane.setAlignmentX(0.0f);
+
+                piPanel.add(imageScrollPane);
+                imageSelPanels.add(piPanel);
+            }
+
+            imageSelPanels.add(GreenfootUtil.createSpacer(GreenfootUtil.X_AXIS, spacingLarge));
+            
+            // Category selection panel
+            File imageDir = new File(Config.getGreenfootLibDir(), "imagelib");
+            ImageCategorySelector imageCategorySelector = new ImageCategorySelector(imageDir);
+
+            // List of images
+            greenfootImageList = new ImageLibList(false, this);
+            
+            JComponent greenfootLibPanel = new GreenfootImageLibPanel(imageCategorySelector, greenfootImageList);
+            
+            imageSelPanels.add(greenfootLibPanel);
+            
+            imageSelPanels.setAlignmentX(0.0f);
+            contentPane.add(imageSelPanels);
+
+            projImageList.addListSelectionListener(this);
+            greenfootImageList.addListSelectionListener(this);
+            imageCategorySelector.setImageLibList(greenfootImageList);
+        }
+        
+        // Creates the PopupMenuButton, adding the edit, duplicate, delete and new
+        // menu items, along with their actions to it. Also creates the browse button
+        // and adds both of these components to a flow panel to display in the content
+        // panel.
+        {
+            JPanel borderPanel = new JPanel();
+            BorderLayout layout = new BorderLayout();
+            borderPanel.setLayout(layout);
+            
+            JPopupMenu popupMenu = new JPopupMenu();
+            
+            editItem = new JMenuItem(Config.getString("imagelib.edit"));
+            editItem.setToolTipText(Config.getString("imagelib.edit.tooltip")); 
+            editItem.setEnabled(false);
+            editItem.setFont(PrefMgr.getPopupMenuFont());
+            editItem.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e)
+                {
+                    ImageListEntry entry = projImageList.getSelectedValue();
+                    if (entry != null && entry.imageFile != null) {
+                        ExternalAppLauncher.editImage(entry.imageFile);
+                    }
+                }
+            });
+            
+            duplicateItem = new JMenuItem(Config.getString("imagelib.duplicate"));
+            duplicateItem.setToolTipText(Config.getString("imagelib.duplicate.tooltip")); 
+            duplicateItem.setEnabled(false);
+            duplicateItem.setFont(PrefMgr.getPopupMenuFont());
+            duplicateItem.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e)
+                {
+                    ImageListEntry entry = projImageList.getSelectedValue();
+                    if (entry != null && entry.imageFile != null) {
+                        duplicateSelected(entry);
+                    }
+                }
+            });
+            
+            deleteItem = new JMenuItem(Config.getString("imagelib.delete"));
+            deleteItem.setToolTipText(Config.getString("imagelib.delete.tooltip"));
+            deleteItem.setEnabled(false);
+            deleteItem.setFont(PrefMgr.getPopupMenuFont());
+            deleteItem.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e)
+                {
+                    ImageListEntry entry = projImageList.getSelectedValue();
+                    if (entry != null && entry.imageFile != null) {
+                        confirmDelete(entry);
+                    }
+                }
+            });
+
+            JMenuItem newImageItem = new JMenuItem(Config.getString("imagelib.create.button"));
+            newImageItem.setToolTipText(Config.getString("imagelib.create.tooltip")); 
+            newImageItem.setFont(PrefMgr.getPopupMenuFont());
+            newImageItem.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e)
+                {
+                    String name = includeClassNameField ? getClassName() : gclass.getName();
+                    NewImageDialog newImage = new NewImageDialog(ImageLibFrame.this, projImagesDir, name);
+                    final File file = newImage.displayModal();
+                    if (file != null) {
+                        projImageList.refresh();
+                        projImageList.select(file);
+                        selectImage(file);
+                    }                                           
+                }                
+            });
+            
+            popupMenu.add(fixHeight(editItem));
+            popupMenu.add(fixHeight(duplicateItem));
+            popupMenu.add(fixHeight(deleteItem));
+            popupMenu.add(fixHeight(newImageItem));
+            
+            JButton dropDownButton = new PopupMenuButton(
+                    new ImageIcon(ImageLibFrame.class.getClassLoader().getResource(DROPDOWN_ICON_FILE)), 
+                    popupMenu);
+            JButton browseButton = new JButton(
+                    new BrowseImagesAction(Config.getString("imagelib.browse.button"), this,
+                    projImagesDir, projImageList));
+        
+           
+            borderPanel.setAlignmentX(0.0f);
+            borderPanel.add(fixHeight(dropDownButton), BorderLayout.LINE_START);
+            borderPanel.add(fixHeight(browseButton), BorderLayout.LINE_END);
+
+            contentPane.add(fixHeight(Box.createVerticalStrut(spacingLarge)));
+            contentPane.add(fixHeight(borderPanel));
+            contentPane.add(fixHeight(Box.createVerticalStrut(spacingLarge)));
+            contentPane.add(fixHeight(new JSeparator()));
+        }
+
+        // Ok and cancel buttons
+        {
+            JPanel okCancelPanel = new JPanel();
+            okCancelPanel.setLayout(new BoxLayout(okCancelPanel, BoxLayout.X_AXIS));
+
+            JButton okButton = BlueJTheme.getOkButton();
+            okButton.setAction(okAction);
+
+            JButton cancelButton = BlueJTheme.getCancelButton();
+            cancelButton.setVerifyInputWhenFocusTarget(false);
+            cancelButton.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    result = CANCEL;
+                    setVisible(false);
+                    dispose();
+                }
+            });
+
+            okCancelPanel.add(Box.createHorizontalGlue());
+            
+            if (Config.isMacOS()) {
+                okCancelPanel.add(cancelButton);
+                okCancelPanel.add(Box.createHorizontalStrut(spacingLarge));
+                okCancelPanel.add(okButton);
+            }
+            else {
+                okCancelPanel.add(okButton);
+                okCancelPanel.add(Box.createHorizontalStrut(spacingLarge));
+                okCancelPanel.add(cancelButton);
+            }
+            
+            okCancelPanel.setAlignmentX(0.0f);
+            okCancelPanel.validate();
+            contentPane.add(fixHeight(Box.createVerticalStrut(spacingLarge)));
+            contentPane.add(fixHeight(okCancelPanel));
+
+            getRootPane().setDefaultButton(okButton);
+        }
+        
+        ActionListener refreshTask = new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                projImageList.refreshPreviews();
+            };
+        };
+            
+        refreshTimer = new Timer(2000, refreshTask);
+        refreshTimer.start();
+
+        pack();
+    }
+
+    /**
+     * Build the class details panel.
+     *
+     * @param includeClassNameField  Whether to include a field for
+     *                              specifying the class name.
+     * @param pkg
+     */
+    private JPanel buildClassDetailsPanel(boolean includeClassNameField, GPackage pkg)
+    {
+        JPanel classDetailsPanel = new JPanel();
+        classDetailsPanel.setLayout(new BoxLayout(classDetailsPanel, BoxLayout.Y_AXIS));
+
+        int spacingLarge = BlueJTheme.componentSpacingLarge;
+        int spacingSmall = BlueJTheme.componentSpacingSmall;
+
+        // Show current image
+        {
+            JPanel currentImagePanel = new JPanel();
+            currentImagePanel.setLayout(new BoxLayout(currentImagePanel, BoxLayout.X_AXIS));
+
+            if (includeClassNameField) {
+                Box b = new Box(BoxLayout.X_AXIS);
+                JLabel classNameLabel = new JLabel(Config.getString("imagelib.className"));
+                b.add(classNameLabel);
+
+                // "ok" button should be disabled until class name entered
+                okAction.setEnabled(false);
+
+                classNameField = new JTextField(12);
+                final JLabel errorMsgLabel = new JLabel();
+                errorMsgLabel.setVisible(false);
+                errorMsgLabel.setForeground(Color.RED);
+
+                final ClassNameVerifier classNameVerifier = new ClassNameVerifier(classNameField, pkg);
+                classNameVerifier.addValidityListener(new ValidityListener() {
+                    public void changedToInvalid(ValidityEvent e)
+                    {
+                        errorMsgLabel.setText(e.getReason());
+                        errorMsgLabel.setVisible(true);
+                        okAction.setEnabled(false);
+                    }
+
+                    public void changedToValid(ValidityEvent e)
+                    {
+                        errorMsgLabel.setVisible(false);
+                        okAction.setEnabled(true);
+                    }
+                });
+
+                b.add(Box.createHorizontalStrut(spacingLarge));
+
+                b.add(fixHeight(classNameField));
+                b.setAlignmentX(0.0f);
+                classDetailsPanel.add(b);
+
+                classDetailsPanel.add(errorMsgLabel);
+
+                classDetailsPanel.add(Box.createVerticalStrut(spacingLarge));
+            }
+
+            // help label
+            JLabel helpLabel = new JLabel(Config.getString("imagelib.help.selectImage"));
+
+            Font smallFont = helpLabel.getFont().deriveFont(Font.ITALIC, 11.0f);
+            helpLabel.setFont(smallFont);
+            classDetailsPanel.add(fixHeight(helpLabel));
+
+            classDetailsPanel.add(fixHeight(Box.createVerticalStrut(spacingLarge)));
+
+            classDetailsPanel.add(fixHeight(new JSeparator()));
+            classDetailsPanel.add(Box.createVerticalStrut(spacingSmall));
+
+            // new class image display
+            JLabel classImageLabel = new JLabel(Config.getString("imagelib.newClass.image"));
+            currentImagePanel.add(classImageLabel);
+
+            Icon icon = getClassIcon(gclass, defaultIcon);
+            
+            currentImagePanel.add(Box.createHorizontalStrut(spacingSmall));
+            imageLabel = new JLabel(icon) {
+                // We don't want changing the image to re-layout the
+                // whole frame
+                public boolean isValidateRoot()
+                {
+                    return true;
+                }
+            };
+            currentImagePanel.add(imageLabel);
+            currentImagePanel.add(Box.createHorizontalStrut(spacingSmall));
+
+            imageTextLabel = new JLabel() {
+                // We don't want changing the text to re-layout the
+                // whole frame
+                public boolean isValidateRoot()
+                {
+                    return true;
+                }
+            };
+            currentImagePanel.add(imageTextLabel);
+            currentImagePanel.setAlignmentX(0.0f);
+
+            classDetailsPanel.add(fixHeight(currentImagePanel));
+        }
+
+        classDetailsPanel.setAlignmentX(0.0f);
+        return classDetailsPanel;
+    }
+
+    /**
+     * A new image was selected in one of the ImageLibLists
+     */
+    public void valueChanged(ListSelectionEvent lse)
+    {
+        Object source = lse.getSource();
+        if (! lse.getValueIsAdjusting() && source instanceof ImageLibList) {
+            imageTextLabel.setText("");
+            ImageLibList sourceList = (ImageLibList) source;
+            ImageLibList.ImageListEntry ile = sourceList.getSelectedValue();
+
+            // handle the no-image image entry.
+            if (ile != null && ile.imageFile != null) {
+                File imageFile = ile.imageFile;
+                selectImage(imageFile);
+                setItemButtons(true);
+            } else {
+                selectImage(null);
+                setItemButtons(false);
+            }
+            
+        }
+
+        if (lse.getValueIsAdjusting() && source instanceof ImageLibList) {
+            if(lse.getSource()==projImageList) {
+                greenfootImageList.clearSelection();
+            }
+            else {
+                projImageList.clearSelection();
+            }
+        }
+    }
+
+    /**
+     * Change the three selection based menu items to the
+     * parameter provided.
+     * @param state To enable or disable the menu item buttons.
+     */
+    private void setItemButtons(boolean state)
+    {
+        editItem.setEnabled(state);
+        duplicateItem.setEnabled(state);
+        deleteItem.setEnabled(state);
+    }
+
+    /**
+     * Selects the given file (or no file) for use in the preview.
+     * 
+     * @param imageFile  The file to select, and to show in the small preview box in the
+     *                   ImageLibFrame. If null, then "no image" is selected.
+     */
+    private void selectImage(File imageFile)
+    {
+        if (imageFile == null || GreenfootUtil.isImage(imageFile)) {
+            imageLabel.setIcon(getPreviewIcon(imageFile));
+            selectedImageFile = imageFile;
+            if (selectionWatcher != null) {
+                selectionWatcher.imageSelected(selectedImageFile);
+            }
+        }
+        else if (imageFile != null) {
+            JOptionPane.showMessageDialog(this, imageFile.getName() +
+                    " " + Config.getString("imagelib.image.invalid.text"), Config.getString("imagelib.image.invalid.title"), JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    /**
+     * Get a preview icon for a class. This is a fixed size image. The
+     * user-specified image is normally used; if none exists, the class
+     * hierarchy is searched.
+     *
+     * @param gclass   The class whose icon to get
+     * @param defaultIcon  The icon to return if none can be found
+     */
+    private static Icon getClassIcon(GClass gclass, Icon defaultIcon)
+    {
+        String imageName = null;
+
+        if (gclass == null) {
+            return defaultIcon;
+        }
+
+        while (gclass != null) {
+            imageName = gclass.getClassProperty("image");
+
+            // If an image is specified for this class, and we can read it, return
+            if (imageName != null) {
+                File imageFile = new File(new File("images"), imageName);
+                if (imageFile.canRead()) {
+                    return getPreviewIcon(imageFile);
+                }
+            }
+
+            gclass = gclass.getSuperclass();
+        }
+
+        return defaultIcon;
+    }
+
+    /**
+     * Load an image from a file and scale it to preview size.
+     * @param fname  The file to load the image from
+     */
+    private static Icon getPreviewIcon(File fname)
+    {
+        int dpi = Toolkit.getDefaultToolkit().getScreenResolution();
+
+        if (fname == null) {
+            BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+            return new ImageIcon(bi);
+        }
+
+        try {
+            BufferedImage bi = ImageIO.read(fname);
+            return new ImageIcon(GreenfootUtil.getScaledImage(bi, dpi/2, dpi/2));
+        }
+        catch (IOException ioe) {
+            BufferedImage bi = GraphicsUtilities.createCompatibleTranslucentImage(dpi/2, dpi/2);
+            return new ImageIcon(bi);
+        }
+    }
+    
+    private static Icon getHalfinchScaledImage(BufferedImage bi)
+    {
+        int dpi = Toolkit.getDefaultToolkit().getScreenResolution();
+        return new ImageIcon(GreenfootUtil.getScaledImage(bi, dpi/2, dpi/2));
+    }
+
+    /**
+     * Fix the maximum height of the component equal to its preferred size, and
+     * return the component.
+     */
+    private static Component fixHeight(Component src)
+    {
+        Dimension d = src.getMaximumSize();
+        d.height = src.getPreferredSize().height;
+        src.setMaximumSize(d);
+        return src;
+    }
+
+    /**
+     * Get the selected image file
+     */
+    public File getSelectedImageFile()
+    {
+        return selectedImageFile;
+    }
+
+    /**
+     * Get the result from the dialog: OK or CANCEL
+     */
+    public int getResult()
+    {
+        return result;
+    }
+
+    /**
+     * Notification that a file changed on disk.
+     */
+    public void imageFileRefreshed(File f, BufferedImage image)
+    {
+        if (f.equals(selectedImageFile)) {
+            imageLabel.setIcon(getHalfinchScaledImage(image));
+        }
+    }
+    
+    /**
+     * Get the name of the class as entered in the dialog.
+     */
+    public String getClassName()
+    {
+        return classNameField.getText();
+    }
+
+    /**
+     * Get the action for the "ok" button.
+     */
+    private AbstractAction getOkAction()
+    {
+        return new AbstractAction(Config.getString("okay")) {
+            public void actionPerformed(ActionEvent e)
+            {
+                result = OK;
+                setVisible(false);
+                dispose();
+            }
+        };
+    }
+
+    /**
+     * If we have been editing an image externally, we select that image.
+     */
+    public void windowActivated(WindowEvent e)
+    {
+    }
+
+    public void windowClosed(WindowEvent e)
+    {
+        refreshTimer.stop();
+    }
+
+    public void windowClosing(WindowEvent e)
+    {
+        refreshTimer.stop();
+    }
+
+    public void windowDeactivated(WindowEvent e) 
+    {
+    }
+
+    public void windowDeiconified(WindowEvent e) 
+    {
+    }
+
+    public void windowIconified(WindowEvent e) 
+    {
+    }
+
+    public void windowOpened(WindowEvent e) 
+    {
+    }
+
+    /**
+     * Create a new file which is an exact copy of the
+     * parameter image and select it if successful in creating
+     * it.
+     * @param entry Cannot be null, nor can its imageFile.
+     */
+    protected void duplicateSelected(ImageListEntry entry)
+    {
+        File srcFile = entry.imageFile;
+        File dstFile = null;
+        File dir = srcFile.getParentFile();
+        String fileName = srcFile.getName();
+        int index = fileName.indexOf('.');
+        
+        String baseName = null;
+        String ext = null;
+        if (index != -1) {
+            baseName = fileName.substring(0, index);
+            ext = fileName.substring(index + 1);
+        } 
+        else {
+            baseName = fileName;
+            ext = "";
+        }
+        baseName += COPY_SUFFIX;
+        
+        try {
+            dstFile = GreenfootUtil.createNumberedFile(dir, baseName, ext);
+            FileUtility.copyFile(srcFile, dstFile);
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+        if (dstFile != null) {
+            projImageList.select(dstFile);
+        }
+    }
+    
+    /**
+     * Confirms whether or not to delete the selected file.
+     * @param entry Cannot be null, nor can its imageFile.
+     */
+    private void confirmDelete(ImageListEntry entry)
+    {
+        String text = Config.getString("imagelib.delete.confirm.text") + 
+                      " " + entry.imageFile.getName() + "?";
+        int optionResult = JOptionPane.showConfirmDialog(this, text,
+              Config.getString("imagelib.delete.confirm.title"), JOptionPane.YES_NO_OPTION);
+        if (optionResult == JOptionPane.YES_OPTION) {
+            entry.imageFile.delete();
+            projImageList.refresh();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageLibList.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageLibList.java
new file mode 100644
index 0000000000000000000000000000000000000000..d4e3846809855616478638e9c4856d74e7cd77b4
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageLibList.java
@@ -0,0 +1,447 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.images;
+
+import greenfoot.gui.EditableList;
+import greenfoot.gui.MessageDialog;
+import greenfoot.util.GreenfootUtil;
+import greenfoot.util.Selectable;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.LinkedList;
+
+import javax.imageio.ImageIO;
+import javax.swing.DefaultCellEditor;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.border.EmptyBorder;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableColumn;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+
+/**
+ * A list component which displays a list of images (found in a directory) with their
+ * filenames.
+ * 
+ * @author Davin McCall
+ * @author Poul Henriksen
+ */
+public class ImageLibList extends EditableList<ImageLibList.ImageListEntry> implements Selectable<File>
+{   
+    /** The directory whose images are currently displayed in this list */
+    private File directory;
+    
+    /** The preferred height of this list */
+    private int prefHeight = 200;
+    
+    private LinkedList<ImageListEntry> data;
+    
+    /** The frame containing this ImageLibList */
+    private ImageLibFrame imageLibFrame;
+    
+    /** The minimum width we'd like */
+    private int minWidth;
+    
+    /**
+     * Construct an empty ImageLibList.
+     */
+    public ImageLibList(final boolean editable, ImageLibFrame imageLibFrame)
+    {      
+        super(editable);
+        this.imageLibFrame = imageLibFrame;
+        
+        JLabel widthCalc = new JLabel("XXXXXXXXXXXXXXXXXXXXXXX");
+        minWidth = widthCalc.getPreferredSize().width;
+        
+        TableColumn tableColumn = getColumnModel().getColumn(0);
+        tableColumn.setCellRenderer(new MyCellRenderer());
+        
+        tableColumn.setCellEditor(new MyCellEditor(new JTextField()));
+        if (!editable) {
+            // A double-click executes the default action for the enclosing
+            // frame. But only if it is not editable, because if it is, double
+            // click will be used to initiate and edit.
+            addMouseListener(new MouseAdapter() {
+                public void mouseClicked(MouseEvent e)
+                {
+                    if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() >= 2) {
+                        if (getSelectedValue() != null && getRootPane().getDefaultButton() != null) {
+                            getRootPane().getDefaultButton().doClick();
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * Construct an empty ImageLibList, and populate it with entries from
+     * the given directory.
+     * 
+     * @param directory  The directory to retrieve images from
+     */
+    public ImageLibList(File directory, final boolean editable, ImageLibFrame imageLibFrame)
+    {
+        this(editable, imageLibFrame);
+        setDirectory(directory);
+    }
+
+    /**
+     * Clear the list and re-populate it with images from the given
+     * directory.
+     * 
+     * @param directory   The directory to retrieve images from
+     */
+    public void setDirectory(File directory)
+    {
+        this.directory = directory;
+        
+        FilenameFilter filter = new FilenameFilter() {
+            public boolean accept(File dir, String name)
+            {
+                // We can accept all files. We try to load them all as an image.
+                return true;
+            }
+        };
+        
+        File [] imageFiles = directory.listFiles(filter);
+        if (imageFiles == null) {
+            imageFiles = new File[0];
+        }
+        
+        Arrays.sort(imageFiles);
+                
+        data = new LinkedList<ImageListEntry>();
+        data.add(new ImageListEntry(null));
+        
+        for (int i = 0; i < imageFiles.length; i++) {
+            ImageListEntry entry = new ImageListEntry(imageFiles[i]);
+            data.add(entry);
+            Icon icon = entry.imageIcon;
+            if (icon != null) {
+                int height = entry.imageIcon.getIconHeight();
+                if (height > getRowHeight()) {
+                    setRowHeight(height);
+                }
+            }
+        }
+        setListData(data);
+    }
+
+    /**
+     * Get the current directory this list is pointing to.
+     */
+    public File getDirectory()
+    {
+        return directory;
+    }
+
+    /**
+     * Refresh the contents of the list.
+     */
+    public void refresh()
+    {
+        if(getDirectory()!=null) {
+            setDirectory(getDirectory());
+        }
+    }
+    
+    /**
+     * Refreshes the previews of any existing images in the list
+     * that have been modified since the previews were last loaded
+     */
+    public void refreshPreviews()
+    {
+        boolean anyReloaded = false;
+        for (ImageListEntry entry : data)
+        {
+            boolean reloaded = entry.refreshPreview();
+            anyReloaded |= reloaded;
+        }
+        
+        if (anyReloaded) {
+            repaint();
+        }
+    }
+
+    /**
+     * If the given file exists in this list, it will be selected.
+     */
+    public void select(File imageFile)
+    {
+        refresh();
+        int row = setSelectedValue(new ImageListEntry(imageFile, false));
+        ensureIndexIsVisible(row);
+    }
+        
+    public Dimension getPreferredScrollableViewportSize()
+    {
+        // Limit the preferred viewport height to the preferred height
+        Dimension d = super.getPreferredScrollableViewportSize();
+        if(d.height > prefHeight) {
+            d.height = prefHeight;
+        }
+        return d;
+    }
+    
+    @Override
+    public Dimension getPreferredSize()
+    {
+        Dimension d = super.getPreferredSize();
+        d.width = Math.max(d.width, minWidth);
+        return d;
+    }
+    
+    /*
+     * @see greenfoot.gui.EditableList#getSelectedValues()
+     */
+    public ImageListEntry[] getSelectedValues()
+    {
+        Object[] list = super.getSelectedValues();
+        ImageListEntry[] entries = new ImageListEntry[list.length];
+        for (int i = 0; i < list.length; i++) {
+            entries[i] = (ImageListEntry) list[i];            
+        }  
+        return entries;
+    }
+    
+    private static class MyCellEditor extends DefaultCellEditor          
+    {
+        /**
+         * Constructs an editor that uses a text field.
+         * 
+         * @param textField a <code>JTextField</code> object
+         */
+        public MyCellEditor(final JTextField textField)
+        {
+            // Use the default JTextField editor, but with out own delegate
+            // installed.
+            super(textField);
+            textField.removeActionListener(delegate);
+            delegate = new EditorDelegate() {
+                private ImageListEntry value;
+
+                public void setValue(Object value)
+                {
+                    this.value = (ImageListEntry) value;
+                    textField.setText((this.value != null) ? this.value.imageFile.getName() : "");
+                }
+
+                public Object getCellEditorValue()
+                {
+                    String fileName = textField.getText();
+                    File oldFile = value.imageFile;
+                    File newFile = new File(oldFile.getParent(), fileName);
+                    if (!oldFile.equals(newFile) && newFile.exists()) {
+                        SwingUtilities.invokeLater(new Runnable() {
+                            public void run()
+                            {
+                                MessageDialog msg = new MessageDialog((JFrame) null,
+                                        Config.getString("imagelib.rename.exists.text"),
+                                        Config.getString("imagelib.rename.exists.title"), 100, new JButton[]{BlueJTheme.getCloseButton()});
+                                msg.displayModal();
+                            }
+                        });
+                    }
+                    else {
+                        boolean success = oldFile.renameTo(newFile);
+                        if (success) {
+                            value.imageFile = newFile;
+                        } else {
+                        }
+                    }
+                    return value;
+                }
+            };
+            textField.addActionListener(delegate);
+        }
+    }
+
+    private static class MyCellRenderer extends DefaultTableCellRenderer         
+    {
+        protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); 
+
+        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
+                boolean hasFocus, int row, int column)
+        {
+            JLabel item = this;
+            if(value != null) {
+                ImageListEntry entry = (ImageListEntry) value;
+                if (null == entry.imageFile) {
+                    item.setText("No image");
+                } else {
+                    item.setText(entry.imageFile.getName());
+                }
+                item.setIcon(entry.imageIcon);
+            }
+            if (isSelected) {
+                item.setBackground(table.getSelectionBackground());
+                item.setForeground(table.getSelectionForeground());
+            }
+            else {
+                item.setBackground(table.getBackground());
+                item.setForeground(table.getForeground());
+            }
+            item.setEnabled(table.isEnabled());
+            item.setFont(table.getFont());
+            
+            if (hasFocus) {
+                Border border = null;
+                if (isSelected) {
+                    border = UIManager.getBorder("Table.focusSelectedCellHighlightBorder");
+                }
+                if (border == null) {
+                    border = UIManager.getBorder("Table.focusCellHighlightBorder");
+                }
+                item.setBorder(border);
+
+                if (!isSelected && table.isCellEditable(row, column)) {
+                    Color col;
+                    col = UIManager.getColor("Table.focusCellForeground");
+                    if (col != null) {
+                        super.setForeground(col);
+                    }
+                    col = UIManager.getColor("Table.focusCellBackground");
+                    if (col != null) {
+                        super.setBackground(col);
+                    }
+                }
+            }
+            else {
+                item.setBorder(noFocusBorder);
+            }
+            
+            item.setOpaque(true);
+            return item;       
+        }        
+      
+        public Dimension getPreferredSize()
+        {
+            Dimension d = super.getPreferredSize();
+            d.width += BlueJTheme.generalSpacingWidth;
+            return d;
+        }
+    }
+    
+    
+    public class ImageListEntry
+    {
+        public File imageFile;
+        public Icon imageIcon;
+        private long lastModified;
+        
+        private ImageListEntry(File file)
+        {
+            this(file, true);
+        }
+        
+        /**
+         * Checks if the file has been modified since the preview was last generated,
+         * and reloads if it has been modified.
+         * 
+         * @return true if the preview did need to be reloaded
+         */
+        public boolean refreshPreview()
+        {
+            if (imageFile != null &&
+                imageFile.lastModified() != lastModified)
+            {
+                loadPreview();
+                return true;
+            }
+            return false;
+        }
+
+        private ImageListEntry(File file, boolean loadImage)
+        {
+            imageFile = file;
+            
+            if (loadImage) {
+                loadPreview();
+            }
+        }
+
+        private void loadPreview()
+        {
+            if (imageFile != null) {
+                lastModified = imageFile.lastModified();
+                int dpi = Toolkit.getDefaultToolkit().getScreenResolution();
+    
+                try {
+                    BufferedImage image = ImageIO.read(imageFile);
+                    if (image != null) {
+                        Image scaledImage = GreenfootUtil.getScaledImage(image, dpi / 3, dpi / 3);
+                        imageIcon = new ImageIcon(scaledImage);
+                    }
+                    
+                    imageLibFrame.imageFileRefreshed(imageFile, image);
+                }
+                catch (IllegalArgumentException iae) {
+                    // Some versions of the JDK seem to throw this when the image is malformed.
+                }
+                catch (IOException ioe) {}
+            }
+        }
+        
+        public boolean equals(Object other) 
+        {
+            if(!(other instanceof ImageListEntry)) {
+                return false;
+            }
+            ImageListEntry otherEntry = (ImageListEntry) other;
+            //other cannot be null here because it passed the instanceof check above:
+            if (otherEntry.imageFile == null || this.imageFile == null) {
+                return false;
+            }
+            else {
+                return otherEntry.imageFile.equals(this.imageFile);
+            }
+        }
+        
+        public int hashCode() 
+        {
+            return imageFile.hashCode();
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageSelectionWatcher.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageSelectionWatcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..842ad769ef2ac22569a07b50f8954406356f1526
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/ImageSelectionWatcher.java
@@ -0,0 +1,34 @@
+/*
+ This file is part of the Greenfoot program.
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ This file is subject to the Classpath exception as provided in the
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.images;
+
+import java.io.File;
+
+/**
+ * An interface for watching when an image selection (in ImageLibFrame) changes.
+ * 
+ * @author Davin McCall
+ */
+public interface ImageSelectionWatcher
+{
+    public void imageSelected(File imageFile);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/NewImageDialog.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/NewImageDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e08f6a4cb3b9fefc0aa8c2b7778556baed0789d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/NewImageDialog.java
@@ -0,0 +1,278 @@
+/*
+ This file is part of the Greenfoot program.
+ Copyright (C) 2009,2010  Poul Henriksen and Michael Kolling
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ This file is subject to the Classpath exception as provided in the
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.images;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+import bluej.utility.EscapeDialog;
+import greenfoot.util.ExternalAppLauncher;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import java.awt.image.BufferedImage;
+import javax.imageio.ImageIO;
+
+import java.io.IOException;
+import java.io.File;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JLabel;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.SpinnerNumberModel;
+
+/**
+ * A new image dialog, used for specifying the properties of an image before its
+ * creation. After it has been created it will automatically be opened in the
+ * default image editing program so the user can edit it.
+ * 
+ * @author Michael Berry (mjrb4)
+ */
+public class NewImageDialog extends EscapeDialog
+{
+    private static final int MAX_IMAGE_HEIGHT = 2000;
+    private static final int MAX_IMAGE_WIDTH = 2000;
+    private static final int DEFAULT_HEIGHT = 100;
+    private static final int DEFAULT_WIDTH = 100;
+    
+    private JTextField name;
+    private JSpinner width;
+    private JSpinner height;
+    private JButton okButton;
+    
+    private File projImagesDir;
+    private JDialog parent;
+    
+    private File file;
+    
+    private int imageWidth;
+    private int imageHeight;
+
+    /**
+     * Create a new image dialog. This is used for specifying the properties for
+     * creating a new image, which will then be opened in the image editor.
+     * @param parent the parent frame associated with this dialog
+     * @param projImagesDir the directory in which the images for the project are placed.
+     */
+    public NewImageDialog(JDialog parent, File projImagesDir, String rootName)
+    {
+        super(parent, Config.getString("imagelib.new.image.title"));
+        this.parent = parent;
+        this.projImagesDir = projImagesDir;
+
+        imageWidth = Config.getPropInteger("greenfoot.image.create.width", DEFAULT_WIDTH);
+        imageHeight = Config.getPropInteger("greenfoot.image.create.height", DEFAULT_HEIGHT);
+        buildUI(rootName);
+    }
+
+    /**
+     * Build the user interface for the dialog.
+     */
+    private void buildUI(String rootName)
+    {
+        JPanel mainPanel = new JPanel();
+        setContentPane(mainPanel);
+        //int space = BlueJTheme.dialogBorder;
+        //mainPanel.setBorder(BorderFactory.createEmptyBorder(space, space, space, space));
+        mainPanel.setBorder(BlueJTheme.dialogBorder);
+
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+
+        JPanel detailsPanel = new JPanel(new GridLayout(3, 2, BlueJTheme.componentSpacingSmall,
+                BlueJTheme.componentSpacingSmall));
+        detailsPanel.add(new JLabel(Config.getString("imagelib.new.image.name") + " "));
+        name = new JTextField(10);
+        name.setText(rootName);
+        name.addKeyListener(new KeyListener() {
+            @Override public void keyPressed(KeyEvent e) {
+                checkName();
+            }
+
+            @Override public void keyReleased(KeyEvent e) {
+                checkName();
+            }
+
+            @Override public void keyTyped(KeyEvent e) {
+                checkName();
+            }
+        });
+        
+        JPanel fileNamePanel = new JPanel();
+        fileNamePanel.setLayout(new BoxLayout(fileNamePanel, BoxLayout.X_AXIS));
+        fileNamePanel.add(name);
+        fileNamePanel.add(new JLabel(".png"));
+        
+        detailsPanel.add(fileNamePanel);
+
+        //mainPanel.add(fixHeight(Box.createVerticalStrut(BlueJTheme.componentSpacingLarge)));
+
+        detailsPanel.add(new JLabel(Config.getString("imagelib.new.image.width")));
+        width = new JSpinner(new SpinnerNumberModel(imageWidth, 1, MAX_IMAGE_WIDTH, 1));
+        detailsPanel.add(width);
+
+        //mainPanel.add(fixHeight(Box.createVerticalStrut(BlueJTheme.componentSpacingLarge)));
+
+        detailsPanel.add(new JLabel(Config.getString("imagelib.new.image.height")));
+        height = new JSpinner(new SpinnerNumberModel(imageHeight, 1, MAX_IMAGE_HEIGHT, 1));
+        detailsPanel.add(height);        
+
+        //mainPanel.add(fixHeight(Box.createVerticalStrut(BlueJTheme.componentSpacingLarge)));
+
+        detailsPanel.setMaximumSize(new Dimension(Short.MAX_VALUE, detailsPanel.getPreferredSize().height));
+        
+        mainPanel.add(detailsPanel);
+        mainPanel.add(Box.createVerticalGlue());
+        mainPanel.add(fixHeight(Box.createVerticalStrut(BlueJTheme.componentSpacingLarge)));
+        
+
+        Box buttonBox = new Box(BoxLayout.X_AXIS);
+        buttonBox.add(Box.createHorizontalGlue());
+        
+        okButton = BlueJTheme.getOkButton();
+        okButton.setEnabled(false);
+        okButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                createAndEdit();
+            }            
+        });
+        okButton.setAlignmentY(1.0f);        
+        
+        JButton cancelButton = BlueJTheme.getCancelButton();
+        cancelButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                dispose();                
+            }
+        });
+        cancelButton.setAlignmentY(1.0f);
+        
+        if (Config.isMacOS()) {
+            buttonBox.add(cancelButton);
+            buttonBox.add(Box.createHorizontalStrut(10));
+            buttonBox.add(okButton);
+        } else {
+            buttonBox.add(okButton);
+            buttonBox.add(Box.createHorizontalStrut(10));
+            buttonBox.add(cancelButton);
+        }
+        
+        mainPanel.add(buttonBox);
+
+        setLocation(parent.getX()+parent.getWidth()/2, parent.getY()+parent.getHeight()/2);
+        getRootPane().setDefaultButton(okButton);
+        pack();
+        checkName();
+    }
+    
+    public File displayModal()
+    {
+        setModal(true);  
+        DialogManager.centreDialog(this);
+        setVisible(true);
+        dispose();
+        setModal(false);
+        return file;
+    }
+
+    public File getFile() 
+    {
+        return file;
+    }
+    
+    /**
+     * Fix the maxiumum height of the component equal to its preferred size, and
+     * return the component.
+     */
+    private static Component fixHeight(Component src)
+    {
+        Dimension d = src.getMaximumSize();
+        d.height = src.getPreferredSize().height;
+        src.setMaximumSize(d);
+        return src;
+    }
+
+    /**
+     * Check that the name specified in the name field is valid, and enable or
+     * disable the ok button accordingly.
+     */
+    private void checkName()
+    {
+        if(name.getText().trim().isEmpty()) {
+            okButton.setEnabled(false);
+        }
+        else {
+            okButton.setEnabled(true);
+        }
+    }
+
+    private void createAndEdit()
+    {
+        BufferedImage im = new BufferedImage((Integer) width.getValue(), (Integer) height.getValue(),
+                BufferedImage.TYPE_INT_ARGB);
+        String fileName = name.getText();
+        fileName += ".png";
+        file = new File(projImagesDir, fileName);
+
+        if (file.exists()) {
+            int r = JOptionPane.showOptionDialog(this, Config.getString("imagelib.write.exists.part1") + file
+                    + Config.getString("imagelib.write.exists.part2"), Config.getString("imagelib.write.exists.title"),
+                    JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null);
+
+            if (r == JOptionPane.OK_OPTION) {
+                writeAndEdit(im);
+            } else {
+                setVisible(false);
+            }
+        } else {
+            writeAndEdit(im);
+        }
+    }
+    
+    private void writeAndEdit(BufferedImage im)
+    {
+        try {
+            if (ImageIO.write(im, "png", file)) {
+                ExternalAppLauncher.editImage(file);
+                setVisible(false);
+            } else {
+                JOptionPane.showMessageDialog(this, "png " +
+                        Config.getString("imagelib.image.unsupportedformat.text"), Config.getString("imagelib.image.unsupportedformat.title"), JOptionPane.ERROR_MESSAGE);
+            }
+        }
+        catch (IOException ex) {
+            Debug.reportError("Error editing new image", ex);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/PopupMenuButton.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/PopupMenuButton.java
new file mode 100644
index 0000000000000000000000000000000000000000..a1c91489b6d3e938bdd07c1ab546c8f3616cb099
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/images/PopupMenuButton.java
@@ -0,0 +1,134 @@
+package greenfoot.gui.images;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JPopupMenu;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+
+/**
+ * Creates a button that can have a PopupMenu which will be
+ * displayed when the button is clicked on.
+ * 
+ * It's appearance is completely dependent on the icon provided.
+ * @author Philip Stevens
+ */
+public class PopupMenuButton extends JButton implements PopupMenuListener, MouseListener
+{
+    /** Holds the PopupMenu to be displayed on pressing this button. */
+    private JPopupMenu popupMenu;
+    
+    /**
+     * Initialises the button, setting up a mouse listener for when
+     * pressed on, or released (mouse pressed on something else). Also
+     * added a popup listener for the popup, to set display states.
+     * @param icon      Icon to show as the button.
+     * @param popupMenu PopupMenu to display when this button is clicked on.
+     */
+    public PopupMenuButton(Icon icon, JPopupMenu popupMenu)
+    {
+        super(icon);
+        this.popupMenu = popupMenu;
+        
+        // removes the blue hint that could appear around the icon
+        setBorder(null);
+        setContentAreaFilled(false);
+        setFocusable(false);
+        
+        // listeners for this, and the PopupMenu
+        popupMenu.addPopupMenuListener(this);
+        addMouseListener(this);
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see javax.swing.AbstractButton#fireActionPerformed(java.awt.event.ActionEvent)
+     */
+    protected void fireActionPerformed(ActionEvent actionEvent) 
+    {
+        super.fireActionPerformed(actionEvent);
+    }
+    
+    /*-------------------[ PopupMenuListener ]------------------------------*/
+    
+    /**
+     * Set the model's Armed and Pressed to true.
+     * @param e is ignored
+     */
+    @Override
+    public void popupMenuWillBecomeVisible(PopupMenuEvent e) 
+    {
+        getModel().setArmed(true);
+        getModel().setPressed(true);
+    }
+    
+    /**
+     * Set the model's Armed and Pressed to false.
+     * @param e is ignored
+     */
+    @Override
+    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) 
+    {
+        getModel().setArmed(false);
+        getModel().setPressed(false);
+    }
+
+    /**
+     * Ignored
+     */
+    @Override
+    public void popupMenuCanceled(PopupMenuEvent e) 
+    {
+    }
+    
+    /*-------------------[ MouseListener ]-----------------------------------*/
+    
+    /**
+     * Show the PopupMenu at the current position of this class.
+     * @param e is ignored
+     */
+    @Override
+    public void mousePressed(MouseEvent e) 
+    {
+        popupMenu.show(PopupMenuButton.this, 0, getHeight());
+    }
+
+    /**
+     * When mouse is released will close the PopupMenu.
+     * @param e is ignored
+     */
+    @Override
+    public void mouseReleased(MouseEvent e) 
+    {
+        fireActionPerformed(new ActionEvent(PopupMenuButton.this,
+                ActionEvent.ACTION_PERFORMED, ""));
+    }
+    
+    /**
+     * Ignored
+     */
+    @Override
+    public void mouseClicked(MouseEvent e) 
+    {
+    }
+    
+    /**
+     * Ignored
+     */
+    @Override
+    public void mouseEntered(MouseEvent e) 
+    {
+    }
+    
+    /**
+     * Ignored
+     */
+    @Override
+    public void mouseExited(MouseEvent e) 
+    {
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/InputManager.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/InputManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..22687d3b0c1bfca9a8c4ad153cd25b597b957605
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/InputManager.java
@@ -0,0 +1,321 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input;
+
+import greenfoot.Actor;
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+import greenfoot.event.TriggeredKeyAdapter;
+import greenfoot.event.TriggeredKeyListener;
+import greenfoot.event.TriggeredMouseAdapter;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionAdapter;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.event.WorldEvent;
+import greenfoot.event.WorldListener;
+import greenfoot.gui.input.states.ConstructorDragState;
+import greenfoot.gui.input.states.ConstructorDragWhileRunningState;
+import greenfoot.gui.input.states.DisabledState;
+import greenfoot.gui.input.states.IdleState;
+import greenfoot.gui.input.states.MoveState;
+import greenfoot.gui.input.states.QuickAddDragState;
+import greenfoot.gui.input.states.RunningState;
+import greenfoot.gui.input.states.State;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+
+import javax.swing.SwingUtilities;
+
+/**
+ * Manages which listeners gets input events (mouse/keyboard) from components at
+ * different times/states.
+ * <p>
+ * It works by forwarding events to the listeners that should receive events at
+ * the current state.
+ * <p>
+ * Not thread safe. Make sure to call methods from the event thread.
+ * @author Poul Henriksen
+ * 
+ */
+public class InputManager
+    implements SimulationListener, KeyListener, MouseListener, MouseMotionListener, WorldListener
+{
+    /** The current state */
+    private State state = null;
+
+    // The active listeners that will receive the events.
+    private TriggeredKeyListener activeKeyListener;
+    private TriggeredMouseListener activeMouseListener;
+    private TriggeredMouseMotionListener activeMouseMotionListener;
+    
+    /**
+     * Create a new input manager. Before using this object, the listeners
+     * should be initialized and the {@link #init()} method should be called.
+     * 
+     * @see #setMoveListeners(TriggeredKeyListener, TriggeredMouseListener,
+     *      TriggeredMouseMotionListener)
+     * @see #setDragListeners(TriggeredKeyListener, TriggeredMouseListener,
+     *      TriggeredMouseMotionListener)
+     * @see #setIdleListeners(TriggeredKeyListener, TriggeredMouseListener,
+     *      TriggeredMouseMotionListener)
+     * @see #setRunningListeners(TriggeredKeyListener, TriggeredMouseListener,
+     *      TriggeredMouseMotionListener)
+     * @see #init()
+     */
+    public InputManager()
+    {
+        State disabledState = DisabledState.initialize(this,  new TriggeredKeyAdapter(),  new TriggeredMouseAdapter(), new TriggeredMouseMotionAdapter());
+        switchAndActivateState(disabledState, null);
+    }
+
+    /**
+     * Set the listeners that should be active when the simulation is running.
+     * 
+     * @see #init()
+     */
+    public void setRunningListeners(TriggeredKeyListener runningKeyListener, TriggeredMouseListener runningMouseListener,
+            TriggeredMouseMotionListener runningMouseMotionListener)
+    {      
+        RunningState.initialize(this, runningKeyListener, runningMouseListener, runningMouseMotionListener);
+    }
+
+    /**
+     * Set the listeners that should be active when the application is idle.
+     * 
+     * @see #init()
+     */
+    public void setIdleListeners(TriggeredKeyListener idleKeyListener, TriggeredMouseListener idleMouseListener,
+            TriggeredMouseMotionListener idleMouseMotionListener)
+    {        
+        IdleState.initialize(this, idleKeyListener, idleMouseListener, idleMouseMotionListener);
+    }
+
+    /**
+     * Set the listeners that should be active when dragging a newly created
+     * object around.
+     * 
+     * @see #init()
+     */
+    public void setDragListeners(TriggeredKeyListener dragKeyListener, TriggeredMouseListener dragMouseListener,
+            TriggeredMouseMotionListener dragMouseMotionListener)
+    {
+        QuickAddDragState.initialize(this, dragKeyListener, dragMouseListener, dragMouseMotionListener);
+        ConstructorDragState.initialize(this, dragKeyListener, dragMouseListener, dragMouseMotionListener);
+        ConstructorDragWhileRunningState.initialize(this, dragKeyListener, dragMouseListener, dragMouseMotionListener);;
+    }
+
+    /**
+     * Set the listeners that should be active when moving an actor around that
+     * has been added to the world previously.
+     * 
+     * @see #init()
+     */
+    public void setMoveListeners(TriggeredKeyListener moveKeyListener, TriggeredMouseListener moveMouseListener,
+            TriggeredMouseMotionListener moveMouseMotionListener)
+    {
+        MoveState.initialize(this, moveKeyListener, moveMouseListener, moveMouseMotionListener);
+    }
+
+    /**
+     * Should be called after all listeners are correctly setup.
+     * 
+     * @see #setMoveListeners(TriggeredKeyListener, TriggeredMouseListener, TriggeredMouseMotionListener)
+     * @see #setDragListeners(TriggeredKeyListener, TriggeredMouseListener, TriggeredMouseMotionListener)
+     * @see #setIdleListeners(TriggeredKeyListener, TriggeredMouseListener, TriggeredMouseMotionListener)
+     * @see #setRunningListeners(TriggeredKeyListener, TriggeredMouseListener,
+     *      TriggeredMouseMotionListener)
+     * @throws IllegalStateException If some of the listeners has not been set up correctly.
+     */
+    public void init() throws IllegalStateException
+    {
+        // Make sure we fail now if we can't get all the states.
+        DisabledState.getInstance();
+        RunningState.getInstance();
+        MoveState.getInstance();
+        QuickAddDragState.getInstance();
+        ConstructorDragState.getInstance();
+        ConstructorDragWhileRunningState.getInstance();
+        
+        switchAndActivateState(IdleState.getInstance(), null);
+    }
+    
+    /**
+     * Deactivates the current listeners and enables the new ones. This method
+     * is called from the State classes when they are activated
+     */
+    public void activateListeners(TriggeredKeyListener keyL, TriggeredMouseListener mouseL, TriggeredMouseMotionListener mouseMotionL, Object obj) 
+    {
+        if (activeKeyListener != null) {
+            activeKeyListener.listeningEnded();
+        }
+        if (activeMouseListener != null) {
+            activeMouseListener.listeningEnded();
+        }
+        if (activeMouseMotionListener != null) {
+            activeMouseMotionListener.listeningEnded();
+        }
+        
+        activeKeyListener = keyL;
+        activeMouseListener = mouseL;
+        activeMouseMotionListener = mouseMotionL;
+
+        activeKeyListener.listeningStarted(obj);
+        activeMouseListener.listeningStarted(obj);
+        activeMouseMotionListener.listeningStarted(obj);
+    }
+    
+    /**
+     * Switches to the given state and activates it by calling the method
+     * {@link #activate()}.
+     * 
+     * @see #activate()
+     */
+    public void switchAndActivateState(State newState, Object obj)
+    {
+        state = newState;
+        state.activate(obj);
+    }
+    
+    /**
+     * Used for changing between running and stopped state.
+     */
+    public void simulationChanged(SimulationEvent e)
+    {
+        if (e.getType() == SimulationEvent.STARTED) {
+            state.switchToNextState(State.Event.SIMULATION_STARTED, null);
+        }
+        else if (e.getType() == SimulationEvent.STOPPED) {
+            state.switchToNextState(State.Event.SIMULATION_STOPPED, null);
+        }
+    }
+
+    /**
+     * When an actor is created via constructor the constructor in the context menu.
+     * @param object Object that has been added
+     */
+    public void objectCreated(Actor object)
+    {
+        state.switchToNextState(State.Event.CONSTRUCTOR_INVOKED, object);
+    }
+    
+
+    /**
+     * When an actor is created via constructor the constructor in the context menu.
+     * @param object Object that has been added
+     */
+    public void objectMoved(Actor object)
+    {
+        state.switchToNextState(State.Event.OBJECT_MOVED, object);
+    }
+
+    public void keyPressed(KeyEvent e)
+    {
+        if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
+            state.switchToNextState(State.Event.SHIFT_PRESSED, null);
+        }
+        activeKeyListener.keyPressed(e);
+    }
+
+    public void keyReleased(KeyEvent e)
+    {
+        activeKeyListener.keyReleased(e);
+        if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
+            state.switchToNextState(State.Event.SHIFT_RELEASED, null);
+        }
+    }
+
+    public void keyTyped(KeyEvent e)
+    {
+        activeKeyListener.keyTyped(e);
+    }
+
+    public void mouseClicked(MouseEvent e)
+    {
+        checkShift(e);
+        activeMouseListener.mouseClicked(e);
+    }
+
+    public void mousePressed(MouseEvent e)
+    {
+        checkShift(e);
+        activeMouseListener.mousePressed(e);
+        if (SwingUtilities.isLeftMouseButton(e) && !e.isShiftDown()) {
+            state.switchToNextState(State.Event.MOUSE_PRESSED, null);
+        }
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+        checkShift(e);
+        activeMouseListener.mouseReleased(e);
+        state.switchToNextState(State.Event.MOUSE_RELEASED, null);
+    }
+
+    public void mouseEntered(MouseEvent e)
+    {
+        checkShift(e);
+        activeMouseListener.mouseEntered(e);
+    }
+
+    public void mouseExited(MouseEvent e)
+    {
+        checkShift(e);
+        activeMouseListener.mouseExited(e);
+    }
+
+    /**
+     * Method that checks whether shift has been released without us noticing.
+     * It will then simulate that the shift key has been released.
+     */
+    private void checkShift(MouseEvent e)
+    {
+        if (state == QuickAddDragState.getInstance() && !e.isShiftDown()) {
+            state.switchToNextState(State.Event.SHIFT_RELEASED, null);
+        }
+    }
+
+    public void mouseDragged(MouseEvent e)
+    {
+        checkShift(e);
+        activeMouseMotionListener.mouseDragged(e);
+    }
+
+    public void mouseMoved(MouseEvent e)
+    {
+        checkShift(e);
+        activeMouseMotionListener.mouseMoved(e);
+    }
+
+    public void worldCreated(WorldEvent e)
+    {
+        state.switchToNextState(State.Event.WORLD_CREATED, null);
+    }
+
+    public void worldRemoved(WorldEvent e)
+    {
+        state.switchToNextState(State.Event.WORLD_REMOVED, null);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/KeyboardManager.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/KeyboardManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f2434bc5899cf211ebd42b37097d54febd5317f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/KeyboardManager.java
@@ -0,0 +1,399 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011,2012,2013  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input;
+
+import greenfoot.event.TriggeredKeyListener;
+
+import java.awt.Toolkit;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Manage keyboard input, to allow Greenfoot programs to poll for
+ * keystrokes. Keystrokes will be delivered on the GUI event thread,
+ * but may be polled from another thread.
+ * 
+ * <p>The following key names are recognized:
+ * up, down, left, right (cursor keys); enter, space, tab, escape, backspace,
+ * F1-F12.
+ * 
+ * @author Davin McCall
+ */
+public class KeyboardManager implements TriggeredKeyListener, FocusListener
+{
+    private String lastKeyTyped;
+
+    // We don't know how many virtual keys there are or what they are
+    // defined as. To allow checking arbitrary keys, we'll allocate an
+    // initial array size of 100, but increase it if we see a higher key
+    // code.
+    private int numKeys = 100;
+    private boolean [] keyLatched = new boolean[numKeys];
+    private boolean [] keyDown = new boolean[numKeys];
+
+    // The highest named key index
+    private int maxNamedKey = 0;
+    // The names of keys, for those keys we want to translate
+    private String [] keyNames;
+    
+    private Map<String,Integer> keyCodeMap;
+    
+    /** Do we think that a numlock key is present? */
+    private boolean hasNumLock = true;
+    
+    /**
+     * Constructor for a KeyboardManager. Key events must be delivered
+     * from an external source.
+     */
+    public KeyboardManager()
+    {
+        keyCodeMap = new HashMap<String,Integer>();
+        addAllKeys();
+        buildKeyNameArray();        
+    }
+    
+    /**
+     * Clear the latched state of keys which were down, but are no longer
+     * down.
+     */
+    public synchronized void clearLatchedKeys()
+    {
+        for (int i = 0; i < numKeys; i++) {
+            keyLatched[i] &= keyDown[i];
+        }
+    }
+    
+    /**
+     * Add all the keys which Greenfoot will directly support into the
+     * key code map (excluding keys with single-character names identifying
+     * the key, such as "a", "b" .. "z" and "0" .. "9", and other keys whose
+     * unicode value maps to their key code.
+     */
+    private void addAllKeys()
+    {
+        addKey("up", KeyEvent.VK_UP);
+        addKey("down", KeyEvent.VK_DOWN);
+        addKey("left", KeyEvent.VK_LEFT);
+        addKey("right", KeyEvent.VK_RIGHT);
+        addKey("space", KeyEvent.VK_SPACE);
+        addKey("enter", KeyEvent.VK_ENTER);
+        addKey("escape", KeyEvent.VK_ESCAPE);
+        addKey("F1", KeyEvent.VK_F1);
+        addKey("F2", KeyEvent.VK_F2);
+        addKey("F3", KeyEvent.VK_F3);
+        addKey("F4", KeyEvent.VK_F4);
+        addKey("F5", KeyEvent.VK_F5);
+        addKey("F6", KeyEvent.VK_F6);
+        addKey("F7", KeyEvent.VK_F7);
+        addKey("F8", KeyEvent.VK_F8);
+        addKey("F9", KeyEvent.VK_F9);
+        addKey("F10", KeyEvent.VK_F10);
+        addKey("F11", KeyEvent.VK_F11);
+        addKey("F12", KeyEvent.VK_F12);
+        addKey("backspace", KeyEvent.VK_BACK_SPACE);
+        addKey("\'", KeyEvent.VK_QUOTE);
+        addKey("shift", KeyEvent.VK_SHIFT);
+        addKey("control", KeyEvent.VK_CONTROL);
+    }
+    
+    /**
+     * Add a single key into the key code map. Adjust numKeys if necessary
+     * so that it can contain the given keycode.
+     * 
+     * @param keyName   The name of the key to add (Greenfoot name)
+     * @param keyCode   The key code of the key to add (Java key code)
+     */
+    private void addKey(String keyName, int keyCode)
+    {
+        keyCodeMap.put(keyName, keyCode);
+        if (keyCode + 1 > maxNamedKey) {
+            maxNamedKey = keyCode + 1;
+        }
+    }
+    
+    /**
+     * Build the three key arrays: keyLatched, keyDown, and keyNames.
+     */
+    private void buildKeyNameArray()
+    {
+        keyNames = new String[maxNamedKey];
+        Iterator<String> keyNamesIterator = keyCodeMap.keySet().iterator();
+        while (keyNamesIterator.hasNext()) {
+             String keyName = keyNamesIterator.next();
+             int keyCode = keyCodeMap.get(keyName);
+             keyNames[keyCode] = keyName;
+        }
+        
+        // remove from the keyNames table keys which will generate
+        // keyTyped events.
+        keyNames[KeyEvent.VK_SPACE] = null;
+        keyNames[KeyEvent.VK_ENTER] = null;
+        keyNames[KeyEvent.VK_ESCAPE] = null;
+        keyNames[KeyEvent.VK_TAB] = null;
+        keyNames[KeyEvent.VK_BACK_SPACE] = null;
+        keyNames[KeyEvent.VK_QUOTE] = null;
+    }
+        
+    
+    /**
+     * Make sure the key arrays are big enough to store information about
+     * the given key. Should be called from a synchronized context.
+     * 
+     * @param keycode  The keycode of the key to check.
+     */
+    private void checkKeyArrays(int keycode)
+    {
+        int nsize = keycode + 1;
+        if (nsize > numKeys) {
+            // we're seeing a new key code, increase array size
+            boolean [] newKeyLatched = new boolean[nsize];
+            boolean [] newKeyDown = new boolean[nsize];
+            for (int i = 0; i < numKeys; i++) {
+                newKeyLatched[i] = keyLatched[i];
+                newKeyDown[i] = keyDown[i];
+            }
+            keyLatched = newKeyLatched;
+            keyDown = newKeyDown;
+            numKeys = nsize;
+        }
+    }
+    
+    /**
+     * Get the last key pressed, as a String key name identifying the key.
+     */
+    public synchronized String getKey()
+    {
+        String r = lastKeyTyped;
+        lastKeyTyped = null;
+        return r;
+    }
+    
+    /**
+     * Check whether a key, identified by a virtual key code (int),
+     * is currently down (or latched).
+     * 
+     * @param keycode   The key code of the key to check
+     * @return        True if the key is currently down, or was down since
+     *                it was last checked; false otherwise.
+     */
+    public synchronized boolean isKeyDown(int keycode)
+    {
+        if (keycode < numKeys) {
+            boolean pressed = keyDown[keycode] || keyLatched[keycode];
+            keyLatched[keycode] = false;
+            return pressed;
+        }
+        else {
+            return false;
+        }
+    }
+    
+    /**
+     * Check whether a key, identified by name, is currently down
+     * (or latched).
+     * 
+     * @param keyId  The Greenfoot name for the key to check
+     * @return       True if the key is down, or was down since it was
+     *               last checked; false otherwise.
+     */
+    public boolean isKeyDown(String keyId)
+    {
+        Integer code = keyCodeMap.get(keyId);
+        if (code != null) {
+            return isKeyDown(code);
+        }
+        else {
+            // If the keyId is a single character, treat the unicode
+            // value of that character as a virtual key code. This is
+            // something of a hack, but it works for a range of keys.
+            if (keyId.codePointCount(0, keyId.length()) == 1) {
+                int keyChar = keyId.codePointAt(0);
+                keyChar = Character.toUpperCase(keyChar);
+                return isKeyDown(keyChar);
+            }
+            return false;
+        }
+    }
+    
+    // ----- KeyListener interface -----
+    
+    /*
+     * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
+     */
+    public synchronized void keyPressed(KeyEvent event)
+    {
+        int keyCode = event.getKeyCode();
+        pressKey(keyCode);
+    }
+
+    private void pressKey(int keyCode)
+    {
+        keyCode = numLockTranslate(keyCode);
+        checkKeyArrays(keyCode);
+        keyLatched[keyCode] = true;
+        keyDown[keyCode] = true;
+    }
+    
+    /*
+     * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
+     */
+    public synchronized void keyReleased(KeyEvent event)
+    {
+        int keyCode = event.getKeyCode();
+        releaseKey(keyCode);
+    }
+
+    private void releaseKey(int keyCode)
+    {
+        keyCode = numLockTranslate(keyCode);
+        checkKeyArrays(keyCode);
+        keyDown[keyCode] = false;
+        if (keyCode < maxNamedKey) {
+            String keyName = keyNames[keyCode];
+            if (keyName != null) {
+                lastKeyTyped = keyName;
+            }
+        }
+    }
+
+    public void listeningStarted(Object obj)
+    {       
+    }
+
+    public void listeningEnded()
+    {
+        releaseAllKeys();
+    }
+
+    /**
+     * Translate the "key pad" directional keys according to the status of numlock.
+     * 
+     * @param keycode  The original keycode
+     * @return   The translated keycode
+     */
+    private int numLockTranslate(int keycode)
+    {
+        if (keycode >= KeyEvent.VK_NUMPAD0 && keycode <= KeyEvent.VK_NUMPAD9) {
+            // At least on linux, we can only get these codes if numlock is on; in that
+            // case we want to map to a digit anyway.
+            return keycode - KeyEvent.VK_NUMPAD0 + KeyEvent.VK_0;
+        }
+
+        // Seems on linux (at least) we can't get the numlock state (get an
+        // UnsupportedOperationException). Update: on Java 1.7.0_03 at least,
+        // we can now retrieve numlock state on linux.
+        boolean numlock = true;
+        if (hasNumLock) {
+            try {
+                numlock = Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_NUM_LOCK);
+            }
+            catch (UnsupportedOperationException usoe) {
+                // Don't try to get numlock status again
+                hasNumLock = false;
+            }
+        }
+
+        if (numlock) {
+            // Translate to digit
+            if (keycode == KeyEvent.VK_KP_UP) {
+                keycode = KeyEvent.VK_8;
+            }
+            else if (keycode == KeyEvent.VK_KP_DOWN) {
+                keycode = KeyEvent.VK_2;
+            }
+            else if (keycode == KeyEvent.VK_KP_LEFT) {
+                keycode = KeyEvent.VK_4;
+            }
+            else if (keycode == KeyEvent.VK_KP_RIGHT) {
+                keycode = KeyEvent.VK_6;
+            }
+        }
+        else {
+            // Translate to direction
+            if (keycode == KeyEvent.VK_KP_UP) {
+                keycode = KeyEvent.VK_UP;
+            }
+            else if (keycode == KeyEvent.VK_KP_DOWN) {
+                keycode = KeyEvent.VK_DOWN;
+            }
+            else if (keycode == KeyEvent.VK_KP_LEFT) {
+                keycode = KeyEvent.VK_LEFT;
+            }
+            else if (keycode == KeyEvent.VK_KP_RIGHT) {
+                keycode = KeyEvent.VK_RIGHT;
+            }
+        }
+        return keycode;
+    }
+    
+    /*
+     * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
+     */
+    @Override
+    public synchronized void keyTyped(KeyEvent key)
+    {
+        char c = key.getKeyChar();
+        if (c == '\n' || c == '\r') {
+            lastKeyTyped = "enter";
+        }
+        else if (c == '\t') {
+            lastKeyTyped = "tab";
+        }
+        else if (c == '\b') {
+            lastKeyTyped = "backspace";
+        }
+        else if (c == ' ') {
+            lastKeyTyped = "space";
+        }
+        else if (c == 27) {
+            lastKeyTyped = "escape";
+        }
+        else {
+            lastKeyTyped = "" + c;
+        }
+    }
+
+    public void focusGained(FocusEvent e) { }
+
+    /**
+     * If we loose focus, we should treat all keys as not pressed anymore
+     */
+    public void focusLost(FocusEvent e)
+    {
+        releaseAllKeys();
+    }
+
+    /**
+     * Release all the keys.
+     */
+    private synchronized void releaseAllKeys()
+    {
+        for (int keyCode = 0; keyCode < keyDown.length; keyCode++) {
+            keyDown[keyCode] = false;
+            keyLatched[keyCode] = false;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/LocationTracker.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/LocationTracker.java
new file mode 100644
index 0000000000000000000000000000000000000000..80d124e7a5d1e99b7f7dda8a83144a328a5bfcda
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/LocationTracker.java
@@ -0,0 +1,177 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.mouse;
+
+import greenfoot.core.WorldHandler;
+import greenfoot.gui.WorldCanvas;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.Toolkit;
+import java.awt.event.AWTEventListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+
+import javax.swing.SwingUtilities;
+
+/**
+ * This singleton keeps track of mouse events. It listens for both mouse motion
+ * and mouse clicks.
+ * 
+ * A location will always be returned.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class LocationTracker
+{
+    private static LocationTracker instance;
+    private MouseEvent mouseButtonEvent;
+    private Component sourceComponent;
+    private MouseEvent mouseMovedEvent;
+
+    static {
+        instance();
+    }
+
+
+    /**
+     * Needed for running in applets.
+     *
+     */
+    public static void initialize()
+    {
+        MouseMotionAdapter mma = new MouseMotionAdapter() {
+            @Override
+            public void mouseMoved(MouseEvent e)
+            {
+                LocationTracker.instance().move(e);
+            }
+            
+            @Override
+            public void mouseDragged(MouseEvent e)
+            {
+            }
+        };
+        MouseAdapter ma = new MouseAdapter() {
+            @Override
+            public void mouseClicked(MouseEvent e)
+            {
+                LocationTracker.instance().click(e);
+            }
+            
+        };
+
+        WorldCanvas canvas = WorldHandler.getInstance().getWorldCanvas();
+        canvas.addMouseListener(ma);
+        canvas.addMouseMotionListener(mma);
+    }
+    
+    private LocationTracker()
+    {
+        try {
+            AWTEventListener listener = new AWTEventListener() {
+                public void eventDispatched(AWTEvent event)
+                {
+                    MouseEvent me = (MouseEvent) event;
+                    if ((event.getID() & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0) {
+                        LocationTracker.instance().move(me);
+                    }
+                    if ((event.getID() & AWTEvent.MOUSE_EVENT_MASK) != 0) {
+                        LocationTracker.instance().click(me);
+                    }
+                }
+            };
+            Toolkit.getDefaultToolkit().addAWTEventListener(listener,
+                    AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
+        }
+        catch (SecurityException e) {
+            // Probably running in an applet, so it should already be
+            // initialised to listen for mouse events.
+        }
+
+    }
+
+    public synchronized static LocationTracker instance()
+    {
+        if (instance == null) {
+            instance = new LocationTracker();
+        }
+        return instance;
+    }
+
+    /**
+     * Gets the last MouseEvent where a mouse button was used.
+     */
+    public MouseEvent getMouseButtonEvent()
+    {
+        return mouseButtonEvent;
+    }
+
+    /**
+     * Gets the last MouseEvent generated by a mouse motion.
+     */
+    public MouseEvent getMouseMotionEvent()
+    {
+        return mouseMovedEvent;
+
+    }
+
+    /**
+     * Updates last motion event.
+     */
+    private void move(MouseEvent e)
+    {
+        mouseMovedEvent = translateEvent(e);
+    }
+
+    /**
+     * Updates last click position.
+     */
+    private void click(MouseEvent e)
+    {
+        mouseButtonEvent = translateEvent(e);
+    }
+
+    /**
+     * Translate the event coordinates into those of the source sourceComponent
+     * of the LocationTracker.
+     * 
+     */
+    private MouseEvent translateEvent(MouseEvent e)
+    {
+        Component source = e.getComponent();
+        if (source != sourceComponent) {
+            e = SwingUtilities.convertMouseEvent(source, e, sourceComponent);
+        }
+        return e;
+    }
+
+    /**
+     * Sets the sourceComponent that all locations will be relative to.
+     */
+    public void setSourceComponent(Component source)
+    {
+        this.sourceComponent = source;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/MouseEventData.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/MouseEventData.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f169f459c006e56dde116e02b7662b4cbccae4d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/MouseEventData.java
@@ -0,0 +1,224 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.mouse;
+
+
+import greenfoot.Actor;
+import greenfoot.MouseInfo;
+import greenfoot.MouseInfoVisitor;
+import greenfoot.World;
+
+
+/**
+ * Class to hold data collected from the mouse events. Using MouseInfo is
+ * not enough, since a mouse info object doesn't contain all the info we
+ * need (whether it was a drag, move, etc)
+ * @author Poul Henriksen
+ * 
+ */
+class MouseEventData
+{
+    private MouseInfo mouseInfo;
+    
+    // We need to hold the data for each individual action that might have
+    // happened, because what to report depends on what we are interested in,
+    // with relation to the actor, world or globally.
+    private MouseInfo mouseDragEndedInfo;
+    private MouseInfo mouseClickedInfo;
+    private MouseInfo mousePressedInfo;
+    private MouseInfo mouseDraggedInfo;
+    private MouseInfo mouseMovedInfo;
+
+    public void init()
+    {
+        mousePressedInfo = null;
+        mouseClickedInfo = null;
+        mouseDraggedInfo = null;
+        mouseDragEndedInfo = null;
+        mouseMovedInfo = null;
+        if (mouseInfo != null)
+        {
+            MouseInfo blankedMouseInfo = MouseInfoVisitor.newMouseInfo();
+            // Only retain info on latest location, not clicks etc:
+            MouseInfoVisitor.setLoc(blankedMouseInfo, mouseInfo.getX(), mouseInfo.getY());
+            mouseInfo = blankedMouseInfo;
+        }
+        
+    }
+    
+    public MouseInfo getMouseInfo()
+    {
+        return mouseInfo;
+    }
+
+    public boolean isMousePressed(Object obj)
+    {
+        return checkObject(obj, mousePressedInfo);
+    }
+
+    public void mousePressed(int x, int y, int button, Actor actor)
+    {
+        init();
+        mousePressedInfo = MouseInfoVisitor.newMouseInfo();
+        mouseInfo = mousePressedInfo;  
+        MouseInfoVisitor.setButton(mouseInfo, button);
+        MouseInfoVisitor.setLoc(mouseInfo, x, y);
+        MouseInfoVisitor.setActor(mouseInfo, actor);
+    }
+
+    public boolean isMouseClicked(Object obj)
+    { 
+        // if the mouse was pressed outside the object we are looking for, it
+        // can't be clicked on that object
+        if(obj != null && (isMousePressed(null) && !isMousePressed(obj))) {
+            return false;
+        }
+        return checkObject(obj, mouseClickedInfo);
+    }
+    
+    public void mouseClicked(int x, int y, int button, int clickCount, Actor actor)
+    {
+        MouseInfo tempPressedInfo = mousePressedInfo;        
+        init();       
+        mousePressedInfo = tempPressedInfo;
+        
+        mouseClickedInfo = MouseInfoVisitor.newMouseInfo();;
+        mouseInfo = mouseClickedInfo;
+        MouseInfoVisitor.setButton(mouseInfo, button);
+        MouseInfoVisitor.setLoc(mouseInfo, x, y);
+        MouseInfoVisitor.setActor(mouseInfo, actor);
+        MouseInfoVisitor.setClickCount(mouseInfo, clickCount);
+    }
+
+    public boolean isMouseDragged(Object obj)
+    {
+        return checkObject(obj, mouseDraggedInfo);
+    }
+
+    public void mouseDragged(int x, int y, int button, Actor actor)
+    {
+        init();
+        mouseDraggedInfo = MouseInfoVisitor.newMouseInfo();
+        mouseInfo = mouseDraggedInfo;
+        MouseInfoVisitor.setButton(mouseInfo, button);
+        MouseInfoVisitor.setLoc(mouseInfo, x, y);
+        MouseInfoVisitor.setActor(mouseInfo, actor);
+    }
+
+    public boolean isMouseDragEnded(Object obj)
+    {
+        return checkObject(obj, mouseDragEndedInfo);
+    }
+
+    public void mouseDragEnded(int x, int y, int button, Actor actor)
+    {
+        MouseInfo tempPressedInfo = mousePressedInfo;
+        MouseInfo tempClickedInfo = mouseClickedInfo;
+        init();
+        mousePressedInfo = tempPressedInfo;
+        mouseClickedInfo = tempClickedInfo;
+        mouseDragEndedInfo = MouseInfoVisitor.newMouseInfo();;
+        mouseInfo = mouseDragEndedInfo;
+        MouseInfoVisitor.setButton(mouseInfo, button);
+        MouseInfoVisitor.setLoc(mouseInfo, x, y);
+        MouseInfoVisitor.setActor(mouseInfo, actor);
+    }
+
+    public void mouseExited()
+    {
+        mouseInfo = mouseDraggedInfo;
+        mouseMovedInfo = null;
+    }
+    
+    public boolean isMouseMoved(Object obj)
+    {
+        return checkObject(obj, mouseMovedInfo);
+    }
+
+    public void mouseMoved(int x, int y, int button, Actor actor)
+    {
+        init();
+        mouseMovedInfo = MouseInfoVisitor.newMouseInfo();;
+        mouseInfo = mouseMovedInfo;
+        MouseInfoVisitor.setButton(mouseInfo, button);
+        MouseInfoVisitor.setLoc(mouseInfo, x, y);
+        MouseInfoVisitor.setActor(mouseInfo, actor);
+    }
+
+    public Actor getActor()
+    {
+        if(mouseInfo == null) {
+            return null;
+        }
+        return mouseInfo.getActor();
+    }
+
+    public int getButton()
+    {
+        if(mouseInfo == null) {
+            return 0;
+        }
+        return mouseInfo.getButton();
+    }
+    
+    /**
+     * Check whether the given object can be considered to match the MouseInfo.
+     * 
+     * @param obj The query
+     * @param info To check against
+     * @return
+     */
+    private boolean checkObject(Object obj, MouseInfo info)
+    {
+        if(info == null) {
+            return false;
+        }
+        Actor actor = info.getActor();
+        return obj == null || (obj instanceof World && actor == null) || actor == obj;
+    }
+
+    
+    public String toString()
+    {
+        String s = "MouseEventData ";
+        if(mouseInfo != null) {
+            s += mouseInfo.toString();
+        }
+        if(mousePressedInfo != null) {
+            s += " pressed";
+        }
+        if(mouseClickedInfo != null) {
+            s += " clicked";
+        }
+        if(mouseDraggedInfo != null) {
+            s += " dragged";
+        }
+        if(mouseDragEndedInfo != null) {
+            s += " dragEnded";
+        }
+        if(mouseMovedInfo != null) {
+            s += " moved";
+        }
+        return s;
+    }
+ 
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/MousePollingManager.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/MousePollingManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..ddf2f28e90d22dcf2e1919efa345dd25873470a6
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/MousePollingManager.java
@@ -0,0 +1,482 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.mouse;
+
+import greenfoot.Actor;
+import greenfoot.MouseInfo;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.gui.input.mouse.MouseEventData;
+
+import java.awt.event.MouseEvent;
+
+import bluej.Config;
+
+/**
+ * There are two ways that the mouse can be handled in Greenfoot. One is the
+ * built-in mouse support like it was in Greenfoot release 1.3.0 and earlier.
+ * This still works the same way in newer Greenfoot versions as long as the
+ * simulation is not running. When the simulation is running there is no default
+ * mouse support for dragging objects already added into the world. When the
+ * simulation is running the user classes have to poll for mouse information
+ * through the greenfoot.Greenfoot class.
+ * <p>
+ * MouseEvents are collected in frames. A frame is defined as the interval
+ * between the first poll of anything in the previous act-round to the first
+ * poll in the current act-round.
+ * <p>
+ * When the first poll in an act loop happens, the future mouse data is copied
+ * into current mouseInfo and the creation of a new future mouse data object is
+ * started.
+ * <p>
+ * 
+ * If several events happen in the same frame the events are prioritized like
+ * this: <br>
+ * Priorities with highest priority first:
+ * <ul>
+ * <li> dragEnd </li>
+ * <li> click </li>
+ * <li> press </li>
+ * <li> drag </li>
+ * <li> move </li>
+ * </ul>
+ * 
+ * In general only one event can happen in a frame, the only exception is click
+ * and press which could happen in the same frame if a mouse is clicked in one
+ * frame. <br>
+ * If several of the same type of event happens, then the last one is used.
+ * <p>
+ * If, for instance, two buttons are pressed at the same time, the behaviour is
+ * undefined. Maybe we should define it so that button1 always have higher
+ * priority than button2 and button2 always higher than button3. But not
+ * necessarily documenting this to the user.
+ * 
+ * @author Poul Henriksen
+ */
+public class MousePollingManager implements TriggeredMouseListener, TriggeredMouseMotionListener
+{
+    /*
+     * Methods in this class are called from two threads: the simulation thread and the
+     * GUI even thread. Some methods are called by one and some by the other; the GUI produces
+     * the data while the simulation consumes it.
+     * 
+     * A small number of fields can be accessed be either thread and so access to them must
+     * be synchronized. Other fields are accessed by only one thread or the other.
+     */
+    
+    /**
+     * The current mouse data This will be the mouse info returned for the rest
+     * of this act loop.
+     * 
+     * <p>Accessed only from the simulation thread.
+     */
+    private MouseEventData currentData = new MouseEventData();
+
+    /**
+     * The future mouse data is build up from mouse events happening from the
+     * first time the user requested mouse info in this act loop, until the user
+     * requests again in the next act-loop, at which point the future will
+     * become the current.
+     * 
+     * <p>Access to this field must be synchronized.
+     */
+    private MouseEventData futureData = new MouseEventData();
+    
+    /**
+     * Used to collect data if we already have a highest priority dragEnded
+     * collected. We need this in order to collect data for a potential new
+     * dragEnd since we want to report the latest dragEnd in case there are more
+     * than one.
+     * 
+     * <p>Access to this field must be synchronized.
+     */
+    private MouseEventData potentialNewDragData = new MouseEventData();
+    
+    /**
+     * Locates the actors in the world (read only field, requires no synchronization).
+     */
+    private WorldLocator locator;
+
+    /**
+     * Keeps track of where a drag started. This should never be explicitly set
+     * to null, because it might result in exceptions when doing undefined
+     * things like dragging with two buttons down at the same time.
+     * 
+     * <p>Accessed only from the GUI thread.
+     */
+    private MouseEventData dragStartData = new MouseEventData();
+
+    /**
+     * Track whether the mouse is currently being dragged.
+     * 
+     * <p>Accessed only from the GUI thread.
+     */
+    private boolean isDragging;
+
+    /**
+     * Whether we have received more mouse data since we last gave data to the simulation.
+     * 
+     * <p>Access to this field must be synchronized.
+     */
+    private boolean gotNewEvent;
+    
+
+    /**
+     * Creates a new mouse manager. The mouse manager should be notified
+     * whenever a new act round starts by calling {@link #newActStarted()}.
+     * 
+     * @param locator
+     *            Used to locate things (actors and coordinates) within the
+     *            World. May be null, but in that case the locator must be set
+     *            later.
+     */
+    public MousePollingManager(WorldLocator locator) 
+    {
+        this.locator = locator;
+    }
+    
+    /**
+     * Set the locator to be used by this mouse polling manager.
+     */
+    public void setWorldLocator(WorldLocator locator)
+    {
+        this.locator = locator;
+    }
+    
+    /**
+     * This method should be called when a new act-loop is started.
+     */
+    public synchronized void newActStarted()
+    {
+        // The current data was already polled, or we have a new event since;
+        // use futureData as our current data. (If there's been no event, i.e. if
+        // gotNewEvent is false, futureData will contain no events).
+        if (gotNewEvent) {
+            MouseEventData newData = new MouseEventData();
+            currentData = futureData;
+            futureData = newData;
+            potentialNewDragData = new MouseEventData();
+    
+            // Indicate that we have processed all current events.
+            gotNewEvent = false;
+        }
+        else {
+            currentData.init();
+        }
+    }
+
+    /**
+     * This method should be called every time we receive a mouse event. It is
+     * used to keep track of whether any events have been occurring in this
+     * frame.
+     * 
+     * <p>This must be called from a synchronized context.
+     */
+    private void registerEventRecieved()
+    {
+        gotNewEvent = true;
+    }
+    
+    
+
+    // ************************************
+    // Methods available to the user
+    // ************************************
+
+    /**
+     * Whether the mouse had been pressed (changed from a non-pressed state to
+     * being pressed) on the given object. If the parameter is an Actor the
+     * method will only return true if the mouse has been pressed on the given
+     * actor - if there are several actors at the same place, only the top most
+     * actor will count. If the parameter is a World then true will be returned
+     * only if the mouse was pressed outside the boundaries of all Actors. If
+     * the parameter is null, then it will return true no matter where the mouse
+     * was pressed as long as it is inside the world boundaries.
+     * 
+     * @param obj Typically one of Actor, World or null
+     * @return True if the mouse has been pressed as explained above
+     */
+    public boolean isMousePressed(Object obj)
+    {
+        return currentData.isMousePressed(obj);
+    }
+
+    /**
+     * Whether the mouse had been clicked (pressed and released) on the given
+     * object. If the parameter is an Actor the method will only return true if
+     * the mouse has been clicked on the given actor - if there are several
+     * actors at the same place, only the top most actor will count. If the
+     * parameter is a World then true will be returned only if the mouse was
+     * clicked outside the boundaries of all Actors. If the parameter is null,
+     * then it will return true no matter where the mouse was clicked as long as
+     * it is inside the world boundaries.
+     * 
+     * @param obj Typically one of Actor, World or null
+     * @return True if the mouse has been clicked as explained above
+     */
+    public boolean isMouseClicked(Object obj)
+    {
+        return currentData.isMouseClicked(obj);
+    }
+
+    /**
+     * Whether the mouse is being dragged on the given object. The mouse is
+     * considered to be dragged on an object, only if the drag started on that
+     * object - even if the mouse has since been moved outside of that object.
+     * <p>
+     * If the parameter is an Actor the method will only return true if the drag
+     * started on the given actor - if there are several actors at the same
+     * place, only the top most actor will count. If the parameter is a World
+     * then true will be returned only if the drag was started outside the
+     * boundaries of all Actors. If the parameter is null, then it will return
+     * true no matter where the drag was started as long as it is inside the
+     * world boundaries.
+     * 
+     * @param obj Typically one of Actor, World or null
+     * @return True if the mouse has been pressed as explained above
+     */
+    public boolean isMouseDragged(Object obj)
+    {
+        return currentData.isMouseDragged(obj);
+    }
+
+    /**
+     * A mouse drag has ended. This happens when the mouse has been dragged and
+     * the mouse button released.
+     * <p>
+     * If the parameter is an Actor the method will only return true if the drag
+     * started on the given actor - if there are several actors at the same
+     * place, only the top most actor will count. If the parameter is a World
+     * then true will be returned only if the drag was started outside the
+     * boundaries of all Actors. If the parameter is null, then it will return
+     * true no matter where the drag was started as long as it is inside the
+     * world boundaries.
+     * 
+     * 
+     * @param obj Typically one of Actor, World or null
+     * @return True if the mouse has been pressed as explained above
+     */
+    public boolean isMouseDragEnded(Object obj)
+    {
+        return currentData.isMouseDragEnded(obj);
+    }
+
+    /**
+     * Whether the mouse had been moved on the given object. The mouse is
+     * considered to be moved on an object, only if the mouse pointer is above that
+     * object.
+     * <p>
+     * If the parameter is an Actor the method will only return true if the move
+     * is on the given actor - if there are several actors at the same
+     * place, only the top most actor will count. If the parameter is a World
+     * then true will be returned only if the move is outside the
+     * boundaries of all Actors. If the parameter is null, then it will return
+     * true no matter where the drag was started as long as it is inside the
+     * world boundaries.
+     * 
+     * @param obj Typically one of Actor, World or null
+     * @return True if the mouse has been moved as explained above
+     */
+    public boolean isMouseMoved(Object obj)
+    {
+        return currentData.isMouseMoved(obj);
+    }
+
+    /**
+     * Gets the mouse info with information about the current state of the
+     * mouse. Within the same act-loop it will always return exactly the same
+     * MouseInfo object with exactly the same contents.
+     * 
+     * @return The info about the current state of the mouse; Null if the mouse is outside
+     *         the world boundaries (unless being dragged).
+     */
+    public MouseInfo getMouseInfo()
+    {
+        return currentData.getMouseInfo();
+    }   
+
+    // ************************************
+    // Implementations of listeners.
+    // ************************************
+
+    public void mouseClicked(MouseEvent e)
+    {
+        // This line must go outside the synchronized block because it involves
+        // claiming a read-lock on the world, which can cause a deadlock because
+        // the simulation thread can synchronize on futureData (in freezeMouseData())
+        // while holding the world write-lock (which would leave the two threads with
+        // one lock each, both trying to claim the other):
+        Actor actor = locator.getTopMostActorAt(e);
+        synchronized (this) {
+            MouseEventData mouseData = futureData;
+            // In case we already have a dragEnded and we get another
+            // dragEnded, we need to start collection data for that.            
+            if (futureData.isMouseDragEnded(null)) {
+                mouseData = potentialNewDragData;
+            }
+            if(! PriorityManager.isHigherPriority(e, mouseData)) return;
+            registerEventRecieved();
+            int x = locator.getTranslatedX(e);
+            int y = locator.getTranslatedY(e);
+            int button = getButton(e);
+            
+            mouseData.mouseClicked(x, y, button, e.getClickCount(), actor);
+            isDragging = false;
+        }
+    }
+
+    /**
+     * Gets the button for the mouse event. This will also translate CTRL-clicks
+     * on mac into mouse button three. Doesn't work for drag events.
+     */
+    private int getButton(MouseEvent e)
+    {
+        int button = e.getButton();
+        if (Config.isMacOS() && button == MouseEvent.BUTTON1) {
+            // Simulate right click on Macs that use CTRL click for right
+            // clicks. Would be nice if we could use isPopupTrigger instead, but
+            // that only works for mouse pressed.
+            if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == MouseEvent.CTRL_DOWN_MASK) {
+                button = MouseEvent.BUTTON3;
+            }
+        }
+        return button;
+    }
+
+    public void mouseEntered(MouseEvent e)
+    {
+    }
+
+    public void mouseExited(MouseEvent e)
+    {
+        synchronized (this) {
+            futureData.mouseExited();
+        }
+    }
+
+    public void mousePressed(MouseEvent e)
+    {
+        // This line must go outside the synchronized block because it involves
+        // claiming a read-lock on the world, which can cause a deadlock because
+        // the simulation thread can synchronize on futureData (in freezeMouseData())
+        // while holding the world write-lock (which would leave the two threads with
+        // one lock each, both trying to claim the other):
+        Actor actor = locator.getTopMostActorAt(e);
+        synchronized(this) {
+            MouseEventData mouseData = futureData;
+            // In case we already have a dragEnded and we get another
+            // dragEnded, we need to start collection data for that.
+            if (futureData.isMouseDragEnded(null)) {
+                mouseData = potentialNewDragData;
+            }
+        
+            // This might be the beginning of a drag so we store it
+            dragStartData = new MouseEventData();
+            int x = locator.getTranslatedX(e);
+            int y = locator.getTranslatedY(e);
+            int button = getButton(e);
+            dragStartData.mousePressed(x, y, button, actor);            
+
+            // We only really want to register this event as a press if there is no higher priorities
+            if(! PriorityManager.isHigherPriority(e, mouseData)) return;
+            registerEventRecieved();
+            mouseData.mousePressed(x, y, button, actor);
+            isDragging = false;
+        }
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+        // This line must go outside the synchronized block because it involves
+        // claiming a read-lock on the world, which can cause a deadlock because
+        // the simulation thread can synchronize on futureData (in freezeMouseData())
+        // while holding the world write-lock (which would leave the two threads with
+        // one lock each, both trying to claim the other):
+        Actor clickActor = locator.getTopMostActorAt(e);
+        synchronized(this) {
+            // This might be the end of a drag
+            if(isDragging) {
+                // In case we already have a dragEnded and we get another
+                // dragEnded, should use the new one
+                if (futureData.isMouseDragEnded(null)) {
+                    futureData = potentialNewDragData;
+                }
+                
+                if(! PriorityManager.isHigherPriority(e, futureData)) return;
+                registerEventRecieved();
+                int x = locator.getTranslatedX(e);
+                int y = locator.getTranslatedY(e);
+                int button = getButton(e);
+
+                futureData.mouseClicked(x, y, button, 1, clickActor);
+                
+                Actor actor = dragStartData.getActor();
+                futureData.mouseDragEnded(x, y, button, actor);
+                isDragging = false;
+                potentialNewDragData = new MouseEventData();
+            }
+        }
+    }
+
+    public void mouseDragged(MouseEvent e)
+    {
+        synchronized(this) {
+            isDragging = true;
+            
+            if(! PriorityManager.isHigherPriority(e, futureData)) return;
+            registerEventRecieved();
+            
+            // Find and store the actor that relates to this drag.
+            int x = locator.getTranslatedX(e);
+            int y = locator.getTranslatedY(e);
+            futureData.mouseDragged(x, y, dragStartData.getButton(), dragStartData.getActor());
+        }
+    }
+
+    public void mouseMoved(MouseEvent e)
+    {
+        // This line must go outside the synchronized block because it involves
+        // claiming a read-lock on the world, which can cause a deadlock because
+        // the simulation thread can synchronize on futureData (in freezeMouseData())
+        // while holding the world write-lock (which would leave the two threads with
+        // one lock each, both trying to claim the other):
+        Actor actor = locator.getTopMostActorAt(e);
+        synchronized(this) {
+            if(! PriorityManager.isHigherPriority(e, futureData)) return;
+            registerEventRecieved();
+            int x = locator.getTranslatedX(e);
+            int y = locator.getTranslatedY(e);
+            int button = getButton(e);
+            futureData.mouseMoved(x, y, button, actor);
+            isDragging = false;
+        }
+    }
+
+    public void listeningEnded()
+    {
+    }
+
+    public void listeningStarted(Object obj)
+    {
+    }   
+}
+
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/PriorityManager.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/PriorityManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..eaff413cd5da1cafb99b28b8cab236af7b732304
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/PriorityManager.java
@@ -0,0 +1,111 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.mouse;
+
+import java.awt.event.MouseEvent;
+
+/**
+ * This class resolves the priorities of mouse events for the MousePollingManager.
+ * <p>
+ *
+ * Priorities with highest priority first::
+ * <ul>
+ * <li> dragEnd </li>
+ * <li> click </li>
+ * <li> press </li>
+ * <li> drag </li>
+ * <li> move </li>
+ * </ul>
+ * 
+ * If several of the same type of event happens, then the last one is used.
+ * <p>
+ * If two buttons are pressed at the same time, the behaviour is
+ * undefined. Maybe we should define it so that button1 always have higher
+ * priority than button2 and button2 always higher than button3. But not
+ * necessarily documenting this to the user.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class PriorityManager
+{
+    /**
+     * Returns true if the new mouse event has higher or equal priority than the current.
+     * @param newEven
+     * @param currentData
+     * @return
+     */
+    public static boolean isHigherPriority(MouseEvent newEvent, MouseEventData currentData)
+    {
+        int currentPriority = getPriority(currentData);
+        int newPriority = getPriority(newEvent);
+        return newPriority <= currentPriority;
+    }
+    /**
+     * Priority 0 is highest.
+     * @param event
+     * @return
+     */
+    private static int getPriority(MouseEvent event)
+    {
+        if(event.getID() == MouseEvent.MOUSE_RELEASED) {
+            return 0;
+        }
+        else if(event.getID() == MouseEvent.MOUSE_CLICKED) {
+            return 1;
+        }
+        else if(event.getID() == MouseEvent.MOUSE_PRESSED) {
+            return 2;
+        }
+        else if(event.getID() == MouseEvent.MOUSE_DRAGGED) {
+            return 3;
+        }
+        else if(event.getID() == MouseEvent.MOUSE_MOVED) {
+            return 4;
+        }
+        else {
+            return Integer.MAX_VALUE;
+        }
+    }
+
+    private static int getPriority(MouseEventData data)
+    {
+        if(data.isMouseDragEnded(null)) {
+            return 0;
+        }
+        else if(data.isMouseClicked(null)) {
+            return 1;
+        }
+        else if(data.isMousePressed(null)) {
+            return 2;
+        }
+        else if(data.isMouseDragged(null)) {
+            return 3;
+        }
+        else if(data.isMouseMoved(null)) {
+            return 4;
+        }
+        else {
+            return Integer.MAX_VALUE;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/WorldLocator.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/WorldLocator.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a4f25ecdd614ac5512d2cc896988db8fad98557
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/mouse/WorldLocator.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.mouse;
+
+import java.awt.event.MouseEvent;
+
+import greenfoot.Actor;
+
+
+/**
+ * Interface for locating actors and coordinates in the world.
+ * 
+ * @author Poul Henriksen
+ */
+public interface WorldLocator
+{
+    /**
+     * Gets the top most actor at the given location.
+     * @param e TODO
+     * @return The top most actor, or null if no actor.
+     */
+    public Actor getTopMostActorAt(MouseEvent e);
+
+    /**
+     * Translates the coordinates from the given source component into some other coordinate system.
+     * @param e The event from which the x-coordinate should be translated
+     * @return The new x-coordinate
+     */
+    public int getTranslatedX(MouseEvent e);
+    
+
+    /**
+     * Translates the coordinates from the given source component into some other coordinate system.
+     * @param e The event from which the y-coordinate should be translated
+     * @return The new y-coordinate
+     */
+    public int getTranslatedY(MouseEvent e);
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/ConstructorDragState.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/ConstructorDragState.java
new file mode 100644
index 0000000000000000000000000000000000000000..b85f179c004bf53f60436310ecb6085436a4bf4e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/ConstructorDragState.java
@@ -0,0 +1,75 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.states;
+
+import greenfoot.event.TriggeredKeyListener;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.gui.input.InputManager;
+
+/**
+ * This state is active when the constructor of an Actor has been invoked via
+ * the context-menu of the Actor. Works only while the simulation is stopped,
+ * but there is another state {@link ConstructorDragWhileRunningState} which
+ * handles the same case when the simulation is running.
+ * 
+ * @author Poul Henriksen
+ */
+public class ConstructorDragState extends State
+{
+    protected static ConstructorDragState instance;
+
+    public static synchronized ConstructorDragState getInstance() throws IllegalStateException
+    {
+        if (instance == null) {
+            throw new IllegalStateException("Not initialized.");
+        }
+        return instance;
+    }
+    
+    private ConstructorDragState(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        super(inputManager, keyListener, mouseListener, mouseMotionListener);
+    }
+
+    public static synchronized ConstructorDragState initialize(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        instance = new ConstructorDragState(inputManager, keyListener, mouseListener, mouseMotionListener);
+        return instance;
+    }
+
+    @Override
+    public void switchToNextState(State.Event event, Object obj)
+    {
+        super.switchToNextState(event, obj);
+        switch(event) {
+            case SHIFT_PRESSED :
+                switchAndActivateState(QuickAddDragState.getInstance(), obj);
+                break;
+            case MOUSE_RELEASED :
+                switchAndActivateState(IdleState.getInstance(), obj);
+                break;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/ConstructorDragWhileRunningState.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/ConstructorDragWhileRunningState.java
new file mode 100644
index 0000000000000000000000000000000000000000..b91b37512f12b9cc6c290c6f8f60a437908e385e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/ConstructorDragWhileRunningState.java
@@ -0,0 +1,75 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.states;
+
+import greenfoot.event.TriggeredKeyListener;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.gui.input.InputManager;
+
+/**
+ * This state is active when the constructor of an Actor has been invoked via
+ * the context-menu of the Actor. Works only while the simulation is running,
+ * but there is another state {@link ConstructorDragState} which handles the
+ * same case when the simulation is stopped.
+ * 
+ * @author Poul Henriksen
+ */
+public class ConstructorDragWhileRunningState extends State
+{
+    protected static ConstructorDragWhileRunningState instance;
+
+    public static synchronized ConstructorDragWhileRunningState getInstance() throws IllegalStateException
+    {
+        if (instance == null) {
+            throw new IllegalStateException("Not initialized.");
+        }
+        return instance;
+    }
+    
+    private ConstructorDragWhileRunningState(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        super(inputManager, keyListener, mouseListener, mouseMotionListener);
+    }
+
+    public static synchronized ConstructorDragWhileRunningState initialize(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        instance = new ConstructorDragWhileRunningState(inputManager, keyListener, mouseListener, mouseMotionListener);
+        return instance;
+    }
+
+    @Override
+    public void switchToNextState(State.Event event, Object obj)
+    {
+        super.switchToNextState(event, obj);
+        switch(event) {
+            case SIMULATION_STOPPED :
+                switchAndActivateState(ConstructorDragState.getInstance(), obj);
+                break;
+            case MOUSE_RELEASED :
+                switchAndActivateState(RunningState.getInstance(), obj);
+                break;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/DisabledState.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/DisabledState.java
new file mode 100644
index 0000000000000000000000000000000000000000..5cef43820eb8060b0459eb418f1b61a90537c39f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/DisabledState.java
@@ -0,0 +1,69 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.states;
+
+import greenfoot.event.TriggeredKeyListener;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.gui.input.InputManager;
+
+/**
+ * This state is active when you should not be allowed to initiate a drag.
+ * 
+ * @author Poul Henriksen
+ */
+public class DisabledState extends State
+{
+    protected static DisabledState instance;
+
+    public static synchronized DisabledState getInstance() throws IllegalStateException
+    {
+        if (instance == null) {
+            throw new IllegalStateException("Not initialized.");
+        }
+        return instance;
+    }
+    
+
+    private DisabledState(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        super(inputManager, keyListener, mouseListener, mouseMotionListener);
+    }
+
+    public static synchronized DisabledState initialize(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        instance = new DisabledState(inputManager, keyListener, mouseListener, mouseMotionListener);
+        return instance;
+    }
+
+    @Override
+    public void switchToNextState(State.Event event, Object obj)
+    {
+        switch(event) {
+            case WORLD_CREATED :
+                switchAndActivateState(IdleState.getInstance(), obj);
+                break;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/IdleState.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/IdleState.java
new file mode 100644
index 0000000000000000000000000000000000000000..7fde005270a13415f0b613f27a768b19a0172635
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/IdleState.java
@@ -0,0 +1,83 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.states;
+
+import greenfoot.event.TriggeredKeyListener;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.gui.input.InputManager;
+
+/**
+ * This is the default state, which is active when the simulation is stopped and
+ * nothing else is happening (no dragging etc.)
+ * 
+ * @author Poul Henriksen
+ */
+public class IdleState extends State
+{
+    protected static IdleState instance;
+
+    public static synchronized IdleState getInstance() throws IllegalStateException
+    {
+        if (instance == null) {
+            throw new IllegalStateException("Not initialized.");
+        }
+        return instance;
+    }
+    
+    private IdleState(InputManager inputManager, TriggeredKeyListener keyListener, TriggeredMouseListener mouseListener,
+            TriggeredMouseMotionListener mouseMotionListener)
+    {
+        super(inputManager, keyListener, mouseListener, mouseMotionListener);
+    }
+
+    public static synchronized IdleState initialize(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        instance = new IdleState(inputManager, keyListener, mouseListener, mouseMotionListener);
+        return instance;
+    }
+
+    @Override
+    public void switchToNextState(State.Event event, Object obj)
+    {
+        super.switchToNextState(event, obj);
+        switch(event) {
+            case CONSTRUCTOR_INVOKED :
+                switchAndActivateState(ConstructorDragState.getInstance(), obj);
+                break;
+            case OBJECT_MOVED :
+                switchAndActivateState(MoveState.getInstance(), obj);
+                break;
+            case SIMULATION_STARTED :
+                switchAndActivateState(RunningState.getInstance(), obj);
+                break;
+            case MOUSE_PRESSED :
+                switchAndActivateState(MoveState.getInstance(), obj);
+                break;
+            case SHIFT_PRESSED :
+                switchAndActivateState(QuickAddDragState.getInstance(), obj);
+                break;
+        }
+    }
+
+};
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/MoveState.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/MoveState.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ad4eccc6f1c5a37c1050074f67d63f14dffec5c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/MoveState.java
@@ -0,0 +1,72 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.states;
+
+import greenfoot.event.TriggeredKeyListener;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.gui.input.InputManager;
+
+/**
+ * This state is active when an Actor that has previously been added to the
+ * world is dragged around. Works only while the simulation is stopped.
+ * 
+ * @author Poul Henriksen
+ */
+public class MoveState extends State
+{
+    protected static MoveState instance;
+
+    public static synchronized MoveState getInstance() throws IllegalStateException
+    {
+        if (instance == null) {
+            throw new IllegalStateException("Not initialized.");
+        }
+        return instance;
+    }
+    
+
+    private MoveState(InputManager inputManager, TriggeredKeyListener keyListener, TriggeredMouseListener mouseListener,
+            TriggeredMouseMotionListener mouseMotionListener)
+    {
+        super(inputManager, keyListener, mouseListener, mouseMotionListener);
+    }
+
+    public static synchronized MoveState initialize(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        instance = new MoveState(inputManager, keyListener, mouseListener, mouseMotionListener);
+        return instance;
+    }
+
+    @Override
+    public void switchToNextState(State.Event event, Object obj)
+    {
+        super.switchToNextState(event, obj);
+        switch(event) {
+            case MOUSE_RELEASED :
+                switchAndActivateState(IdleState.getInstance(), obj);
+                break;
+        }
+    }
+
+};
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/QuickAddDragState.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/QuickAddDragState.java
new file mode 100644
index 0000000000000000000000000000000000000000..9417536bb8aa6a9b4161540a01e55baeec0f41e8
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/QuickAddDragState.java
@@ -0,0 +1,70 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.states;
+
+import greenfoot.event.TriggeredKeyListener;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.gui.input.InputManager;
+
+/**
+ * This state is active when "quick adding" a new Actor by holding down the
+ * SHIFT-key. Works only while the simulation is stopped.
+ * 
+ * @author Poul Henriksen
+ */
+public class QuickAddDragState extends State
+{
+    protected static QuickAddDragState instance;
+
+    public static synchronized QuickAddDragState getInstance() throws IllegalStateException
+    {
+        if (instance == null) {
+            throw new IllegalStateException("Not initialized.");
+        }
+        return instance;
+    }
+        
+    private QuickAddDragState(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        super(inputManager, keyListener, mouseListener, mouseMotionListener);
+    }
+    
+    public static synchronized QuickAddDragState initialize(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        instance = new QuickAddDragState(inputManager, keyListener, mouseListener, mouseMotionListener);
+        return instance;
+    }
+
+    @Override
+    public void switchToNextState(State.Event event, Object obj)
+    {
+        super.switchToNextState(event, obj);
+        switch(event) {
+            case SHIFT_RELEASED :
+                switchAndActivateState(IdleState.getInstance(), obj);
+                break;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/RunningState.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/RunningState.java
new file mode 100644
index 0000000000000000000000000000000000000000..5fab7a5497861c3dc9659e002cedc380c72089d4
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/RunningState.java
@@ -0,0 +1,72 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.states;
+
+import greenfoot.event.TriggeredKeyListener;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.gui.input.InputManager;
+
+/**
+ * This state is active when the simulation is running.
+ * 
+ * @author Poul Henriksen
+ */
+public class RunningState extends State
+{
+    protected static RunningState instance;
+
+    public static synchronized RunningState getInstance() throws IllegalStateException
+    {
+        if (instance == null) {
+            throw new IllegalStateException("Not initialized.");
+        }
+        return instance;
+    }
+    
+    private RunningState(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        super(inputManager, keyListener, mouseListener, mouseMotionListener);
+    }
+
+    public static synchronized RunningState initialize(InputManager inputManager, TriggeredKeyListener keyListener,
+            TriggeredMouseListener mouseListener, TriggeredMouseMotionListener mouseMotionListener)
+    {
+        instance = new RunningState(inputManager, keyListener, mouseListener, mouseMotionListener);
+        return instance;
+    }
+
+    @Override
+    public void switchToNextState(State.Event event, Object obj)
+    {
+        super.switchToNextState(event, obj);
+        switch(event) {
+            case SIMULATION_STOPPED :
+                switchAndActivateState(IdleState.getInstance(), obj);
+                break;
+            case CONSTRUCTOR_INVOKED :
+                switchAndActivateState(ConstructorDragWhileRunningState.getInstance(), obj);
+                break;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/State.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/State.java
new file mode 100644
index 0000000000000000000000000000000000000000..02dddcba10a59648097087dd953606b330578894
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/input/states/State.java
@@ -0,0 +1,119 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.input.states;
+
+import greenfoot.event.TriggeredKeyAdapter;
+import greenfoot.event.TriggeredKeyListener;
+import greenfoot.event.TriggeredMouseAdapter;
+import greenfoot.event.TriggeredMouseListener;
+import greenfoot.event.TriggeredMouseMotionAdapter;
+import greenfoot.event.TriggeredMouseMotionListener;
+import greenfoot.gui.input.InputManager;
+
+/**
+ * Superclass for all states. Each state is also responsible for determining the
+ * next state given a specific event. The states also set up the listeners that
+ * should be active in that state.
+ * <p>
+ * Sub classes should make sure to initialize the singleton instance.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public abstract class State
+{
+    /**
+     * Represents the different events that can tricker state changes.
+     */
+    public static enum Event {
+         CONSTRUCTOR_INVOKED,  MOUSE_RELEASED,  SHIFT_PRESSED,  SHIFT_RELEASED,  MOUSE_PRESSED,  SIMULATION_STARTED,  SIMULATION_STOPPED,  WORLD_CREATED,  WORLD_REMOVED, OBJECT_MOVED;        
+    }
+
+    protected InputManager inputManager;
+    private TriggeredKeyListener keyListener;
+    private TriggeredMouseListener mouseListener;
+    private TriggeredMouseMotionListener mouseMotionListener;
+
+    State(InputManager inputManager, TriggeredKeyListener keyListener, TriggeredMouseListener mouseListener,
+            TriggeredMouseMotionListener mouseMotionListener)
+    {
+        super();
+        this.inputManager = inputManager;
+
+        if (keyListener != null) {
+            this.keyListener = keyListener;
+        }
+        else {
+            this.keyListener = new TriggeredKeyAdapter();
+        }
+
+        if (mouseListener != null) {
+            this.mouseListener = mouseListener;
+        }
+        else {
+            this.mouseListener = new TriggeredMouseAdapter();
+        }
+
+        if (mouseMotionListener != null) {
+            this.mouseMotionListener = mouseMotionListener;
+        }
+        else {
+            this.mouseMotionListener = new TriggeredMouseMotionAdapter();
+        }
+    }
+    
+    /**
+     * The rules for switching states. Implementations should respond to events
+     * by using the method
+     * {@link #switchAndActivateState(greenfoot.gui.InputManager.State)} to
+     * switch to other states based on the event.
+     * 
+     * @see #switchAndActivateState(greenfoot.gui.InputManager.State)
+     */
+    public void switchToNextState(State.Event event, Object obj)
+    {
+        switch(event) {
+            case WORLD_REMOVED :
+                inputManager.switchAndActivateState(DisabledState.getInstance(), obj);
+                break;
+        }
+    }
+
+    /**
+     * This method should sets up the listeners. Activating a state means
+     * setting up the listeners to receive events and notifying them that
+     * listening has started via the TriggeredListener interface.
+     * 
+     * @see InputManager.#activeKeyListener
+     * @see InputManager.#activeMouseListener
+     * @see InputManager.#activeMouseMotionListener
+     */
+    public void activate(Object obj)
+    {
+        inputManager.activateListeners(keyListener, mouseListener, mouseMotionListener, obj);
+    }
+
+    void switchAndActivateState(State state, Object obj)
+    {
+        inputManager.switchAndActivateState(state, obj);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootClassInspector.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootClassInspector.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce3298adc485300950f6bcaceea3afb4203e4546
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootClassInspector.java
@@ -0,0 +1,73 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.inspector;
+
+import greenfoot.util.GreenfootUtil;
+
+import javax.swing.JFrame;
+
+import bluej.debugger.DebuggerClass;
+import bluej.debugmgr.inspector.ClassInspector;
+import bluej.debugmgr.inspector.InspectorManager;
+import bluej.pkgmgr.Package;
+import bluej.testmgr.record.InvokerRecord;
+
+/**
+ * Inspector that updates the values in the inspector with a fixed timer
+ * interval.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class GreenfootClassInspector extends ClassInspector
+{
+    /**
+     * Construct a new class inspector.
+     */
+    public GreenfootClassInspector(DebuggerClass clss, InspectorManager inspectorManager, Package pkg, InvokerRecord ir,
+            JFrame parent)
+    {
+        super(clss, inspectorManager, pkg, ir, parent);
+        new InspectorUpdater(this);
+        GreenfootUtil.makeGreenfootTitle(GreenfootClassInspector.this);
+    }
+
+    /**
+     * Whether the Get button should be enabled.
+     * 
+     * @return True if the selected object is an actor
+     */
+    @Override
+    protected boolean isGetEnabled()
+    {
+        return GreenfootInspector.isGetEnabled(selectedField);
+    }
+
+    /**
+     * The "Get" button was pressed. Start dragging the selected object.
+     */
+    @Override
+    protected void doGet()
+    {
+        GreenfootInspector.doGet(selectedField);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootInspector.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootInspector.java
new file mode 100644
index 0000000000000000000000000000000000000000..fce6b2c3482f354183bf3e816718a54d2a3ffe63
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootInspector.java
@@ -0,0 +1,67 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.inspector;
+
+import greenfoot.Actor;
+import greenfoot.ActorVisitor;
+import greenfoot.core.WorldHandler;
+import greenfoot.gui.input.InputManager;
+import greenfoot.localdebugger.LocalObject;
+
+/**
+ * Contains methods used by the inspector in greenfoot.
+ * 
+ * @author Poul Henriksen
+ */
+public class GreenfootInspector
+{
+    /**
+     * Whether the Get button should be enabled.
+     * @return True if the selected object is an actor
+     */
+    static boolean isGetEnabled(Object selectedObject)
+    {
+        if (selectedObject != null && selectedObject instanceof LocalObject) {
+            Object obj = ((LocalObject) selectedObject).getObject();
+            if (obj != null && obj instanceof Actor) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * The "Get" button was pressed. Start dragging the selected object.
+     */
+    static void doGet(Object selectedObject)
+    {
+        Object obj = ((LocalObject) selectedObject).getObject();
+        InputManager inputManager = WorldHandler.getInstance().getInputManager();
+        Actor actor = (Actor) obj;
+        if(ActorVisitor.getWorld(actor) != null) {
+            inputManager.objectMoved(actor);
+        }
+        else {
+            inputManager.objectCreated(actor);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootObjectInspector.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootObjectInspector.java
new file mode 100644
index 0000000000000000000000000000000000000000..1880c40ada7138fda5c3d18a14f292f0c5877579
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootObjectInspector.java
@@ -0,0 +1,73 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.inspector;
+
+import greenfoot.util.GreenfootUtil;
+
+import javax.swing.JFrame;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugmgr.inspector.InspectorManager;
+import bluej.debugmgr.inspector.ObjectInspector;
+import bluej.pkgmgr.Package;
+import bluej.testmgr.record.InvokerRecord;
+
+/**
+ * Inspector that updates the values in the inspector with a fixed timer
+ * interval.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class GreenfootObjectInspector extends ObjectInspector
+{
+    /**
+     * Construct a new object inspector.
+     */
+    public GreenfootObjectInspector(DebuggerObject obj, InspectorManager inspectorManager, String name, Package pkg,
+            InvokerRecord ir, JFrame parent)
+    {
+        super(obj, inspectorManager, name, pkg, ir, parent);
+        new InspectorUpdater(this);
+        GreenfootUtil.makeGreenfootTitle(GreenfootObjectInspector.this);
+    }
+
+    /**
+     * Whether the Get button should be enabled.
+     * 
+     * @return True if the selected object is an actor
+     */
+    @Override
+    protected boolean isGetEnabled()
+    {
+        return GreenfootInspector.isGetEnabled(selectedField);
+    }
+
+    /**
+     * The "Get" button was pressed. Start dragging the selected object.
+     */
+    @Override
+    protected void doGet()
+    {
+        GreenfootInspector.doGet(selectedField);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootResultInspector.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootResultInspector.java
new file mode 100644
index 0000000000000000000000000000000000000000..94f58ea901447da38e4e362b5dac23b7102c6562
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/GreenfootResultInspector.java
@@ -0,0 +1,70 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.inspector;
+
+import greenfoot.util.GreenfootUtil;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugmgr.ExpressionInformation;
+import bluej.debugmgr.inspector.InspectorManager;
+import bluej.debugmgr.inspector.ResultInspector;
+import bluej.pkgmgr.Package;
+import bluej.testmgr.record.InvokerRecord;
+
+/**
+ * Result inspector for Greenfoot.
+ * 
+ * @author Poul Henriksen
+ */
+public class GreenfootResultInspector extends ResultInspector
+{
+    /**
+     * Construct a result inspector.
+     */
+    public GreenfootResultInspector(DebuggerObject obj, InspectorManager inspectorManager, String name, Package pkg,
+            InvokerRecord ir, ExpressionInformation info)
+    {
+        super(obj, inspectorManager, name, pkg, ir, info);
+        GreenfootUtil.makeGreenfootTitle(GreenfootResultInspector.this);
+    }
+
+    /**
+     * Whether the Get button should be enabled.
+     * 
+     * @return True if the selected object is an actor
+     */
+    @Override
+    protected boolean isGetEnabled()
+    {
+        return GreenfootInspector.isGetEnabled(selectedField);
+    }
+
+    /**
+     * The "Get" button was pressed. Start dragging the selected object.
+     */
+    @Override
+    protected void doGet()
+    {
+        GreenfootInspector.doGet(selectedField);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/InspectorUpdater.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/InspectorUpdater.java
new file mode 100644
index 0000000000000000000000000000000000000000..a867da7da21ab3f189f850d0b81afcf41eaa49ec
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/InspectorUpdater.java
@@ -0,0 +1,118 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.inspector;
+
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.Timer;
+
+import bluej.debugmgr.inspector.Inspector;
+
+/**
+ * Updater that will call update on an inspector with fixed time intervals. <br>
+ * The updater will stop when the window is closed.
+ * 
+ * @author Poul Henriksen
+ */
+public class InspectorUpdater
+    implements WindowListener
+{
+    private Inspector inspector;
+    private Timer timer;
+    private static final int PERIOD = 500;
+
+    /**
+     * Creates a new updater. It will start updating as soon as the inspector
+     * becomes visible.
+     * 
+     * @param inspector
+     */
+    public InspectorUpdater(Inspector inspector)
+    {
+        this.inspector = inspector;
+        inspector.addWindowListener(this);
+        if (inspector.isVisible()) {
+            start();
+        }
+
+    }
+
+    /**
+     * Starts the updater.
+     * 
+     */
+    public void start()
+    {
+        if (timer != null) {
+            timer.cancel();
+        }
+        timer = new Timer();
+        timer.schedule(new UpdateTask(inspector), PERIOD, PERIOD);
+    }
+
+    /**
+     * Stops the updater.
+     * 
+     */
+    public void stop()
+    {
+        if (timer != null) {
+            timer.cancel();
+        }
+    }
+
+    public void windowActivated(WindowEvent e)
+    {
+    // Nothing to do
+    }
+
+    public void windowDeactivated(WindowEvent e)
+    {
+    // Nothing to do
+    }
+
+    public void windowOpened(WindowEvent e)
+    {
+        start();
+    }
+
+    public void windowClosed(WindowEvent e)
+    {
+        stop();
+    }
+
+    public void windowClosing(WindowEvent e)
+    {
+    // Nothing to do
+    }
+
+    public void windowDeiconified(WindowEvent e)
+    {
+        start();
+    }
+
+    public void windowIconified(WindowEvent e)
+    {
+        stop();
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/UpdateTask.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/UpdateTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..298ccf5e50435db7422aa94e1ab5a805075c78d2
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/inspector/UpdateTask.java
@@ -0,0 +1,47 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.inspector;
+
+import java.util.TimerTask;
+
+import bluej.debugmgr.inspector.Inspector;
+
+/**
+ * Timer task that calls update on an inspector.
+ * 
+ * @author Poul Henriksen
+ */
+public class UpdateTask extends TimerTask
+{
+    private Inspector inspector;
+
+    public UpdateTask(Inspector insp)
+    {
+        this.inspector = insp;
+    }
+
+    @Override
+    public void run()
+    {
+        inspector.update();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/soundrecorder/SaveState.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/soundrecorder/SaveState.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b13061cbbfe7e62fe3ea05c8621df5792616494
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/soundrecorder/SaveState.java
@@ -0,0 +1,186 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.soundrecorder;
+
+import greenfoot.sound.SoundRecorder;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+
+/**
+ * This class manages the saving aspect of SoundRecorderControls:
+ * keeping track of whether the sound has changed since last save,
+ * displaying the overwrite dialog, updating the status message
+ */
+class SaveState
+{
+    private final SoundRecorder recorder;
+    private Component parent;
+
+    private boolean changedSinceSave = false;
+    private String lastSaveName = null;
+    private JTextField filenameField;
+    private JButton saveButton;
+    private JLabel messageLabel;
+    private String savedText;
+    private String notSavedText;
+
+    SaveState(Component parent, SoundRecorder recorder)
+    {
+        this.parent = parent;
+        this.recorder = recorder;
+        savedText = Config.getString("soundRecorder.saved");
+        notSavedText = Config.getString("soundRecorder.notSaved");
+    }
+
+    
+    public boolean hasChangedSinceSave()
+    {
+        return changedSinceSave;
+    }
+    
+    private void savedAs(String name)
+    {
+        changedSinceSave = false;
+        lastSaveName = name;
+        updateSaveButtonAndLabel();
+    }
+    
+    public void changed()
+    {
+        changedSinceSave = true;
+        updateSaveButtonAndLabel();
+    }
+
+    // Updates the save button based on whether the filename field is blank (and whether a recording exists)
+    private void updateSaveButtonAndLabel()
+    {
+        boolean differentFromSaved = !filenameField.getText().equals(lastSaveName) || changedSinceSave;
+        
+        if (recorder.getRawSound() != null) {
+            messageLabel.setText(differentFromSaved ? notSavedText : savedText);
+        }
+        
+        saveButton.setEnabled(recorder.getRawSound() != null && !filenameField.getText().isEmpty()
+                  && differentFromSaved);
+    }
+    
+    // Builds the save row: a filename field and save button
+    public Box buildSaveBox(final String projectSoundDir)
+    {
+        Box saveBox = new Box(BoxLayout.X_AXIS);
+        saveBox.add(new JLabel(Config.getString("soundRecorder.filename") + ": "));
+        filenameField = new JTextField();
+        filenameField.setMaximumSize(new Dimension(Short.MAX_VALUE, filenameField.getPreferredSize().height));
+        filenameField.getDocument().addDocumentListener(new DocumentListener() {
+            public void removeUpdate(DocumentEvent e)
+            {
+                updateSaveButtonAndLabel();
+            }
+            
+            public void insertUpdate(DocumentEvent e)
+            {
+                updateSaveButtonAndLabel();                
+            }
+            
+            public void changedUpdate(DocumentEvent e)
+            {                
+            }
+        });
+        saveBox.add(filenameField);
+        saveBox.add(new JLabel(".wav"));
+        
+        saveBox.add(Box.createHorizontalStrut(12));
+        
+        saveButton = new JButton(Config.getString("soundRecorder.save"));
+        saveButton.setEnabled(false);
+        saveButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                if (projectSoundDir != null) {
+                    File destination = new File(projectSoundDir + filenameField.getText() + ".wav");
+                    if (destination.exists()) {
+                        String[] options = null;
+                        int overwrite;
+                        if (Config.isMacOS()) {
+                            options = new String[] { BlueJTheme.getCancelLabel(), Config.getString("soundRecorder.overwrite") };
+                            overwrite = 1;
+                        }
+                        else {
+                            options = new String[] { Config.getString("soundRecorder.overwrite"), BlueJTheme.getCancelLabel() };
+                            overwrite = 0;
+                        }
+                        
+                        if (overwrite == JOptionPane.showOptionDialog(parent,
+                          Config.getString("soundRecorder.overwrite.part1") + destination.getName() + Config.getString("soundRecorder.overwrite.part2"),
+                          Config.getString("soundRecorder.overwrite.title"),
+                          JOptionPane.YES_NO_OPTION,
+                          JOptionPane.QUESTION_MESSAGE,
+                          null,
+                          options, options[overwrite])) {
+                            recorder.writeWAV(destination);
+                            savedAs(filenameField.getText());
+                        }
+                    } else {
+                        recorder.writeWAV(destination);
+                        savedAs(filenameField.getText());
+                        
+                    }
+                    
+                }
+            }
+        });
+        saveBox.add(saveButton);
+        
+        return saveBox;
+    }
+
+
+    JLabel createLabel()
+    {
+        messageLabel = new JLabel("");
+        messageLabel.setForeground(Color.GRAY);
+        messageLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+        Font font = messageLabel.getFont();
+        font = font.deriveFont(10.0f);
+        messageLabel.setFont(font);
+        return messageLabel;
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/soundrecorder/SoundRecorderControls.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/soundrecorder/SoundRecorderControls.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b6efb4ae1351e6e1f2c2fb26da781b0cd84a168
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/gui/soundrecorder/SoundRecorderControls.java
@@ -0,0 +1,526 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.gui.soundrecorder;
+
+import greenfoot.core.GProject;
+import greenfoot.sound.MemoryAudioInputStream;
+import greenfoot.sound.Sound;
+import greenfoot.sound.SoundPlaybackListener;
+import greenfoot.sound.SoundRecorder;
+import greenfoot.sound.SoundStream;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.io.File;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.SoftBevelBorder;
+
+import bluej.BlueJTheme;
+import bluej.Config;
+import bluej.utility.Utility;
+
+/**
+ * The GUI class for the sound recorder.
+ * 
+ * @author neil
+ */
+public class SoundRecorderControls extends JFrame implements WindowListener
+{
+    SoundRecorder recorder = new SoundRecorder();
+    
+    // Indicates whether the selection is currently in use (and should be displayed/used)
+    // If the selection is zero width, this will be false
+    private boolean selectionActive = false;
+    // Indicates whether the user is currently in the middle of drawing a selection
+    private boolean selectionDrawing = false;
+    //Begin is where the user started dragging, end is where the user has dragged it to.
+    //It's valid for end to be before beginning, if they drag right to left.
+    private float selectionBegin;
+    private float selectionEnd;
+    
+    private JButton trim;
+    private JButton playStop;
+    private JButton recordStop;
+    
+    private boolean playing = false;
+    //Position will only be valid when "playing" is true:
+    private long playbackPosition;
+    private boolean recording = false;
+    // Reference will be only be valid when "recording" is true:
+    private AtomicReference<List<byte[]>> currentRecording;
+
+    private SoundPanel soundPanel;
+    
+    private SaveState saveState = new SaveState(this, recorder);
+    
+    private final String playLabel;
+    private final String playSelectionLabel;
+    private final String stopPlayLabel;
+    private final String recordLabel;
+    private final String stopRecordLabel;
+    
+    /**
+     * Creates a SoundRecorderDialog that will save the sounds
+     * in the sounds directory of the given project.
+     */
+    public SoundRecorderControls(GProject project)
+    {        
+        playLabel = Config.getString("soundRecorder.play");
+        playSelectionLabel = Config.getString("soundRecorder.playSelection");
+        stopPlayLabel = Config.getString("soundRecorder.stopPlay");
+        recordLabel = Config.getString("soundRecorder.record");
+        stopRecordLabel = Config.getString("soundRecorder.stopRecord");
+        setTitle(Config.getString("soundRecorder.title"));
+        buildUI(project);
+        
+        Image icon = BlueJTheme.getApplicationIcon("greenfoot");
+        if (icon != null) {
+            setIconImage(icon);
+        }
+    }
+    
+    // Builds the controls: record/trim/play
+    private JPanel buildControlBox()
+    {
+        recordStop = new JButton(recordLabel);
+        Utility.changeToMacButton(recordStop);
+        recordStop.setFocusable(false);
+        recordStop.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                if (!recording) {
+                    //Start recording
+                    currentRecording = recorder.startRecording();
+                    recordStop.setText(stopRecordLabel);
+                    playStop.setEnabled(false);
+                    recording = true;
+                    new Timer().scheduleAtFixedRate(new TimerTask() {
+                        List<byte[]> lastValue = null;
+                        public void run()
+                        {
+                            List<byte[]> curValue = currentRecording.get();
+                            if (curValue != lastValue)
+                                soundPanel.repaint();
+                            if (lastValue != null && curValue == null)
+                                cancel();
+                            lastValue = curValue;
+                            
+                        }
+                    }, 100, 200);
+                } else {
+                    //Stop recording
+                    stopRecording();
+                }
+            }
+        });
+        
+        trim = new JButton(Config.getString("soundRecorder.trim"));
+        trim.setEnabled(false);
+        trim.setFocusable(false);
+        Utility.changeToMacButton(trim);
+        trim.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                recorder.trim(Math.min(selectionBegin, selectionEnd), Math.max(selectionBegin, selectionEnd));
+                saveState.changed();
+                selectionActive = false;
+                updateButtons();
+                repaint();
+            }
+        });
+        
+        playStop = new JButton(playLabel);
+        Utility.changeToMacButton(playStop);
+        playStop.setFocusable(false);
+        playStop.setEnabled(false);
+        playStop.addActionListener(new Player());
+
+        JPanel controls = new JPanel(new FlowLayout(FlowLayout.CENTER, 2, 0));
+        controls.add(recordStop);
+        controls.add(playStop);
+        controls.add(trim);
+
+        return controls;
+    }
+    
+    
+    
+    private void buildUI(GProject project)
+    {
+        JPanel contentPane = new JPanel();
+        this.setContentPane(contentPane);
+        contentPane.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
+        contentPane.setBorder(BlueJTheme.dialogBorder);
+
+        soundPanel = new SoundPanel();
+
+        JLabel messageLabel = saveState.createLabel();
+
+        JPanel soundAndControls = new JPanel(new BorderLayout(0,0));
+        
+            soundAndControls.add(soundPanel, BorderLayout.CENTER);
+
+            JPanel controls = new JPanel(new BorderLayout(0,0));
+                controls.add(buildControlBox(), BorderLayout.CENTER);
+                controls.add(messageLabel, BorderLayout.SOUTH);
+            soundAndControls.add(controls, BorderLayout.SOUTH);
+            soundAndControls.setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
+ 
+        contentPane.add(soundAndControls);
+        
+        contentPane.add(Box.createVerticalStrut(12));      
+        
+        contentPane.add(saveState.buildSaveBox(getSoundDir(project)));
+        
+        contentPane.add(Box.createVerticalStrut(12));
+
+        JButton done = new JButton(Config.getString("soundRecorder.done"));
+        done.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                closeAndStopRecording();
+            }
+        });
+        done.setAlignmentX(CENTER_ALIGNMENT);
+        contentPane.add(done);
+        
+        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+        addWindowListener(this);
+        
+        pack();
+        setVisible(true);
+    }
+
+    // Gets the sounds directory for the given project, or null if there is a problem
+    private static String getSoundDir(GProject project)
+    {
+        return project.getDir() + File.separator + "sounds" + File.separator;
+    }
+    
+    // Updates trim and play buttons based on whether the selection is active
+    private void updateButtons()
+    {
+        trim.setEnabled(selectionActive);
+        playStop.setText(selectionActive ? playSelectionLabel : playLabel);
+    }
+    
+    /**
+     * A class that handles playing sound, controlled by a play/stop button (for which this is the ActionListener).
+     *
+     */
+    private class Player implements ActionListener, SoundPlaybackListener
+    {
+        private final Timer tim = new Timer();
+        private TimerTask repaintWhilePlaying;
+        private SoundStream stream;
+                
+        public void actionPerformed(ActionEvent e)
+        {
+            if (playing) {
+                stream.stop();
+                //Everything will be done in the stop callback, below
+            } else {
+                MemoryAudioInputStream memoryStream;
+                final int start;
+                if (selectionActive) {
+                    start = getSelectionStartOffset();
+                    int len = getSelectionFinishOffset() - start;
+                    memoryStream = new MemoryAudioInputStream(recorder.getRawSound(), start, len, recorder.getFormat());
+                } else {
+                    start = 0;
+                    memoryStream = new MemoryAudioInputStream(recorder.getRawSound(), recorder.getFormat());
+                }
+                stream = new SoundStream(memoryStream, this);
+                playing = true;
+                playbackPosition = start;
+                stream.play();
+                playStop.setText(stopPlayLabel);
+                recordStop.setEnabled(false);
+                
+                repaintWhilePlaying = new TimerTask() {
+                    public void run()
+                    {
+                        playbackPosition = start + stream.getLongFramePosition();
+                        soundPanel.repaint();
+                    }
+                }; 
+                tim.scheduleAtFixedRate(repaintWhilePlaying, 50, 100);
+            }
+        }
+
+        public void playbackPaused(Sound sound)
+        {
+            //Shouldn't happen as we don't have a pause button
+        }
+
+        public void playbackStarted(Sound sound)
+        {
+            //Nothing to do            
+        }
+
+        public void playbackStopped(Sound sound)
+        {
+            updateButtons();
+            recordStop.setEnabled(true);
+            repaintWhilePlaying.cancel();
+            playing = false;
+            soundPanel.repaint();
+        }
+
+        public void soundClosed(Sound sound)
+        {
+            // Nothing to do            
+        }
+    }
+
+    /**
+     * A panel for displaying a recorded sound.
+     */
+    private class SoundPanel extends JPanel implements MouseListener, MouseMotionListener
+    {       
+        private SoundPanel()
+        {
+            setPreferredSize(new Dimension(400, 200));
+            setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
+            addMouseListener(this);
+            addMouseMotionListener(this);
+        }
+        
+        @SuppressWarnings("cast")
+        protected void paintComponent(Graphics g)
+        {
+            int width = getWidth();
+            int height = getHeight();
+            int middle = height / 2;
+            int halfHeight = height / 2;
+            byte[] sound = recorder.getRawSound();
+            
+            g.setColor(Color.BLACK);
+            g.fillRect(0, 0, width, height);
+            
+            if (recording || (sound != null && sound.length > 0)) {
+                if (selectionActive) {
+                    g.setColor(Color.GRAY);
+                    g.fillRect((int)(Math.min(selectionBegin, selectionEnd) * width), 0, (int)(Math.abs(selectionBegin - selectionEnd) * width), height);
+                }
+                
+                // Get this outside the loop to make sure it's consistent:
+                byte[][] rec = null;
+                int recLength = 0;
+                if (recording) {
+                    List<byte[]> recList = currentRecording.get();
+                    if (recList != null) {
+                        rec = recList.toArray(new byte[0][]);
+                        for (byte[] chunk : rec) {
+                            //Shouldn't have any null chunks, but just in case:
+                            int chunkLength = chunk == null ? 0 : chunk.length;
+                            recLength += chunkLength;
+                        }
+                    }
+                }
+                else
+                    recLength = sound.length;
+                int curRecChunk = 0;
+                int prevChunksLength = 0;
+                
+                for (int i = 0; i < width; i++) {
+                    float pos = (float)i / (float)width;
+                    float f;
+                    // Use rec test rather than "recording" in case "recording" changes mid-paint:
+                    if (rec != null) {
+                        int index = (int)(pos * (float)recLength);
+                        if (recLength == 0 || index >= recLength) {
+                            // No data yet:
+                            f = 0.0f;
+                        } else {                            
+                            // We have a list of chunks that make up the current recording:
+                            //  Skip forward to right chunk if needed:
+                            while (index >= prevChunksLength + rec[curRecChunk].length) {
+                                prevChunksLength += rec[curRecChunk].length;
+                                curRecChunk += 1;
+                            }
+                            f = (float)rec[curRecChunk][index - prevChunksLength] / 128.0f;
+                        }
+                    } else {
+                        int index = (int)(pos * (float)sound.length);
+                        f = (float)sound[index] / 128.0f;
+                    }
+                    //Looks slightly better if we don't draw all the way to the edge, so use 90%:
+                    int waveHeight = (int)(halfHeight * f * 0.9f);
+                    
+                    if (inSelection(pos)) {
+                        g.setColor(Color.YELLOW);
+                    } else {
+                        g.setColor(Color.GREEN);
+                    }
+                    g.drawLine(i, middle - waveHeight, i, middle + waveHeight);
+
+                }
+                
+                if (playing) {
+                    g.setColor(Color.RED);
+                    float playPosRel = (float)playbackPosition / (float)recLength;
+                    int pos = (int)(playPosRel * (float)width);
+                    g.drawLine(pos, 0, pos, height);
+                }
+            }
+        }
+        
+        // Works out whether the given number (0->1) is inside the current selection (if there is one)
+        private boolean inSelection(float f)
+        {
+            return selectionActive && f >= Math.min(selectionBegin, selectionEnd)
+              && f <= Math.max(selectionBegin, selectionEnd);
+        }
+
+        public void mousePressed(MouseEvent e)
+        {
+            if (recorder.getRawSound() != null) {
+                // Selection only becomes active if they drag.
+                // Otherwise this is just a click and actually ends up removing the selection:
+                selectionActive = false;
+                selectionDrawing = true;
+                selectionBegin = calculatePosition(e.getPoint());
+                selectionEnd = selectionBegin;
+            }            
+        }
+
+        public void mouseReleased(MouseEvent e)
+        {
+            if (selectionDrawing) {
+                selectionDrawing = false;
+                selectionEnd = calculatePosition(e.getPoint());
+                if (selectionBegin == selectionEnd)
+                    selectionActive = false;
+                repaint();
+            }
+            updateButtons();
+        }    
+        
+                
+        private float calculatePosition(Point p)
+        {
+            float pos = (float)p.x / getWidth();
+            // Clamp to the range 0->1:
+            pos = Math.max(0, pos);
+            pos = Math.min(1, pos);
+            return pos;
+        }
+
+        public void mouseDragged(MouseEvent e)
+        {
+            if (selectionDrawing) {
+                selectionEnd = calculatePosition(e.getPoint());
+                selectionActive = true;
+                repaint();
+            }
+            
+        }
+
+        public void mouseClicked(MouseEvent e) {}
+        
+        public void mouseEntered(MouseEvent e) {}
+        
+        public void mouseExited(MouseEvent e) {}
+
+        public void mouseMoved(MouseEvent e) {}
+    }
+    
+    // Gets the start of the selection as an index into the raw sound array 
+    private int getSelectionStartOffset()
+    {
+        float start = Math.min(selectionBegin, selectionEnd);
+        float length = recorder.getRawSound().length;
+        return (int)(start * length);
+    }
+    
+    // Gets the finish of the selection as an index into the raw sound array
+    private int getSelectionFinishOffset()
+    {
+        float finish = Math.max(selectionBegin, selectionEnd);
+        float length = recorder.getRawSound().length;
+        return (int)(finish * length);
+    }
+    
+    
+    // WindowListener:
+    
+    public void windowClosing(WindowEvent e)
+    {
+        closeAndStopRecording();
+    }
+
+    public void closeAndStopRecording()
+    {
+        stopRecording();
+        setVisible(false);
+        
+    }
+
+    public void windowActivated(WindowEvent e) {}
+    
+    public void windowClosed(WindowEvent e) {}
+    
+    public void windowDeactivated(WindowEvent e) {}
+    
+    public void windowDeiconified(WindowEvent e) {}
+    
+    public void windowIconified(WindowEvent e) {}
+    
+    public void windowOpened(WindowEvent e) {}
+
+    private void stopRecording()
+    {
+        if (recording) {
+            recorder.stopRecording();
+            playStop.setEnabled(true);
+            saveState.changed();
+            soundPanel.repaint();
+            recordStop.setText(recordLabel);
+            recording = false;
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ImageMedia.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ImageMedia.java
new file mode 100644
index 0000000000000000000000000000000000000000..3236e075ea7ffa011548f88c9b919359245ff3fa
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ImageMedia.java
@@ -0,0 +1,147 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Equivalent of the Scratch ImageMedia class.
+ * 
+ * This is primarily a container that holds a ScratchImage inside it (which you can get at with getImage()).
+ * 
+ * It also has support for things like holding an original copy of a JPEG
+ * and compositing text with images, but we don't support that at the moment.
+ * 
+ * @author neil
+ *
+ */
+public class ImageMedia extends ScratchMedia
+{
+    // If non-null, the File that the image has been saved into
+    private File imageFile;
+
+    public ImageMedia(int version, List<ScratchObject> scratchObjects)
+    {
+        super(ScratchUserObject.IMAGE_MEDIA, version, scratchObjects);
+    }
+
+    // Fields:
+    //  form (ScratchImage), rotationCenter (?), textBox (?), jpegBytes (?), compositeForm (?) 
+    
+    public int fields()
+    {
+        return super.fields() + 5;
+    }    
+    
+    private ScratchImage getImage()
+    {
+        if (scratchObjects.get(super.fields() + 4) != null) {
+            return (ScratchImage) scratchObjects.get(super.fields() + 4);
+        } else {
+            return (ScratchImage)scratchObjects.get(super.fields() + 0);
+        }
+    }
+    
+    private byte[] getJpegBytes()
+    {
+        ScratchObject obj = scratchObjects.get(super.fields() + 3);
+        if (obj == null) {
+            return null;
+        } else {
+            return (byte[]) obj.getValue();
+        }
+    }
+    
+    public ScratchPoint getRotationCentre()
+    {
+        return (ScratchPoint) scratchObjects.get(super.fields() + 1);
+    }
+    
+    public int getWidth()
+    {
+        byte[] jpegBytes = getJpegBytes();
+        if (jpegBytes != null) {
+            try {
+                return ImageIO.read(new ByteArrayInputStream(jpegBytes)).getWidth();
+            } catch (IOException e) {
+                return -1;
+            }
+        } else {
+            return getImage().getWidth();
+        }        
+    }
+    
+    public int getHeight()
+    {
+        byte[] jpegBytes = getJpegBytes();
+        if (jpegBytes != null) {
+            try {
+                return ImageIO.read(new ByteArrayInputStream(jpegBytes)).getHeight();
+            } catch (IOException e) {
+                return -1;
+            }
+        } else {
+            return getImage().getHeight();
+        }        
+    }
+
+    @Override public File saveInto(File destDir, Properties props, String prefix) throws IOException
+    {       
+        if (imageFile == null) {
+            byte[] jpegBytes = getJpegBytes();
+            
+            String extension = jpegBytes == null ? "png" : "jpg";
+            
+            File imageDir = new File(destDir, "images");
+            imageDir.mkdirs();
+            for (int i = -1;;i++) {
+                // First try without addition, then append numbers until we find a free file:
+                imageFile = new File(imageDir, prefix + mungeChars(getMediaName()) + (i < 0 ? "" : "_" + i) + "." + extension);
+                if (false == imageFile.exists())
+                    break;
+            }
+            
+            if (jpegBytes != null) {
+                FileOutputStream fos = new FileOutputStream(imageFile);
+                fos.write(jpegBytes);
+                fos.close();
+            } else {
+                ImageIO.write(getImage().getBufferedImage(), "png", imageFile);
+            }
+        }
+        
+        return imageFile;
+    }
+    
+    private static String mungeChars(String name)
+    {
+        // Replace special characters (colons and slashes) with underscore:
+        return name.replaceAll("[:/\\\\]", "_");
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/Morph.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/Morph.java
new file mode 100644
index 0000000000000000000000000000000000000000..af85b0f4425be122f7fd93df63de3a2d260fc0b5
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/Morph.java
@@ -0,0 +1,53 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.util.List;
+
+/**
+ * Mirrors the Scratch Morph class, the base class for a lot of things in Scratch.
+ * 
+ * Mainly relevant because it holds the bounds (particularly useful for sprites).
+ * 
+ * @author neil
+ *
+ */
+public class Morph extends ScratchUserObject
+{
+    public Morph(int id, int version, List<ScratchObject> scratchObjects)
+    {
+        super(id, version, scratchObjects);
+    }
+
+    // Fields:
+    //  bounds (Rectangle), owner (?), submorphs (array), color (Color), flags (int), placeholder (null)
+    
+    public int fields()
+    {
+        return 6; 
+    }
+    
+    public ScratchRectangle getBounds()
+    {
+        return (ScratchRectangle)scratchObjects.get(0);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchImage.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchImage.java
new file mode 100644
index 0000000000000000000000000000000000000000..02d2ec4f5a6576793c39919e9dd016d3d8bd0428
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchImage.java
@@ -0,0 +1,241 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+
+/**
+ * A Scratch image resource, loaded from the Scratch Form class.
+ * 
+ * @author neil
+ *
+ */
+public class ScratchImage extends ScratchObject
+{
+    // The ScratchObject representing the bits.  Almost certainly an object reference
+    // When it is resolved, the actual image will be stored in the "img" field
+    private ScratchObject bitsRef;
+    private int w;
+    private int h;
+    private int d;
+    private int offset;
+    // The image, only valid after resolve is called
+    private BufferedImage img;
+    // The ScratchObject representing the palette.  Almost certainly an object reference
+    // When it is resolved, the actual image will be stored in the "palette" field
+    private ScratchObject paletteRef;
+    private Color[] palette;
+    
+    private boolean isResolved = false;
+    
+    /**
+     * Constructs a ScratchImage using the data read from the file
+     * @param w Width of image
+     * @param h Height of image
+     * @param d Depth (number of *bits* (not bytes) per pixel)
+     * @param offset Offset (TODO work out how this is used)
+     * @param bitsRef Reference to byte array with raw compressed data
+     * @param paletteRef Reference to palette (array of colours)
+     */
+    public ScratchImage(int w, int h, int d, int offset, ScratchObject bitsRef, ScratchObject paletteRef)
+    {
+        this.w = w;
+        this.h = h;
+        this.d = d;
+        this.offset = offset;
+        this.bitsRef = bitsRef;
+        this.paletteRef = paletteRef;            
+    }
+
+    /**
+     * Resolves the references for bits and palette, and decodes the image
+     */
+    public ScratchObject resolve(ArrayList<ScratchObject> objects) {
+        if (isResolved) return this;
+        
+        if (paletteRef != null) {
+            ScratchObject resolvedPalette = paletteRef.resolve(objects);
+            ScratchObject[] pal = (ScratchObject[])resolvedPalette.getValue();
+            
+            palette = new Color[pal.length];
+            for (int i = 0;i < pal.length;i++) {
+                palette[i] = (Color)pal[i].resolve(objects).getValue();
+            }
+        }
+        
+        // The compression scheme is documented in the 
+        // Graphics-Primitives.Bitmap.compress:toByteArray: method
+        
+        img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
+               
+        ScratchObject resolved = bitsRef.resolve(objects);
+        
+        if (resolved.getValue() instanceof int[]) {
+            // Uncompressed:
+            int[] values = (int[])resolved.getValue();
+            for (int pos = 0; pos < values.length;pos++) {
+                setBitmapEntry(pos, values[pos]);
+            }
+            
+        } else if (resolved.getValue() instanceof byte[]) {
+            //Compressed, need to decompress:
+            ByteArrayInputStream bitsInput = new ByteArrayInputStream((byte[]) resolved.getValue());
+            
+            
+    
+            int bitmapPos = 0;
+            // Skip the length at the very beginning of the image
+            // It tells us final size but we already know that:
+            decodeLen(bitsInput);
+            for (int rawN = decodeLen(bitsInput);rawN != -1;rawN = decodeLen(bitsInput)) {
+                // Lowest two bits contain a 0-3 code
+                // Rest of bits contain a count of (4-byte) words:
+                int wordCount = rawN >> 2;
+                switch (rawN & 0x3) {
+                case 0: // Skip that many words
+                    bitmapPos += wordCount;
+                break;
+                case 1: { // Replicate next byte to all 4 bytes to wordCount words:
+                    int b = bitsInput.read();
+                    int x = (b << 24) | (b << 16) | (b << 8) | b;
+                    int end = bitmapPos + wordCount;
+                    while (bitmapPos < end) {
+                        setBitmapEntry(bitmapPos++, x);
+                    }
+                }
+                break;
+                case 2: { //Replicate next 4 bytes to wordCount words: 
+                    int x = 0;
+                    for (int i = 0; i < 4; i++) {
+                        x <<= 8;
+                        x |= bitsInput.read();
+                    }
+                    int end = bitmapPos + wordCount;
+                    while (bitmapPos < end) {
+                        setBitmapEntry(bitmapPos++, x);
+                    }
+                }
+                break;
+                case 3: { //Exact wordCount words follows (no repetition) 
+                    int end = bitmapPos + wordCount;
+                    while (bitmapPos < end) {
+                        int x = 0;
+                        for (int i = 0; i < 4; i++) {
+                            x <<= 8;
+                            x |= bitsInput.read();
+                        }
+                        
+                        setBitmapEntry(bitmapPos++, x);
+                    }
+                }
+                break;
+                }
+            }
+        }
+        
+        isResolved = true;
+
+        return this;
+    }
+    
+    private void setBitmapEntry(int pos, int val)
+    {
+        final int pixelsPerWord = 32 / d;
+        for (int i = 0; i < pixelsPerWord;i++) {
+            int index = d == 32 ? val : val & ((1 << d) - 1);
+            
+            // Number of pixels per row divided by pixels-per-word gives number of words per row:
+            int realWidth = (w + (pixelsPerWord - 1)) / pixelsPerWord;
+            
+            // Take remainder from word-position by words per row to get
+            // index of words into row, then times by pixels-per-word to get number of pixels,
+            // then add i (number of pixels into word)
+            int x = ((pos % realWidth) * pixelsPerWord) + (pixelsPerWord - i);
+            // Divide word-position by words per row to get row 
+            int y = pos / realWidth;
+            // Some bits can be beyond the image due to aligning the images to nice 2^n sizes:
+            if (x < w && y < h) {
+                if (palette != null) {
+                    img.setRGB(x, y, palette[index].getRGB());
+                } else {
+                    // If the alpha is zero but the other channels are not,
+                    // set alpha to 255.  I can't find any part of the Scratch code
+                    // that does this, but it's the only rule I can find
+                    // that seems to make the images work correctly.
+                    if (index >> 24 == 0 && (index & 0xFFFFFF) != 0) {
+                        index |= 0xFF000000;
+                    }
+                    img.setRGB(x, y, index);
+                }
+            }
+            
+            val >>= d;
+        }
+    }
+
+
+    /**
+     * Decodes a count field.
+     * Anything above 0xE0 has its low bits (& 0x1F) merged with the next number
+     */
+    private int decodeLen(ByteArrayInputStream bitsInput)
+    {
+        int x = 0;
+        int first = bitsInput.read();
+        
+        if (first == -1) //EOF
+            return -1;
+        
+        if (first == 0xFF) {
+            for (int i = 0; i < 4; i++) {
+                x <<= 8;
+                x |= bitsInput.read();
+            }
+            return x;
+        } else if (first >= 0xE0) {
+            x = (first & 0x1F) << 8;
+            x |= bitsInput.read();
+        } else {
+            x = first;
+        }
+        return x;
+    }
+
+    public int getWidth()
+    {
+        return w;
+    }
+
+    public int getHeight()
+    {
+        return h;
+    }
+
+    public BufferedImage getBufferedImage()
+    {
+        return img;
+    }
+    
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchImport.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchImport.java
new file mode 100644
index 0000000000000000000000000000000000000000..28f7c8bb3945a70cd232a71684ffeb20dc834a87
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchImport.java
@@ -0,0 +1,392 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+
+import greenfoot.core.GreenfootMain;
+
+import java.awt.Color;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import bluej.pkgmgr.PackageFile;
+import bluej.pkgmgr.PackageFileFactory;
+import bluej.utility.Debug;
+
+public class ScratchImport
+{   
+    /**
+     * Reads a fixed number of bytes, treats them as ASCII, and returns them as a String
+     */
+    private static String readFixedASCII(FileInputStream input, int num) throws IOException
+    {
+        byte[] b = new byte[num];
+        input.read(b);
+        return new String(b, Charset.forName("US-ASCII"));
+    }
+    
+    /**
+     * Reads a fixed number of bytes, treats them as UTF8, and returns them as a String
+     */
+    private static String readUTF8(FileInputStream input, int num) throws IOException
+    {
+        byte[] b = new byte[num];
+        input.read(b);
+        return new String(b, Charset.forName("UTF-8"));
+    }
+    
+    /**
+     * Reads the version string from the file
+     */
+    private static void readVersion(FileInputStream input) throws IOException 
+    {
+        String ver = readFixedASCII(input, 10);
+        if ("ScratchV01".equals(ver)) {
+            //Version 1
+        } else if ("ScratchV02".equals(ver)) {
+            //Version 2
+        } else {
+            Debug.message("Unknown Scratch version: " + ver);
+        }
+    }
+    
+    /**
+     * Reads a big-endian int using the given number of bytes
+     * 
+     * The Scratch format has all sorts of integer sizes, including 3 bytes.
+     */
+    private static long readInt(FileInputStream input, int bytes) throws IOException
+    {
+        long x = 0;
+        for (int i = 0; i < bytes; i++)
+        {
+            x <<= 8;
+            x |= input.read();
+        }
+        
+        // Fix negative numbers when less than 8-bytes:
+        if (x >> ((8 * bytes) - 1) != 0 && bytes < 8) {
+            // When upper bit is one, perform sign extension:
+            x |= 0xFFFFFFFFFFFFFFFFL << (8 * bytes);
+        }
+        
+        return x;
+    }
+
+    /**
+     * Reads the header from a Scratch file (the version, and the info block, which is skipped)
+     */
+    private static void readHeader(FileInputStream input) throws IOException
+    {
+        readVersion(input);
+        int infoSize = (int)readInt(input, 4);
+        input.skip(infoSize);
+    }
+    
+    private static ScratchObject readObject(FileInputStream input) throws IOException
+    {
+        int id = input.read();
+        if (id == -1)
+            return null;
+        
+        if (id >= 100) {
+            //User Object
+            return readUserObject(id, input);
+        } else {
+            //Primitive (fixed-format) object, or reference:
+            return readPrimitiveOrReferenceWithGivenId(id, input);
+        }
+    }
+    
+    // See Scratch Object IO.ObjStream.readObjectRecord
+    private static ScratchUserObject readUserObject(int id, FileInputStream input) throws IOException
+    {
+        int version = input.read();
+        int fieldAmount = input.read();
+        
+        List<ScratchObject> scratchObjects = Arrays.asList(readFields(input, fieldAmount));
+        
+        switch (id) {
+        case ScratchUserObject.IMAGE_MEDIA:
+            return new ImageMedia(version, scratchObjects);
+        case ScratchUserObject.SOUND_MEDIA:
+            return new SoundMedia(version, scratchObjects);
+        case ScratchUserObject.SCRATCH_STAGE_MORPH:
+            return new ScratchStageMorph(version, scratchObjects);
+        case ScratchUserObject.SCRATCH_SPRITE_MORPH:
+            return new ScratchSpriteMorph(version, scratchObjects);
+        default: 
+            return new ScratchUserObject(id, version, scratchObjects);
+        }
+    }
+    
+    private static ScratchObject readPrimitiveOrReference(FileInputStream input) throws IOException
+    {
+        int id = input.read();
+        return readPrimitiveOrReferenceWithGivenId(id, input);
+    }
+    
+    // See Scratch Object IO.ObjStream.readField and Scratch Object IO.ObjStream.<class>  
+    private static ScratchObject readPrimitiveOrReferenceWithGivenId(int id, FileInputStream input) throws IOException
+    {
+        switch (id)
+        {
+        case 99: //Object Reference (3-byte one-based index into object table):
+            return new ScratchObjectReference((int)readInt(input, 3));
+        
+        case 1: return null; //Undefined -- is null okay?
+        case 2: // True 
+        case 3: // False
+            return new ScratchPrimitive(new Boolean(id == 2));
+        case 4: //4-byte integer
+            return new ScratchPrimitive(new BigDecimal(readInt(input, 4)));
+        case 5: //2-byte integer 
+            return new ScratchPrimitive(new BigDecimal(readInt(input, 2)));
+        case 8: { /* Float */
+            long bits = readInt(input, 8);
+            return new ScratchPrimitive(new BigDecimal(Double.longBitsToDouble(bits)));
+        } case 9:  // String
+        case 10: { // Symbol
+            int size = (int)readInt(input, 4);
+            return new ScratchPrimitive(readFixedASCII(input, size));
+        } case 11: { // ByteArray
+            int size = (int)readInt(input, 4);
+            byte[] b = new byte[size];
+            input.read(b);
+            return new ScratchPrimitive(b);
+        } case 12: { // SoundBuf -- TODO read this properly as int16s
+            int size = (int)readInt(input, 4);
+            byte[] b = new byte[size * 2];
+            input.read(b);
+            return new ScratchPrimitive(b);
+        } case 13: { //Bitmap, oddly this is effectively int[] and nothing more
+            int size = (int)readInt(input, 4);
+            int[] arr = new int[size];
+            for (int i = 0; i < size; i++) {
+                arr[i] = (int)readInt(input, 4);
+            }
+            return new ScratchPrimitive(arr);
+        } case 14: { // UTF8
+            int size = (int)readInt(input, 4);
+            return new ScratchPrimitive(readUTF8(input, size));
+        } case 20: // Array
+          case 21: { // OrderedCollection
+            int size = (int)readInt(input, 4);
+            
+            ScratchObject[] scratchObjects = readFields(input, size);
+            
+            return new ScratchObjectArray(scratchObjects);
+        } case 24: { // Dictionary
+            int size = (int)readInt(input, 4);
+            ScratchObject[] keyValues = readFields(input, size*2);
+            HashMap<ScratchObject, ScratchObject> map = new HashMap<ScratchObject, ScratchObject>();
+            for (int i = 0; i < size; i++) {
+                map.put(keyValues[i*2], keyValues[i*2+1]);
+            }
+            return new ScratchPrimitive(map);
+        } case 30: // Color
+          case 31: { // TranslucentColor
+            int colour =(int)readInt(input, 4);
+            int alpha = id == 31 ? (int)readInt(input, 1) : 255;
+            //Smalltalk uses 10-bit colour channels, with the top 2 bits unused.
+            //So we just take the high 8 bits out of each 10-bit channel:
+            Color c = new Color((colour >> 22) & 255, (colour >> 12) & 255, (colour >> 2) & 255, alpha);
+            return new ScratchPrimitive(c);
+        } case 32: {  //Point
+            ScratchObject[] fields = readFields(input, 2);
+            BigDecimal x = (BigDecimal)fields[0].getValue();
+            BigDecimal y = (BigDecimal)fields[1].getValue();
+            return new ScratchPoint(x, y);
+        } case 33: { // Rectangle
+            ScratchObject[] fields = readFields(input, 4);
+            BigDecimal x = (BigDecimal)fields[0].getValue();
+            BigDecimal y = (BigDecimal)fields[1].getValue();
+            BigDecimal x2 = (BigDecimal)fields[2].getValue();
+            BigDecimal y2 = (BigDecimal)fields[3].getValue();
+            return new ScratchRectangle(x, y, x2, y2);
+        } case 34: // Form (an image)
+          case 35: { // ColorForm (colour image)
+              ScratchObject[] fields = readFields(input, id == 35 ? 6 : 5);
+              int w = ((BigDecimal)fields[0].getValue()).intValue();
+              int h = ((BigDecimal)fields[1].getValue()).intValue();
+              int d = ((BigDecimal)fields[2].getValue()).intValue();
+              int offset = fields[3] == null ? 0 : (Integer)fields[3].getValue();
+              ScratchObject bits = fields[4];
+              ScratchObject palette = id == 35 ? fields[5] : null;
+              return new ScratchImage(w,h,d,offset,bits, palette);
+          }
+          default:
+              Debug.message("*** UNKNOWN SCRATCH FIELD: " + id + " ***");
+              return null;
+        }
+    }
+
+    private static ScratchObject[] readFields(FileInputStream input,
+            int size) throws IOException
+    {
+        List<ScratchObject> scratchObjects = new ArrayList<ScratchObject>();
+        for (int i = 0; i < size; i++) {
+            scratchObjects.add(readPrimitiveOrReference(input));
+        }
+        return scratchObjects.toArray(new ScratchObject[0]);
+    }
+
+
+
+    private static List<ScratchObject> readObjectStore(FileInputStream input) throws IOException
+    {
+        String header = readFixedASCII(input, 10);
+        if (!"ObjS\001Stch\001".equals(header)) {
+            Debug.message("Unknown Scratch object store header: " + header);
+            return null;
+        }
+        
+        int numObjects = (int)readInt(input, 4);
+        
+        ArrayList<ScratchObject> objects = new ArrayList<ScratchObject>(numObjects);
+        for (int i = 0; i < numObjects; i++) {
+            objects.add(readObject(input));
+        }
+        
+        
+        // For debug; Print before resolving, otherwise we have circular references and print forever:
+        //int c = 1;
+        //for (ScratchObject m : objects) {
+        //    Debug.message(c + ": " + m);
+        //    c++;
+        //}
+        
+        // Resolve all objects:
+        for (int i = 0; i < objects.size(); i++) {
+            if (objects.get(i) != null) {
+                objects.set(i, objects.get(i).resolve(objects));
+            }
+        }
+        
+        return objects;
+    }
+
+    private static void importScratch(File src, File dest)
+    {
+        try {
+            FileInputStream input = new FileInputStream(src);
+        
+            readHeader(input);
+            List<ScratchObject> objects = readObjectStore(input);
+            
+            Properties props = new Properties();
+            props.setProperty("version", GreenfootMain.getAPIVersion().toString());
+            for (ScratchObject o : objects) {
+                o.saveInto(dest, props, null);
+            }
+            
+            File javaFile = new File(dest, "Bubble.java");
+            FileWriter javaFileWriter = new FileWriter(javaFile);
+            javaFileWriter.write("import greenfoot.*;\nimport java.awt.Color;\npublic class Bubble extends Actor \n{\n");
+            javaFileWriter.write("public Bubble(String s)\n{\nsetImage(new GreenfootImage(s, 15, Color.BLACK, Color.WHITE));\n}\n");
+            javaFileWriter.write("public void act()\n{\n}\n");
+            javaFileWriter.write("}\n");
+            javaFileWriter.close();
+            
+            
+            PackageFile packageFile = PackageFileFactory.getPackageFile(dest);
+            packageFile.create();
+            packageFile.save(props);
+            
+        } catch (IOException e) {
+            Debug.reportError("Problem during Scratch import", e);
+        }
+    }
+
+    public static File convert(File scratchFile)
+    {
+        String archiveName = scratchFile.getName();
+        int dotIndex = archiveName.lastIndexOf('.');
+        String strippedName = null;
+        if(dotIndex != -1) {
+            strippedName = archiveName.substring(0, dotIndex);
+        } else {
+            strippedName = archiveName;
+        }
+        File dest = new File(scratchFile.getParentFile(), strippedName);
+        
+        int i = 0;
+        while (dest.exists()) {
+            dest = new File(scratchFile.getParentFile(), strippedName + i);
+            i++;
+        }
+        
+        existingNames = new HashSet<String>();
+        existingNames.add("World");
+        existingNames.add("Actor");
+        
+        importScratch(scratchFile, dest);
+        
+        return dest;
+    }
+    
+    private static Set<String> existingNames;
+    
+    // Munges a Scratch name into a valid Java class name, also
+    // avoiding naming anything World or Actor, and taking care to avoid duplicates
+    // Therefore you should only call this method once per name you want to convert.
+    static String mungeUnique(String orig)
+    {
+        StringBuilder r = new StringBuilder();
+        if (orig.length() > 0) {
+            if (Character.isJavaIdentifierStart(orig.charAt(0))) {
+                r.append(orig.charAt(0));
+            } else {
+                r.append("C");
+            }
+            for (char c : Arrays.copyOfRange(orig.toCharArray(),1, orig.toCharArray().length)) {
+                if (Character.isJavaIdentifierPart(c)) {
+                    r.append(c);
+                }
+            }
+        }
+        String initial = r.toString();
+        String result;
+        if (initial.length() == 0 || existingNames.contains(initial)) {
+            int i = 0;
+            while (existingNames.contains(initial + i)) {
+                i += 1;
+            }
+            result = initial + i;
+        } else {
+            result = initial;
+        }
+        existingNames.add(result);
+        return result;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchMedia.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchMedia.java
new file mode 100644
index 0000000000000000000000000000000000000000..5fe62369606df76525ba0a26bf0e36d44968062b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchMedia.java
@@ -0,0 +1,54 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.util.List;
+
+/**
+ * Mirrors the Scratch ScratchMedia class, which is the base class for ImageMedia and SoundMedia.
+ * 
+ * It only holds the name of the media, but that's useful for us.
+ * 
+ * @author neil
+ *
+ */
+public class ScratchMedia extends ScratchUserObject
+{
+
+    public ScratchMedia(int id, int version, List<ScratchObject> scratchObjects)
+    {
+        super(id, version, scratchObjects);
+    }
+    
+    // Fields:
+    //  mediaName (String)
+    
+    @Override public int fields()
+    {
+        return 1;
+    }
+
+    public String getMediaName()
+    {
+        return (String)scratchObjects.get(0).getValue();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchObject.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..6365e9d558dbfcb2ff2369ba80c90a842987a072
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchObject.java
@@ -0,0 +1,75 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Properties;
+
+/**
+ * A Scratch object.  This can be a user-object (which includes sprites, stages, images, etc)
+ * or it can be a primitive (byte array, colour, etc); this is taken care of by various
+ * sub-classes.
+ * @author neil
+ */
+public class ScratchObject
+{
+    /**
+     * Resolves all ScratchObjectReferences inside this object.
+     * 
+     * Because Scratch objects stored in the file may have circular references,
+     * they are stored in a long table, and any pointers to objects in the table
+     * are stored as ScratchObjectReference.  Once everything is loaded,
+     * we invoke this method everywhere, passing the object table,
+     * so that the references can get resolved.
+     * 
+     * @param objects
+     * @return The resolved object.  Returns "this" by default,
+     *   but ScratchObjectReferences will return a different object.
+     */
+    public ScratchObject resolve(ArrayList<ScratchObject> objects)
+    {
+        return this;
+    }
+    
+    /**
+     * Gets the value for this object.  You will mainly want to call this
+     * and cast the result when you have an expectation of the inner class.
+     * For example, you may expect a colour, so you call getValue() and cast
+     * to java.awt.Color.
+     * @return The value represented by this object; by default returns "this",
+     *   but ScratchPrimitive will return the primitive value inside.
+     */
+    public Object getValue()
+    {
+        return this;
+    }
+
+    /**
+     * Saves the item (e.g. image, sound, class) in the given project
+     */
+    public File saveInto(File destDir, Properties props, String prefix) throws IOException
+    {
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchObjectArray.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchObjectArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..00d42ff8ddc8c356a411515d4179ac37b4dc27cf
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchObjectArray.java
@@ -0,0 +1,84 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+
+/**
+ * An array (well, collection) of ScratchObjects.
+ * 
+ * This needs its own class, rather than using ScratchPrimitive, because resolve
+ * calls must recurse into the array in case there are object-references in the array
+ * (in fact, this is almost always the case).
+ * 
+ * It is possible for entries in the array to be null, although the array
+ * itself should not be null.
+ * 
+ * @author neil
+ */
+class ScratchObjectArray extends ScratchObject implements Iterable<ScratchObject>
+{
+    @Override
+  public void forEach(Consumer<? super ScratchObject> action) {
+    // TODO Auto-generated method stub
+    
+  }
+
+  @Override
+  public Spliterator<ScratchObject> spliterator() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+    private ScratchObject[] value;
+
+    public ScratchObjectArray(ScratchObject[] value)
+    {
+        this.value = value;
+    }
+    
+    @Override public ScratchObject[] getValue()
+    {
+        return value;
+    }
+
+    @Override
+    public ScratchObject resolve(ArrayList<ScratchObject> objects)
+    {
+        for (int i = 0; i < value.length; i++) {
+            if (value[i] != null) {
+                value[i] = value[i].resolve(objects);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public Iterator<ScratchObject> iterator()
+    {
+        return Arrays.asList(value).iterator();
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchObjectReference.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchObjectReference.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b54d928df0b3cad9c2d728670705762ba8dd745
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchObjectReference.java
@@ -0,0 +1,56 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.util.ArrayList;
+
+/**
+ * Represents a reference to a real ScratchObject
+ * 
+ * This class is used when first loading from the store file, but after resolve
+ * is called, a real (non-reference) ScratchObject will be returned, and thus
+ * all instances of ScratchObjectReference will disappear from view.
+ * 
+ * @author neil
+ *
+ */
+class ScratchObjectReference extends ScratchObject
+{
+    // The one-based index into the object table
+    private int index;
+    
+    public ScratchObjectReference(int i)
+    {
+        index = i;
+    }
+
+    public ScratchObject resolve(ArrayList<ScratchObject> objects)
+    {
+        // Convert one-based index to zero-based index into the array list:
+        return objects.get(index - 1);
+    }
+    
+    public String toString()
+    {
+        return "{#" + index + "}";
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchPoint.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchPoint.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f8137f9116c4245c761d039d9ce413a7574c682
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchPoint.java
@@ -0,0 +1,53 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.math.BigDecimal;
+
+/**
+ * As with ScratchRectangle, we use our own class because the bounds can be in any
+ * number format
+ * @author neil
+ *
+ */
+public class ScratchPoint extends ScratchObject
+{
+    public BigDecimal x, y;
+
+    public ScratchPoint(BigDecimal x, BigDecimal y)
+    {
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder();
+        builder.append("ScratchPoint [x=");
+        builder.append(x);
+        builder.append(", y=");
+        builder.append(y);
+        builder.append("]");
+        return builder.toString();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchPrimitive.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchPrimitive.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae9c4140c9b8361da4661336ff7793a25a1fe634
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchPrimitive.java
@@ -0,0 +1,49 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+/**
+ * A primitive value (e.g. string, byte array, colour)
+ * 
+ * Things like int are stored as Integer 
+ * 
+ * @author neil
+ */
+class ScratchPrimitive extends ScratchObject
+{
+    private Object value;
+
+    public ScratchPrimitive(Object value)
+    {
+        this.value = value;
+    }
+    
+    public Object getValue()
+    {
+        return value;
+    }
+    
+    public String toString()
+    {
+        return value == null ? "null" : value.toString();
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchRectangle.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchRectangle.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a0570068d4162e05a910a2bb5dac6cb7ef9d0ca
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchRectangle.java
@@ -0,0 +1,81 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.math.BigDecimal;
+
+/**
+ * Represents a Rectangle in Scratch.
+ * 
+ * We can't use java.awt.Rectangle (for example) because Scratch rectangles can
+ * have floating point or integer limits, so hence we must store all measurements
+ * using the a class that can represent all of those.  Number would do it, but we also
+ * need to perform calculations so BigDecimal seems like a good alternative (plus, Scratch
+ * does support arbitrary precision integers).
+ * 
+ * @author neil
+ *
+ */
+public class ScratchRectangle extends ScratchObject
+{
+    // x and y are the top-left of the rectangle, x2 and y2 are the bottom right
+    public BigDecimal x, y, x2, y2;
+
+    public ScratchRectangle(BigDecimal x, BigDecimal y, BigDecimal x2, BigDecimal y2)
+    {
+        this.x = x;
+        this.y = y;
+        this.x2 = x2;
+        this.y2 = y2;
+    }
+    
+    public BigDecimal getWidth()
+    {
+        return x2.subtract(x);
+    }
+    
+    public BigDecimal getHeight()
+    {
+        return y2.subtract(y);
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder();
+        builder.append("ScratchRectangle [x=");
+        builder.append(x);
+        builder.append(", x2=");
+        builder.append(x2);
+        builder.append(", y=");
+        builder.append(y);
+        builder.append(", y2=");
+        builder.append(y2);
+        builder.append("]");
+        return builder.toString();
+    }
+
+    public ScratchPoint getMiddle()
+    {
+        return new ScratchPoint(x.add(x2).divide(new BigDecimal(2)), y.add(y2).divide(new BigDecimal(2)));
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchSpriteMorph.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchSpriteMorph.java
new file mode 100644
index 0000000000000000000000000000000000000000..e107a46e9b8f037aae5a16f3fcbdba8f7df409ff
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchSpriteMorph.java
@@ -0,0 +1,94 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * Mirrors the Scratch ScratchSpriteMorph class, which is the equivalent of an actor.
+ * @author neil
+ *
+ */
+public class ScratchSpriteMorph extends ScriptableScratchMorph
+{
+    public ScratchSpriteMorph(int version, List<ScratchObject> scratchObjects)
+    {
+        super(ScratchUserObject.SCRATCH_SPRITE_MORPH, version, scratchObjects);
+    }
+    
+    // Fields:
+    //  visibility, scalePoint, rotationDegrees, rotationStyle, volume, tempoBPM, draggable, sceneStates, lists
+    
+    @Override public int fields()
+    {
+        return 9;
+    }
+
+    @Override
+    protected void constructorContents(StringBuilder acc)
+    {
+        acc.append("GreenfootImage img = getImage();\n");
+        acc.append("img.scale(")
+           .append(getBounds().getWidth().intValue())
+           .append(", ")
+           .append(getBounds().getHeight().intValue())
+           .append(");\n");
+    }
+
+    @Override
+    protected String greenfootSuperClass()
+    {
+        return "Actor";
+    }
+    
+    @Override
+    public ScratchPoint getScaleAmount()
+    {
+        return (ScratchPoint) scratchObjects.get(super.fields() + 1);
+    }
+
+    public ScratchPoint getGreenfootCentre()
+    {
+        return new ScratchPoint(getBounds().getMiddle().x.subtract(
+                                    getScaleAmount().x.subtract(new BigDecimal(1)).multiply(
+                                      getCostume().getRotationCentre().x
+                                    )
+                                )
+                               ,getBounds().getMiddle().y.subtract(
+                                    getScaleAmount().y.subtract(new BigDecimal(1)).multiply(
+                                      getCostume().getRotationCentre().y
+                                    )
+                               ) );
+                
+    }
+    
+    @Override
+    protected void addHelpers(StringBuilder acc)
+    {
+        acc.append("private void turn(int angle)\n{\nsetRotation(getRotation() + angle);\n}\n");
+        acc.append("private void move(int speed)\n{\ndouble angle = Math.toRadians( getRotation() );\nint x = (int) Math.round(getX() + Math.cos(angle) * speed);\nint y = (int) Math.round(getY() + Math.sin(angle) * speed);\nsetLocation(x, y);\n}\n");
+        acc.append("private boolean atWorldEdge()\n{\nif(getX() < 20 || getX() > getWorld().getWidth() - 20) return true;\nif(getY() < 20 || getY() > getWorld().getHeight() - 20) return true;\nelse return false;\n}\n");
+        //acc.append("private void setTopLeft(int x, int y)\n{setLocation(x + (getImage().getWidth()/2),y + (getImage().getHeight()/2));\n}\n");
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchStageMorph.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchStageMorph.java
new file mode 100644
index 0000000000000000000000000000000000000000..acafb195a454eb7d4808ab43730daed1dfad6808
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchStageMorph.java
@@ -0,0 +1,90 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Mirrors the Scratch ScratchStageMorph class, which is the equivalent of World.
+ * @author neil
+ *
+ */
+public class ScratchStageMorph extends ScriptableScratchMorph
+{
+    public ScratchStageMorph(int version, List<ScratchObject> scratchObjects)
+    {
+        super(ScratchUserObject.SCRATCH_STAGE_MORPH, version, scratchObjects);
+    }
+    
+    // Fields:
+    //  zoom (int), hPan (int), vPan (int), obsoleteSavedState (?), sprites (array), volume (int), tempoBPM (int), sceneStates (?), lists(?)
+    
+    @Override public int fields()
+    {
+        return super.fields() + 9;
+    }
+    
+    ScratchObjectArray getSprites()
+    {
+        return (ScratchObjectArray)scratchObjects.get(super.fields() + 4);
+    }
+
+    @Override
+    protected void constructorContents(StringBuilder acc)
+    {
+        ImageMedia image = getCostume();
+        //TODO should this actually be our bounds rather than the world's image -- can we be stretched?
+        acc.append("super(").append(image.getWidth()).append(", ").append(image.getHeight()).append(", 1);\n");
+        
+        LinkedList<String> classes = new LinkedList<String>();
+        
+        ScratchObjectArray sprites = getSprites();
+        for (ScratchObject o : sprites.getValue()) {
+            ScratchSpriteMorph sprite = (ScratchSpriteMorph)o;
+            String spriteName = sprite.getObjNameJava();
+            acc.append("addObject(new ").append(spriteName).append("(), ");
+            acc.append(sprite.getGreenfootCentre().x.intValue());
+            acc.append(", ");
+            acc.append(sprite.getGreenfootCentre().y.intValue());
+            acc.append(");\n");
+            
+            // Add at beginning so that later classes will get drawn first:
+            classes.addFirst(spriteName); 
+        }
+        
+        if (!classes.isEmpty()) {
+            acc.append("setPaintOrder(Bubble.class");
+            for (String cls : classes) {
+                acc.append(", ").append(cls).append(".class");
+            }
+            acc.append(");\n");
+        }
+    }
+
+    @Override
+    protected String greenfootSuperClass()
+    {
+        return "World";
+    }
+}
+
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchUserObject.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchUserObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..e211fac60f5a8a71fbf8a9322073c825fd072563
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScratchUserObject.java
@@ -0,0 +1,87 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A Scratch user-defined object (as opposed to an array or primitive type).
+ * @author neil
+ *
+ */
+class ScratchUserObject extends ScratchObject
+{
+    // See the table in Scratch-Object IO.ObjStream.<class>.userClasses
+    protected static final int SCRATCH_SPRITE_MORPH = 124;
+    protected static final int SCRATCH_STAGE_MORPH = 125;
+    protected static final int IMAGE_MEDIA = 162;
+    protected static final int SOUND_MEDIA = 164;
+    
+    private int id;
+    private int version;
+    protected List<ScratchObject> scratchObjects;
+    public ScratchUserObject(int id, int version, List<ScratchObject> scratchObjects)
+    {
+        this.id = id;
+        this.version = version;
+        this.scratchObjects = scratchObjects;
+    }
+    
+    @Override public ScratchObject resolve(ArrayList<ScratchObject> objects)
+    {
+        for (int i = 0; i < scratchObjects.size(); i++) {
+            ScratchObject scratchObject = scratchObjects.get(i);
+            if (scratchObject != null) {
+                scratchObjects.set(i, scratchObject.resolve(objects));
+            }
+        }
+        return this;
+    }
+
+    /**
+     * The number of fields that this class loads from the file in total.
+     * 
+     * This should usually be implemented as super.fields() + N.
+     */
+    public int fields()
+    {
+        return 0;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder();
+        builder.append("ScratchUserObject [id=");
+        builder.append(id);
+        builder.append("]\n  {");
+        for (ScratchObject o : scratchObjects) {
+            builder.append(o).append(",");
+        }
+        builder.append("}");
+        return builder.toString();
+    }
+    
+    
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScriptableScratchMorph.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScriptableScratchMorph.java
new file mode 100644
index 0000000000000000000000000000000000000000..6632fbc62c5e636084c4ac8397b3e935b778554c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/ScriptableScratchMorph.java
@@ -0,0 +1,495 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import bluej.utility.Debug;
+
+public abstract class ScriptableScratchMorph extends Morph
+{
+    private String[] costumes;
+    private String mungedName;
+    private File javaFile;
+
+    public ScriptableScratchMorph(int id, int version,
+            List<ScratchObject> scratchObjects)
+    {
+        super(id, version, scratchObjects);
+    }
+    
+    // Fields:
+    //  objName (String), vars (?), blocksBin (array), isClone (boolean), media (array), costume (SObject, 162)
+    
+    @Override public int fields()
+    {
+        return super.fields() + 6;
+        
+    }
+    
+    // Make this private to prevent accidental use by sub-classes
+    // (most of the time we are using objName as a proxy for class name,
+    //  but objName can contain spaces so isn't always a valid Java identifier)
+    private String getObjName()
+    {
+        return (String)scratchObjects.get(super.fields() + 0).getValue();
+    }
+    
+    public String getObjNameJava()
+    {
+        if (mungedName == null) {
+            Debug.message("Munging: " + getObjName());
+            mungedName = ScratchImport.mungeUnique(getObjName());
+            Debug.message("Munged to: " + mungedName);
+        }
+        return mungedName;
+    }
+    
+    public ScratchObjectArray getBlocks()
+    {
+        return (ScratchObjectArray)scratchObjects.get(super.fields() + 2);
+    }
+    
+    public ScratchObjectArray getMedia()
+    {
+        return (ScratchObjectArray)scratchObjects.get(super.fields() + 4);
+    }
+
+    public ImageMedia getCostume()
+    {
+        return (ImageMedia)scratchObjects.get(super.fields() + 5);
+    }
+    
+    public ImageMedia[] getCostumes()
+    {
+        ArrayList<ImageMedia> imgs = new ArrayList<ImageMedia>();
+        ScratchObjectArray objArray = (ScratchObjectArray)scratchObjects.get(super.fields() + 4);
+        for (ScratchObject o : objArray.getValue()) {
+            if (o instanceof ImageMedia) {
+                imgs.add((ImageMedia)o);
+            }
+        }
+        return imgs.toArray(new ImageMedia[0]);
+    }
+    
+    public int getCostumeCount()
+    {
+        return ((ScratchObjectArray)scratchObjects.get(super.fields() + 4)).getValue().length;
+    }
+    
+    protected abstract String greenfootSuperClass();
+    protected abstract void constructorContents(StringBuilder acc);
+
+    @Override
+    public File saveInto(File destDir, Properties props, String prefix) throws IOException
+    {
+        if (javaFile != null) return javaFile;
+        
+        // blocksBin is at the same index for all scriptable things:
+        ScratchObject imageMedia = getCostume();            
+        String className = getObjNameJava();
+        
+        StringBuilder acc = new StringBuilder();
+        acc.append("import greenfoot.*;\npublic class " + className);
+        
+        String superClass = greenfootSuperClass();
+        if (superClass != null) {
+            acc.append(" extends ").append(superClass);
+        }
+        
+        costumes = new String[getCostumeCount()];
+        
+        acc.append("\n{\n");
+        acc.append("private static final String[] COSTUMES = new String[] {");
+        int i = 0;
+        int curCostume = 0;
+        for (ImageMedia img : getCostumes()) {
+            if (i != 0) acc.append(", ");
+            costumes[i] = img.saveInto(destDir, props, className + "_").getName();
+            acc.append("\"").append(costumes[i]).append("\"");
+            if (img == imageMedia) {
+                curCostume = i;
+            }
+            i += 1;
+        }
+        acc.append("};\n");
+        acc.append("private static final int[] X_OFFSETS = new int[] {");
+        i = 0;
+        for (ImageMedia img : getCostumes()) {
+            if (i != 0) acc.append(", ");
+            acc.append(
+                  getScaleAmount().x.multiply(
+                    new BigDecimal(img.getWidth() / 2).subtract(
+                      img.getRotationCentre().x
+                    )
+                  ).intValue());
+            i++;
+        }
+        acc.append("};\n");
+        
+        acc.append("private static final int[] Y_OFFSETS = new int[] {");
+        i = 0;
+        for (ImageMedia img : getCostumes()) {
+            if (i != 0) acc.append(", ");
+            acc.append(
+                    getScaleAmount().y.multiply(
+                      new BigDecimal(img.getHeight() / 2).subtract(
+                        img.getRotationCentre().y
+                      )
+                    ).intValue());
+            i++;
+        }
+        acc.append("};\n");
+        
+        acc.append("private int curCostume = ").append(curCostume).append(";\n");
+        
+        acc.append("public " + className + "()\n{\n");
+        constructorContents(acc);    
+        acc.append("}\n");
+        
+        addHelpers(acc);
+
+        codeForScripts(getBlocks(), acc, new LoopVarIterator());
+        acc.append("}\n");
+        
+        javaFile = new File(destDir, className + ".java");
+        FileWriter javaFileWriter = new FileWriter(javaFile);
+        javaFileWriter.write(acc.toString());
+        javaFileWriter.close();
+        
+        for (ScratchObject media : getMedia()) {
+            media.saveInto(destDir, props, className + "_");
+        }
+        
+        
+        File imageFile = imageMedia.saveInto(destDir, props, className + "_");
+        props.setProperty("class." + className + ".image", imageFile.getName());
+        
+        return javaFile;
+    }
+
+    protected void addHelpers(StringBuilder acc)
+    {
+    }
+
+    private void codeForBlock(ScratchObject block, StringBuilder decl, StringBuilder method, LoopVarIterator loopVars)
+    {
+        // Each block is an array of entries.  For example, if you have
+        // a repeat block, that will be an array of three things:
+        // [doRepeat, <the number of counts>, <the block to repeat>]
+        // The block to repeat will in turn be an array and so on!
+        ScratchObject[] blockContents = (ScratchObject[])block.getValue();
+        
+        if ("doRepeat".equals(blockContents[0].getValue())) {
+            String var = loopVars.next();
+            method.append("for (int " + var + " = 0; " + var + " < ").append(blockContents[1].getValue()).append(";" + var + "++)\n{\n");
+            codeForBlock(blockContents[2], decl, method, new LoopVarIterator(loopVars));
+            method.append("}\n");
+        }
+        else if ("doPlaySoundAndWait".equals(blockContents[0].getValue())) {
+            String soundName = ScratchImport.mungeUnique("snd" + (String)blockContents[1].getValue());
+            decl.append("GreenfootSound ").append(soundName).append(";\n");
+            method.append("if (" + soundName + " == null || !" + soundName + ".isPlaying()) {\n")
+            	  .append(soundName).append(" = new GreenfootSound(\"")
+            	  .append(getObjNameJava()).append("_")
+                  .append(blockContents[1].getValue())
+                  .append(".wav\");\n")
+                  .append(soundName).append(".play();\n}\n");
+            // TODO need a state machine to wait in the state until done playing
+        }
+        else if ("playSound:".equals(blockContents[0].getValue())) {
+            method.append("new GreenfootSound(\"")
+                  .append(getObjNameJava()).append("_")
+                  .append(blockContents[1].getValue())
+                  .append(".wav\").play();\n");
+        }
+        else if ("setGraphicEffect:to:".equals(blockContents[0].getValue())) {
+            if ("ghost".equals(blockContents[1].getValue())) {
+                method.append("getImage().setTransparency(")
+                      .append(new BigDecimal(255).subtract(((BigDecimal)blockContents[2].getValue()).multiply(new BigDecimal(255.0 / 100.0))).intValue())
+                      .append(");\n");
+            }
+        }
+        else if ("hide".equals(blockContents[0].getValue())) {
+            method.append("getImage().setTransparency(0);\n");
+        }
+        else if ("show".equals(blockContents[0].getValue())) {
+            method.append("getImage().setTransparency(255);\n");
+        }
+        else if ("lookLike:".equals(blockContents[0].getValue())) {
+            if (blockContents[1].getValue() instanceof String) {
+                String costumeRoot = getObjNameJava() + "_" + (String)blockContents[1].getValue();
+                
+                int costumeFile = findCostume(costumeRoot + ".png");
+                if (costumeFile >= 0) {
+                    costumeRoot += ".png";
+                } else {
+                    costumeFile = findCostume(costumeRoot + ".jpg");
+                    if (costumeFile >= 0) costumeRoot += ".jpg";
+                }
+                if (costumeFile >= 0) {
+                    method.append("curCostume = ")
+                          .append(costumeFile)
+                          .append(";\n");
+                    method.append("setImage(\"").append(costumeRoot).append("\");\n");
+                    method.append("getImage().scale(")
+                          .append(getBounds().x2.subtract(getBounds().x).intValue())
+                          .append(", ")
+                          .append(getBounds().y2.subtract(getBounds().y).intValue())
+                          .append(");\n");
+                    method.append("getWorld().repaint();\n");
+                } else {
+                    Debug.message("Could not locate costume: " + costumeFile);
+                }
+            }
+        }
+        else if ("forward:".equals(blockContents[0].getValue())) {
+            method.append("move(").append(blockContents[1].getValue()).append(");\n");
+        }
+        else if ("bounceOffEdge".equals(blockContents[0].getValue())) {
+            method.append("if (atWorldEdge()) turn(180);\n");
+        }
+        else if ("randomFrom:to:".equals(blockContents[0].getValue())) {
+            int from = (Integer)blockContents[1].getValue();
+            int to = (Integer)blockContents[2].getValue();
+            if (from == 0) {
+                method.append("Greenfoot.randomNumber(").append(to).append(")");
+            } else {
+                method.append("(Greenfoot.randomNumber(").append(to - from).append(") + ").append(from).append(")");
+            }
+        }
+        else if ("say:duration:elapsed:from:".equals(blockContents[0].getValue())) {
+            if (blockContents.length >= 3) {
+                method.append("{\nBubble bubble = new Bubble(\"")
+                      .append((String)blockContents[1].getValue())
+                      .append("\");\n");
+                method.append("getWorld().addObject(bubble, getX(), getY());");
+                method.append("getWorld().repaint();\n");
+                codeForBlock(new ScratchObjectArray(new ScratchObject[] {new ScratchPrimitive("wait:elapsed:from:"), blockContents[2]}), decl, method, loopVars);
+                method.append("getWorld().removeObject(bubble);\n}\n");
+            }
+        }
+        else if ("gotoX:y:".equals(blockContents[0].getValue())) {
+            method.append("setLocation((getWorld().getWidth() / 2) + ")
+                  .append(((BigDecimal)blockContents[1].getValue()).intValue())
+                  .append(" + X_OFFSETS[curCostume]")
+                  .append(", (getWorld().getHeight() / 2) - ")
+                  .append(((BigDecimal)blockContents[2].getValue()).intValue())
+                  .append(" + Y_OFFSETS[curCostume]")
+                  .append(");\n");
+        }
+        else if ("turnRight:".equals(blockContents[0].getValue())) {
+            String degrees = blockContents[1].getValue().toString();
+            method.append("turn(-").append(degrees).append(");\n");
+        }
+        else if ("nextCostume".equals(blockContents[0].getValue())) {
+            method.append("curCostume = (curCostume + 1) % COSTUMES.length;\n");
+            method.append("setImage(COSTUMES[curCostume]);\n");
+            method.append("getImage().scale(")
+                  .append(getBounds().x2.subtract(getBounds().x).intValue())
+                  .append(", ")
+                  .append(getBounds().y2.subtract(getBounds().y).intValue())
+                  .append(");\n");
+            method.append("getWorld().repaint();\n");
+        }
+        else if ("wait:elapsed:from:".equals(blockContents[0].getValue())) {
+            if (blockContents[1].getValue() instanceof BigDecimal) {
+                BigDecimal seconds = (BigDecimal) blockContents[1].getValue();
+                method.append("try {\n");
+                method.append("Thread.sleep(").append(seconds.scaleByPowerOfTen(3).intValue()).append(");\n");
+                method.append("} catch (InterruptedException e) { }");
+            }
+        }
+        else if (blockContents[0] instanceof ScratchObjectArray) {
+            for (ScratchObject blockContent : blockContents) {
+                codeForBlock(blockContent, decl, method, loopVars);
+            }
+        }
+        else {
+            StringBuilder tmp = new StringBuilder();
+            for (ScratchObject o : blockContents) {
+                tmp.append(o).append(",");
+            }
+            Debug.message("Unknown Scratch block/code: " + tmp.toString());
+        }
+    }
+
+    private int findCostume(String searchFor)
+    {
+        for (int i = 0; i < costumes.length;i++) {
+            if (searchFor.equals(costumes[i])) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private void codeForScripts(ScratchObjectArray scripts, StringBuilder acc, LoopVarIterator loopVars)
+    {
+        StringBuilder decl = new StringBuilder();
+        StringBuilder method = new StringBuilder();
+        StringBuilder firstTimeCode = new StringBuilder();
+        
+        // Each item in the array of blocks is a separate script chunk in
+        // the scripts window in Scratch:
+        for (ScratchObject scriptChunk : scripts.getValue()) {
+            ScratchObject[] info = (ScratchObject[])scriptChunk.getValue();
+            //First entry is always a ScratchPrimitive with a Point
+            //  (location in the Scratch script window; we can ignore)
+            //Second entry is the actual block array.
+            
+            ScratchObject[] blocks = (ScratchObject[])info[1].getValue();
+            
+            // Each item in this array is a separate block, 
+            // taken together they are a chunk.
+            
+            // We are only interested (for now, at least) in blocks that
+            // can run automatically, either from the outset or when clicked.
+    
+            ScratchObject[] firstBlockContents = (ScratchObject[])blocks[0].getValue();
+            
+            if ("MouseClickEventHatMorph".equals(firstBlockContents[0].getValue())) {
+                if ("Scratch-MouseClickEvent".equals(firstBlockContents[1].getValue())) {
+                    method.append("if (Greenfoot.mouseClicked(this)) {");
+                    //TODO actually this should set a boolean indicating we've started and should run in future
+                    for (ScratchObject block : Arrays.copyOfRange(blocks, 1, blocks.length)) {
+                        codeForBlock(block, decl, method, loopVars);
+                    }
+                    
+                    method.append("}");
+                }
+            }
+            else if ("EventHatMorph".equals(firstBlockContents[0].getValue())) {
+                if ("Scratch-StartClicked".equals(firstBlockContents[1].getValue())) {
+                    // Don't need any special code for when flag clicked, that's just the first time
+                    // that the act() method will be run anyway:
+                    
+                    ScratchObject[] subsequentBlocks = Arrays.copyOfRange(blocks, 1, blocks.length);
+                    
+                    if (subsequentBlocks.length == 1 && isLoop(subsequentBlocks[0])) {
+                        codeForBlock(subsequentBlocks[0], decl, method, loopVars);
+                    } else {
+                        
+                        int i;
+                        for (i = 0; i < subsequentBlocks.length;i++) {
+                            ScratchObject[] blockContents = (ScratchObject[]) subsequentBlocks[i].getValue();
+                            if (!isLoop(blockContents[0])) {
+                                codeForBlock(subsequentBlocks[i], decl, firstTimeCode, loopVars);
+                            } else {
+                                break;
+                            }
+                        }
+
+                        if (i < subsequentBlocks.length) {
+                            ScratchObject[] blockContents = (ScratchObject[]) subsequentBlocks[i].getValue();
+                            //Must be a loop:
+                            if ("doForever".equals(blockContents[0].getValue())) {
+                                //Just do it each time in the act method:
+                                codeForBlock(blockContents[1], decl, method, loopVars);
+                            } else if ("doRepeat".equals(blockContents[0].getValue())) {
+                                decl.append("private int loopCount = 0;\n");
+                                
+                                method.append("if (loopCount < ")
+                                      .append(blockContents[1].getValue())
+                                      .append(") {\n");
+                                method.append("loopCount += 1;\n");
+                                codeForBlock(blockContents[2], decl, method, loopVars);
+                                method.append("}\n");
+                            }
+                        }
+                    }
+                }
+            } else if ("KeyEventHatMorph".equals(firstBlockContents[0].getValue())) {
+                String scratchKeyName = (String) firstBlockContents[1].getValue();
+                String greenfootKeyName = null;
+                if (scratchKeyName.endsWith(" arrow")) {
+                    greenfootKeyName = scratchKeyName.substring(0, scratchKeyName.length() - " arrow".length());
+                }
+                
+                if (greenfootKeyName != null) {
+                    method.append("if (Greenfoot.isKeyDown(\"" + greenfootKeyName + "\")) {\n");
+                    
+                    ScratchObject[] subsequentBlocks = Arrays.copyOfRange(blocks, 1, blocks.length);
+                    for (ScratchObject block : subsequentBlocks) {
+                        codeForBlock(block, decl, method, loopVars);
+                    }
+                    method.append("}\n");
+                }
+            }
+            else {
+                // else ignore for now
+                Debug.message("Ignoring block headed: " + firstBlockContents[0].getValue());
+            }            
+        }
+        
+        acc.append(decl);
+        if (firstTimeCode.length() > 0) {
+            acc.append("private boolean firstTime = true;\n");
+        }
+        acc.append("public void act()\n{\n");
+        if (firstTimeCode.length() > 0) {
+            acc.append("if (firstTime) {\n");
+            acc.append("firstTime = false;\n");
+            acc.append(firstTimeCode);
+            acc.append("}\n");
+        }
+        acc.append(method);
+        acc.append("}\n");
+    }
+
+    private static boolean isLoop(ScratchObject scratchObject)
+    {
+        return "doForever".equals(scratchObject.getValue()) || "doRepeat".equals(scratchObject.getValue());
+    }
+
+    public ScratchPoint getScaleAmount()
+    {
+        return new ScratchPoint(new BigDecimal(1), new BigDecimal(1));
+    }
+    
+    private static class LoopVarIterator
+    {
+        int i = 0;
+        
+        public LoopVarIterator() {}
+        public LoopVarIterator(LoopVarIterator it) { i = it.i; }
+
+        public String next()
+        {
+            switch (i++)
+            {
+            case 0: return "i";
+            case 1: return "j";
+            case 2: return "k";
+            default: return "i" + (i - 2);
+            }
+        }
+
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/SoundMedia.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/SoundMedia.java
new file mode 100644
index 0000000000000000000000000000000000000000..5f3d8e53cab9c7167fce9d83a49e3be8d58a91cc
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/importer/scratch/SoundMedia.java
@@ -0,0 +1,209 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.importer.scratch;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Properties;
+
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+
+import bluej.utility.Debug;
+
+/**
+ * A sound clip, typically compressed as ADPCM.
+ * 
+ * 
+ * @author neil
+ *
+ */
+public class SoundMedia extends ScratchMedia
+{
+    //ADPCM step table, see Scratch/SmallTalk source code and
+    //http://wiki.multimedia.cx/index.php?title=IMA_ADPCM
+    private static final int[] STEP_TABLE = new int[] { 
+        7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 
+        19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 
+        50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 
+        130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+        337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+        876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 
+        2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+        5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 
+        15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 
+      };
+    //Index table, see Scratch/SmallTalk source code
+    private static final int[][] INDEX_TABLE = new int[][] {
+        null, null, //0 and 1
+        new int[] {-1, 2, -1, 2}, // 2
+        new int[] {-1, -1, 2, 4, -1, -1, 2, 4}, // 3
+        new int[] { // 4
+        -1, -1, -1, -1, 2, 4, 6, 8,
+        -1, -1, -1, -1, 2, 4, 6, 8},
+        new int[] { // 8
+        -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16,
+        -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16}
+    };
+    private File destFile;
+        
+    public SoundMedia(int version, List<ScratchObject> scratchObjects)
+    {
+        super(SOUND_MEDIA, version, scratchObjects);
+    }
+    
+    // Fields:
+    //   originalSound, volume, balance, compressedSampleRate, compressedBitsPerSample, compressedData
+    
+    @Override
+    public int fields()
+    {
+        return super.fields() + 6;
+    }
+
+    @Override
+    public File saveInto(File destDir, Properties props, String prefix) throws IOException
+    {
+        if (destFile != null) return destFile;
+        
+        String name = getMediaName();
+        
+        // The code for this method is cobbled together from the Scratch/SmallTalk code
+        // and this page: http://wiki.multimedia.cx/index.php?title=IMA_ADPCM
+        
+        float sampleRate = getSampleRate();
+        //bits per sample can be 2, 3, 4, 5
+        int bitsPerSample = getBitsPerSample();
+        byte[] compressed = getCompressedSamples();
+        
+        if (compressed == null)
+            return null; // TODO must be uncompressed?
+        
+        int uncompressedSamples = (compressed.length * 8) / bitsPerSample; // Length in samples
+        byte[] uncompressed = new byte[uncompressedSamples * 2]; // * 2 because we use 16-bits (2 bytes) per sample
+        
+        short prev = 0;
+        int stepIndex = 0;
+        int step = 0;
+        
+        int byteIndex = 0;
+        // Starts at 7, comes down to 0:
+        int bitIndex = 8 - bitsPerSample;
+        int destSample = 0;
+        
+        while (byteIndex < compressed.length) {
+            int unsignedCompressedVal;
+            if (bitIndex > 8 - bitsPerSample) {
+                // We need bits from across two bytes -- this byte and the byte before!               
+                unsignedCompressedVal = (compressed[byteIndex] >> bitIndex) & ((1 << (8 - bitIndex)) - 1);
+                unsignedCompressedVal |= (compressed[byteIndex-1] & ((1 << (bitsPerSample - (8 - bitIndex))) - 1)) << (8 - bitIndex);
+            } else {
+                unsignedCompressedVal = (compressed[byteIndex] >> bitIndex) & ((1 << bitsPerSample) - 1);
+            }
+            if (bitIndex - bitsPerSample < 0) {
+                byteIndex += 1;
+                bitIndex = 8 + bitIndex - bitsPerSample;
+            } else {
+                bitIndex -= bitsPerSample;
+            }                        
+            stepIndex = Math.max(0,Math.min(88,stepIndex + INDEX_TABLE[bitsPerSample][unsignedCompressedVal]));
+            // This code is copied from the Scratch algorithm
+            // (see Sound-Synthesis.ADPCMCodec.privateDecodeMono),
+            // hence all the bit-twiddling.
+            int diff = 0;
+            for (int bit = 1 << (bitsPerSample - 2); bit != 0; bit >>= 1) {
+                if ((unsignedCompressedVal & bit) != 0) {
+                    diff += step;
+                }
+                step >>= 1;
+            }
+            // The high bit appears to be a sign bit:
+            if ((unsignedCompressedVal & (1 << (bitsPerSample - 1))) != 0)
+                diff = -diff;
+            prev = (short)Math.max(-32768, Math.min(32767, (int)prev + diff));
+            uncompressed[destSample * 2] = (byte)(prev >> 8);
+            uncompressed[(destSample * 2) + 1] = (byte)(prev & 255);
+            destSample += 1;
+            
+            step = STEP_TABLE[stepIndex];
+            
+        }
+        
+        
+        File soundsDir = new File(destDir, "sounds");
+        soundsDir.mkdirs();
+        destFile = new File(soundsDir, prefix + name + ".wav");
+        
+        ByteArrayInputStream baiStream = new ByteArrayInputStream(uncompressed);
+        AudioFormat format = new AudioFormat(sampleRate, 16, 1, true, true);
+        AudioInputStream aiStream = new AudioInputStream(baiStream,format,uncompressed.length);
+        try {
+            
+            AudioSystem.write(aiStream,AudioFileFormat.Type.WAVE,destFile);
+            aiStream.close();
+            baiStream.close();
+        }
+        catch (IOException e) {
+            Debug.reportError("Problem writing converted sound to WAV file", e);
+        }
+        
+        return destFile;
+    }
+
+    private byte[] getCompressedSamples()
+    {
+        ScratchObject obj = scratchObjects.get(super.fields() + 5);
+        if (obj == null) {
+            return null;
+        } else {
+            return (byte[]) obj.getValue();
+        }
+    }
+
+    private int getBitsPerSample()
+    {
+        ScratchObject obj = scratchObjects.get(super.fields() + 4);
+        if (obj == null) {
+            return 0;
+        } else {
+            return ((BigDecimal)obj.getValue()).intValue();
+        }
+    }
+
+    private float getSampleRate()
+    {
+        ScratchObject obj = scratchObjects.get(super.fields() + 3);
+        if (obj == null) {
+            return 0;
+        } else {
+            return ((BigDecimal)obj.getValue()).floatValue();
+        }
+    }
+
+    
+    
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalArray.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..ccdd24136ed0c1aa2f36f955a9d4f169f333c763
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalArray.java
@@ -0,0 +1,93 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.JavaType;
+import bluej.utility.JavaUtils;
+
+/**
+ * A DebuggerObject to represent arrays. This base class is for object arrays;
+ * primitive array types are represented in seperate classes which derive from
+ * this one.<p>
+ * 
+ * Subclasses should override:
+ * <ul>
+ * <li> getValueString(int)
+ * <li> instanceFieldIsObject(int)
+ * </ul>
+ * 
+ * @author Davin McCall
+ */
+public class LocalArray extends LocalObject
+{
+    private int length;
+    
+    protected LocalArray(Object [] object)
+    {
+        super(object);
+        length = object.length;
+    }
+    
+    /**
+     * Subclasses use this constructor to specify the array length.
+     * 
+     * @param object  The array object
+     * @param length  The array length
+     */
+    protected LocalArray(Object object, int length)
+    {
+        super(object);
+        this.length = length;
+    }
+
+    @Override
+    public int getElementCount()
+    {
+        return length;
+    }
+    
+    @Override
+    public DebuggerObject getElementObject(int index)
+    {
+        Object val = ((Object []) object)[index];
+        return getLocalObject(val);
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return LocalField.valueStringForObject(getElementObject(index));
+    }
+
+    @Override
+    public JavaType getElementType()
+    {
+        return JavaUtils.genTypeFromClass(object.getClass().getComponentType());
+    }
+    
+    @Override
+    public boolean isArray()
+    {
+        return true;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalBooleanArray.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalBooleanArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..91a24af5d27a312f27c2469dd8cec3eb3a650ee2
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalBooleanArray.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+/**
+ * Represents an array of boolean as a DebuggerObject.
+ * 
+ * @author Davin McCall
+ */
+public class LocalBooleanArray extends LocalArray
+{
+    public LocalBooleanArray(boolean [] array)
+    {
+        super(array, array.length);
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return Boolean.toString(((boolean []) object)[index]);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalByteArray.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalByteArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..e057d1c8a680638432a47cf5e7bde449adee64f2
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalByteArray.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+/**
+ * Represent an array of byte as a DebuggerObject.
+ * 
+ * @author Davin McCall
+ */
+public class LocalByteArray extends LocalArray
+{
+    public LocalByteArray(byte [] array)
+    {
+        super(array, array.length);
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return Byte.toString(((byte []) object)[index]);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalCharArray.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalCharArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..14768a2dd0f02f1bd9cb6d43b8d22bce6b8e2308
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalCharArray.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+/**
+ * Represent an array of char as a DebuggerObject
+ * 
+ * @author Davin McCall
+ */
+public class LocalCharArray extends LocalArray
+{
+    public LocalCharArray(char [] array)
+    {
+        super(array, array.length);
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return Character.toString(((char []) object)[index]);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalClass.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3f2463987e5cedc05b148e46ab7eee619a63d6e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalClass.java
@@ -0,0 +1,248 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+import greenfoot.Actor;
+import greenfoot.World;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+
+/**
+ * Represent a local class as a DebuggerClass.
+ * 
+ * @author Davin McCall
+ */
+public class LocalClass extends DebuggerClass
+{
+    private Class<?> cl;
+    private static Field [] noFields = new Field[0];
+     
+    /**
+     * Constructor for LocalClass.
+     */
+    public LocalClass(Class<?> cl)
+    {
+        this.cl = cl;
+    }
+    
+    /*
+     * @see bluej.debugger.DebuggerClass#getName()
+     */
+    public String getName()
+    {
+        return cl.getName();
+    }
+    
+    @Override
+    public List<DebuggerField> getStaticFields()
+    {
+        Field [] fields = getFields();
+        Set<String> usedNames = new HashSet<String>();
+        List<DebuggerField> rlist = new ArrayList<DebuggerField>(fields.length);
+        
+        for (Field field : fields) {
+            boolean visible = usedNames.add(field.getName());
+            rlist.add(new LocalField(null, field, !visible));
+        }
+        
+        return rlist;
+    }
+    
+    /*
+     * @see bluej.debugger.DebuggerClass#getStaticFieldCount()
+     */
+    public int getStaticFieldCount()
+    {        
+        return getFields().length;
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerClass#getStaticFieldName(int)
+     */
+    public String getStaticFieldName(int slot)
+    {
+        Field field = getFields()[slot];
+        return field.getName();
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerClass#getStaticFieldObject(int)
+     */
+    public DebuggerObject getStaticFieldObject(int slot)
+    {
+        Field field = getFields()[slot];
+        try {
+            return LocalObject.getLocalObject(field.get(null));
+        }
+        catch (IllegalAccessException iae) {}
+        return null;
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerClass#getStaticFields(boolean)
+     */
+    public List<String> getStaticFields(boolean includeModifiers, Map<String, List<String>> restrictedClasses)
+    {
+        List<String> r = new ArrayList<String>();
+        
+        Field [] fields = getFields();
+        for (int i = 0; i < fields.length; i++) {
+            // skip non-instance fields
+            int mods = fields[i].getModifiers();
+            
+            String desc = "";
+            if (includeModifiers) {
+                desc = Modifier.toString(mods) + " ";
+            }
+            
+            desc += fields[i].getName() + " = ";
+            try {
+                if (fields[i].getType().isPrimitive()) {
+                    desc += fields[i].get(null);
+                }
+                else {
+                    Object fieldval = fields[i].get(null);
+                    if (fieldval instanceof String) {
+                        desc += '\"' + fieldval.toString() + '\"';
+                    }
+                    else if (fieldval == null) {
+                        desc += "null";
+                    }
+                    else {
+                        desc += DebuggerObject.OBJECT_REFERENCE;
+                    }
+                }
+            }
+            catch (IllegalAccessException iae) {
+                desc += "?";
+            }
+            
+            r.add(desc);
+        }
+        
+        return r;
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerClass#staticFieldIsPublic(int)
+     */
+    public boolean staticFieldIsPublic(int slot)
+    {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerClass#staticFieldIsObject(int)
+     */
+    public boolean staticFieldIsObject(int slot)
+    {
+        Field field = getFields()[slot];
+        return ! field.getType().isPrimitive()
+            && fieldNotNull(field);
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerClass#isInterface()
+     */
+    public boolean isInterface()
+    {
+        return cl.isInterface();
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerClass#isEnum()
+     */
+    public boolean isEnum()
+    {
+        // TODO support for enums
+        return false;
+    }
+
+    /**
+     * Convenience method to get static fields, public
+     * and private. Except the ones that should be filtered out.
+     */
+    private Field [] getFields()
+    {
+        ArrayList<Field> allFields = new ArrayList<Field>();
+        Class<?> c = cl;
+        
+        while (c != null) {
+            Field [] declFields = c.getDeclaredFields();
+            ArrayList<Field> sfields = new ArrayList<Field>();
+            for (int i = 0; i < declFields.length; i++) {
+                Field field = declFields[i];
+                if ((field.getModifiers() & Modifier.STATIC) != 0 && keepField(c, field)) {
+                    sfields.add(field);
+                }
+            }
+            
+            declFields = sfields.toArray(noFields);
+            AccessibleObject.setAccessible(declFields, true);
+            allFields.addAll(Arrays.asList(declFields));
+            c = c.getSuperclass();
+
+        }
+
+        return allFields.toArray(noFields);
+    }
+    
+    /**
+     * Check whether a field in this class contains a null reference.
+     */
+    public boolean fieldNotNull(Field field)
+    {
+        try {
+            Object v = field.get(null);
+            return v != null;
+        }
+        catch (IllegalAccessException iae) { return false; }
+    }
+
+    /**
+     * Whether a given field should be used.
+     * @return True if the field should be used, false if it should be ignored
+     */
+    private boolean keepField(Class<?> cls, Field field) 
+    {
+        if(cls.equals(World.class)) {
+            return false;
+        }
+        else if(cls.equals(Actor.class)) {
+            return false;
+        }
+        return true;            
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalDebugger.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalDebugger.java
new file mode 100644
index 0000000000000000000000000000000000000000..1158642158c568101f36ff193b11b6d80dd93b6a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalDebugger.java
@@ -0,0 +1,357 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+import greenfoot.core.Simulation;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import bluej.classmgr.BPClassLoader;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerListener;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.DebuggerResult;
+import bluej.debugger.DebuggerTestResult;
+import bluej.debugger.DebuggerThreadTreeModel;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugger.SourceLocation;
+import bluej.runtime.ExecServer;
+import bluej.utility.Debug;
+
+/**
+ * A "local" debugger. This implements various parts of the Debugger interface, to allow
+ * executing user code in the local VM. Some of the interface is not implemented however.
+ * 
+ * @author Davin McCall
+ */
+public class LocalDebugger extends Debugger
+{
+    @Override
+    public void setUserLibraries(URL[] libraries)
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
+    public int addDebuggerListener(DebuggerListener l)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean addObject(String scopeId, String newInstanceName,
+            DebuggerObject dob)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void close(boolean restart)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void disposeWindows()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DebuggerClass getClass(String className, boolean initialize)
+            throws ClassNotFoundException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DebuggerObject getMirror(String value)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, DebuggerObject> getObjects()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getStatus()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DebuggerThreadTreeModel getThreadTreeModel()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String guessNewName(String className)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String guessNewName(DebuggerObject obj)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void hideSystemThreads(boolean hide)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * A class to support running user code on the simulation thread.
+     * 
+     * @author Davin McCall
+     */
+    private static class QueuedInstantiation implements Runnable
+    {
+        private Class<?> c;
+        private DebuggerResult result;
+        
+        public QueuedInstantiation(Class <?> c)
+        {
+            this.c = c;
+        }
+        
+        public synchronized void run()
+        {
+            try {
+                final Constructor<?> cons = c.getDeclaredConstructor(new Class[0]);
+                cons.setAccessible(true);
+                Object o = Simulation.newInstance(cons);
+                result = new DebuggerResult(LocalObject.getLocalObject(o));
+            }
+            catch (InstantiationException ite) {
+                Debug.reportError("LocalDebugger instantiateClass error", ite);
+                result = new DebuggerResult(new ExceptionDescription("Internal error"));
+            }
+            catch (IllegalAccessException iae) {
+                Debug.reportError("LocalDebugger instantiateClass error", iae);
+                result = new DebuggerResult(new ExceptionDescription("Internal error"));
+            }
+            catch (NoSuchMethodException nsme) {
+                Debug.reportError("LocalDebugger instantiateClass error", nsme);
+                result = new DebuggerResult(new ExceptionDescription("Internal error"));
+            }
+            catch(InvocationTargetException ite) {
+                ite.getCause().printStackTrace(System.err);
+                ExceptionDescription exception = getExceptionDescription(ite.getCause());
+                result = new DebuggerResult(exception);
+            }
+            notify();
+        }
+        
+        public synchronized DebuggerResult getResult()
+        {
+            while (result == null) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                    // should be safe to ignore
+                }
+            }
+            return result;
+        }
+    }
+    
+    @Override
+    public DebuggerResult instantiateClass(String className)
+    {
+        ClassLoader currentLoader = ExecServer.getCurrentClassLoader();
+        
+        try {
+            Class<?> cl = currentLoader.loadClass(className);
+            QueuedInstantiation q = new QueuedInstantiation(cl);
+            Simulation.getInstance().runLater(q);
+            return q.getResult();
+        }
+        catch (ClassNotFoundException cnfe) {
+            Debug.reportError("Invoking constructor", cnfe);
+        }
+        catch (LinkageError le) {
+            Debug.reportError("Invoking constructor", le);
+        }
+        return new DebuggerResult(new ExceptionDescription("Internal error"));
+    }
+
+    @Override
+    public DebuggerResult instantiateClass(String className,
+            String[] paramTypes, DebuggerObject[] args)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void launch()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void newClassLoader(BPClassLoader bpClassLoader)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeBreakpointsForClass(String className)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeDebuggerListener(DebuggerListener l)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeObject(String scopeId, String instanceName)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * A class to support running user code on the simulation thread.
+     * 
+     * @author Davin McCall
+     */
+    private static class QueuedExecution implements Runnable
+    {
+        private Class<?> c;
+        private DebuggerResult result;
+        
+        public QueuedExecution(Class <?> c)
+        {
+            this.c = c;
+        }
+        
+        public synchronized void run()
+        {
+            try {
+                Method m = c.getMethod("run", new Class[0]);
+                Object result = m.invoke(null, new Object[0]);
+                this.result = new DebuggerResult(LocalObject.getLocalObject(result));
+            }
+            catch (IllegalAccessException iae) {
+                Debug.reportError("LocalDebugger runClassMain error", iae);
+                result = new DebuggerResult(new ExceptionDescription("Internal error"));
+            }
+            catch (NoSuchMethodException nsme) {
+                Debug.reportError("LocalDebugger runClassMain error", nsme);
+                result = new DebuggerResult(new ExceptionDescription("Internal error"));
+            }
+            catch(InvocationTargetException ite) {
+                ite.getCause().printStackTrace(System.err);
+                ExceptionDescription exception = getExceptionDescription(ite.getCause());
+                result = new DebuggerResult(exception);
+            }
+            notify();
+        }
+        
+        public synchronized DebuggerResult getResult()
+        {
+            while (result == null) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                    // should be safe to ignore
+                }
+            }
+            return result;
+        }
+    }
+    
+    @Override
+    public DebuggerResult runClassMain(String className)
+            throws ClassNotFoundException
+    {
+        ClassLoader currentLoader = ExecServer.getCurrentClassLoader();
+        Class<?> c = currentLoader.loadClass(className);
+        QueuedExecution qe = new QueuedExecution(c);
+        Simulation.getInstance().runLater(qe);
+        return qe.getResult();
+    }
+
+    @Override
+    public DebuggerTestResult runTestMethod(String className, String methodName)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String, DebuggerObject> runTestSetUp(String className)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toggleBreakpoint(String className, int line, boolean set,
+            Map<String, String> properties)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toggleBreakpoint(String className, String method,
+            boolean set, Map<String, String> properties)
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
+    public String toggleBreakpoint(DebuggerClass debuggerClass, String method,
+            boolean set, Map<String, String> properties)
+    {
+        throw new UnsupportedOperationException();
+    }
+    
+    /**
+     * Convert a Throwable into an ExceptionDescription.
+     */
+    private static ExceptionDescription getExceptionDescription(Throwable t)
+    {
+        List<SourceLocation> stack = new ArrayList<SourceLocation>();
+        StackTraceElement [] stackTrace = t.getStackTrace();
+        for (StackTraceElement element : stackTrace) {
+            stack.add(new SourceLocation(element.getClassName(), element.getFileName(),
+                    element.getMethodName(), element.getLineNumber()));
+        }
+        new ExceptionDescription(t.getClass().getName(), t.getLocalizedMessage(), stack);
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalDoubleArray.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalDoubleArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..365f7d6114b6f82b4e9504686b6f1a803ffbd26d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalDoubleArray.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+/**
+ * Represent an array of double as a DebuggerObject.
+ * 
+ * @author Davin McCall
+ */
+public class LocalDoubleArray extends LocalArray
+{
+    public LocalDoubleArray(double [] array)
+    {
+        super(array, array.length);
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return Double.toString(((double []) object)[index]);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalField.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalField.java
new file mode 100644
index 0000000000000000000000000000000000000000..03b29f9cbbd7bbc1f8351822a3cba6f32e02fe29
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalField.java
@@ -0,0 +1,153 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+import java.lang.reflect.Field;
+
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.JavaType;
+import bluej.utility.JavaReflective;
+import bluej.utility.JavaUtils;
+
+/**
+ * Implementation of DebuggerField for local objects.
+ * 
+ * @author Davin McCall
+ */
+public class LocalField extends DebuggerField
+{
+    private boolean hidden;
+    private Field field;
+    private LocalObject parentObject;
+    
+    public LocalField(LocalObject parentObject, Field field, boolean hidden)
+    {
+        this.parentObject = parentObject;
+        this.field = field;
+        this.hidden = hidden;
+    }
+    
+    @Override
+    public DebuggerClass getDeclaringClass()
+    {
+        return new LocalClass(field.getDeclaringClass());
+    }
+    
+    @Override
+    public int getModifiers()
+    {
+        return field.getModifiers();
+    }
+    
+    @Override
+    public String getName()
+    {
+        return field.getName();
+    }
+    
+    @Override
+    public JavaType getType()
+    {
+        try {
+            JavaType fieldType = JavaUtils.getJavaUtils().getFieldType(field);
+            if (parentObject != null) {
+                GenTypeClass parentType = parentObject.getGenType();
+                parentType = parentType.mapToSuper(field.getDeclaringClass().getName());
+                fieldType = fieldType.mapTparsToTypes(parentType.getMap()).getUpperBound();
+            }
+            return fieldType;
+        }
+        catch (ClassNotFoundException cnfe) {
+            return new GenTypeClass(new JavaReflective(field.getType()));
+        }
+    }
+    
+    @Override
+    public DebuggerObject getValueObject(JavaType expectedType)
+    {
+        try {
+            boolean accessible = field.isAccessible();
+            field.setAccessible(true);
+            Object resultObj = parentObject == null ? field.get(null) : field.get(parentObject.object);
+            field.setAccessible(accessible);
+            
+            // Get type parameters
+            GenTypeClass fieldClass = getType().asClass();
+            if (resultObj != null && fieldClass != null) {
+                GenTypeClass objClass = fieldClass.mapToDerived(new JavaReflective(resultObj.getClass()));
+                return LocalObject.getLocalObject(resultObj, objClass.getMap());
+            }
+            else {
+                // Though it's invalid to call getValueObject when the field type isn't a reference
+                // type, we may have a primitive array type, for which asClass() can return null.
+                return LocalObject.getLocalObject(resultObj);
+            }
+        }
+        catch (IllegalAccessException iae) {
+            return null;
+        }
+    }
+    
+    @Override
+    public String getValueString()
+    {
+        try {
+            boolean accessible = field.isAccessible();
+            field.setAccessible(true);
+            Object pObj = (parentObject == null) ? null : parentObject.object;
+            Object resultObj = field.get(pObj);
+            field.setAccessible(accessible);
+            if (field.getType().isPrimitive()) {
+                return resultObj.toString();
+            }
+            else {
+                return valueStringForObject(resultObj);
+            }
+        }
+        catch (IllegalAccessException iae) {
+            return null;
+        }
+    }
+    
+    /**
+     * Get the value string representation for some object reference.
+     */
+    public static String valueStringForObject(Object o)
+    {
+        if (o instanceof String) {
+            return "\"" + JavaUtils.escapeString(o.toString()) + "\"";
+        }
+        if (o == null) {
+            return "null";
+        }
+        return DebuggerObject.OBJECT_REFERENCE;
+    }
+    
+    @Override
+    public boolean isHidden()
+    {
+        return hidden;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalFloatArray.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalFloatArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc1f94a1d80172e1f77d1d0a1d7f1222b7299bba
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalFloatArray.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+/**
+ * Represent an array of float as a DebuggerObject
+ * 
+ * @author Davin McCall
+ */
+public class LocalFloatArray extends LocalArray
+{
+    public LocalFloatArray(float [] array)
+    {
+        super(array, array.length);
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return Float.toString(((float []) object)[index]);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalIntArray.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalIntArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ad0ea6ffddf05f9223b034e83b834eb85fd1563
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalIntArray.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+/**
+ * Represent an array of int as a DebuggerObject.
+ * 
+ * @author Davin McCall
+ */
+public class LocalIntArray extends LocalArray
+{
+    public LocalIntArray(int [] array)
+    {
+        super(array, array.length);
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return Integer.toString(((int []) object)[index]);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalLongArray.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalLongArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f022e891a33440e5ab432fe7de372c9aa137f96
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalLongArray.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+/**
+ * Represent an array of long as a DebuggerObject.
+ * 
+ * @author Davin McCall
+ */
+public class LocalLongArray extends LocalArray
+{
+    public LocalLongArray(long [] array)
+    {
+        super(array, array.length);
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return Long.toString(((long [])object)[index]);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalObject.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..fdd43274e9209ce8bd2e8ae8f0f8d5db4fd9058b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalObject.java
@@ -0,0 +1,327 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2013  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+import greenfoot.util.DebugUtil;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.GenTypeClass;
+import bluej.debugger.gentype.GenTypeParameter;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugger.gentype.Reflective;
+import bluej.utility.JavaReflective;
+
+import com.sun.jdi.ObjectReference;
+
+/**
+ * A class to represent a local object as a DebuggerObject
+ *  
+ * @author Davin McCall
+ */
+public class LocalObject extends DebuggerObject
+{
+    // static fields
+    private static Field [] noFields = new Field[0];
+    
+    // instance fields
+    protected Object object;
+    private Map<String,GenTypeParameter> genericParams = null; // Map of parameter names to types 
+    
+    public static LocalObject getLocalObject(Object o)
+    {
+        if (o != null && o.getClass().isArray()) {
+            if (o instanceof boolean[]) {
+                return new LocalBooleanArray((boolean []) o);
+            }
+            else if (o instanceof byte[]) {
+                return new LocalByteArray((byte []) o);
+            }
+            else if (o instanceof char[]) {
+                return new LocalCharArray((char []) o);
+            }
+            else if (o instanceof int[]) {
+                return new LocalIntArray((int []) o);
+            }
+            else if (o instanceof long[]) {
+                return new LocalLongArray((long []) o);
+            }
+            else if (o instanceof short[]) {
+                return new LocalShortArray((short []) o);
+            }
+            else if (o instanceof float[]) {
+                return new LocalFloatArray((float []) o);
+            }
+            else if (o instanceof double[]) {
+                return new LocalDoubleArray((double []) o);
+            }
+            
+            return new LocalArray((Object []) o);
+        }
+        else {
+            return new LocalObject(o);
+        }
+    }
+    
+    public static LocalObject getLocalObject(Object o, Map<String,GenTypeParameter> genericParams)
+    {
+        if (o != null && o.getClass().isArray()) {
+            if (o instanceof boolean[]) {
+                return new LocalBooleanArray((boolean []) o);
+            }
+            else if (o instanceof byte[]) {
+                return new LocalByteArray((byte []) o);
+            }
+            else if (o instanceof char[]) {
+                return new LocalCharArray((char []) o);
+            }
+            else if (o instanceof int[]) {
+                return new LocalIntArray((int []) o);
+            }
+            else if (o instanceof long[]) {
+                return new LocalLongArray((long []) o);
+            }
+            else if (o instanceof short[]) {
+                return new LocalShortArray((short []) o);
+            }
+            else if (o instanceof float[]) {
+                return new LocalFloatArray((float []) o);
+            }
+            else if (o instanceof double[]) {
+                return new LocalDoubleArray((double []) o);
+            }
+            
+            // TODO generic arrays
+            return new LocalArray((Object []) o);
+        }
+        else {
+            return new LocalObject(o, genericParams);
+        }
+    }
+    
+    /**
+     * Construct a LocalObject to represent a local object as a DebuggerObject.
+     * @param o  The local object to represent
+     */
+    protected LocalObject(Object o)
+    {
+        object = o;
+    }
+    
+    /**
+     * Construct a LocalObject of generic type
+     * @param o   The local object to represent
+     * @param genericParams  The mapping of type parameter names to types
+     *                       (String to GenType).
+     */
+    protected LocalObject(Object o, Map<String,GenTypeParameter> genericParams)
+    {
+        object = o;
+        this.genericParams = genericParams;
+    }
+    
+    // hash and equality defined in terms of the underlying object
+    
+    @Override
+    public int hashCode()
+    {
+        return object.hashCode();
+    }
+    
+    @Override
+    public boolean equals(Object other)
+    {
+        if (other instanceof LocalObject) {
+            Object otherObj = ((LocalObject) other).object;
+            return object.equals(otherObj);
+        }
+        return false;
+    }
+    
+    
+    /*
+     * @see bluej.debugger.DebuggerObject#getClassName()
+     */
+    @Override
+    public String getClassName()
+    {
+        if (object != null) {
+            return object.getClass().getName();
+        }
+        else {
+            return "";
+        }
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerObject#getClassRef()
+     */
+    @Override
+    public DebuggerClass getClassRef()
+    {
+        return new LocalClass(object.getClass());
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerObject#getGenType()
+     */
+    @Override
+    public GenTypeClass getGenType()
+    {
+        Reflective r = new JavaReflective(object.getClass());
+        if(genericParams != null)
+            return new GenTypeClass(r, genericParams);
+        else
+            return new GenTypeClass(r);
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerObject#isArray()
+     */
+    @Override
+    public boolean isArray()
+    {
+        return object.getClass().isArray();
+    }
+
+    /*
+     * @see bluej.debugger.DebuggerObject#isNullObject()
+     */
+    @Override
+    public boolean isNullObject()
+    {
+        return object == null;
+    }
+    
+    @Override
+    public int getElementCount()
+    {
+        return -1;
+    }
+    
+    @Override
+    public DebuggerObject getElementObject(int index)
+    {
+        return null;
+    }
+    
+    @Override
+    public JavaType getElementType()
+    {
+        return null;
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return null;
+    }
+    
+    @Override
+    public List<DebuggerField> getFields()
+    {
+        Field [] fields = getAllFields();
+        Set<String> usedNames = new HashSet<String>();
+        List<DebuggerField> rlist = new ArrayList<DebuggerField>(fields.length);
+        
+        for (Field field : fields) {
+            boolean visible = usedNames.add(field.getName());
+            rlist.add(new LocalField(this, field, !visible));
+        }
+        
+        return rlist;
+    }
+
+    /**
+     * Convenience method to get all fields, instance and static, public
+     * and private. Fields are returned in order - first those declared in this
+     * class, then the superclass, and so on.
+     */
+    private Field [] getAllFields()
+    {
+        if (object == null) {
+            return noFields;
+        }
+        
+        ArrayList<Field> allFields = new ArrayList<Field>();
+        Class<?> c = object.getClass();
+        
+        while (c != null) {
+            Field [] declFields = c.getDeclaredFields();
+            AccessibleObject.setAccessible(declFields, true);
+            
+            for (int j = 0; j < declFields.length; j++) {
+                Field field = declFields[j];
+                // Filter out some fields that we want to hide.
+                if(keepField(c, field)) {
+                    allFields.add(field);
+                }
+            }
+            
+            c = c.getSuperclass();
+        }
+
+        return allFields.toArray(noFields);
+    }
+    
+    /* (non-Javadoc)
+     * @see bluej.debugger.DebuggerObject#getObjectReference()
+     */
+    @Override
+    public ObjectReference getObjectReference()
+    {
+        // No, this implementation is not Jdi related!
+        return null;
+    }
+
+    /**
+     * Whether a given field should be used.
+     * @return True if the field should be used, false if it should be ignored
+     */
+    private boolean keepField(Class<?> cls, Field field) 
+    {
+        List<String> fieldWhitelist = DebugUtil.restrictedClasses().get(cls);
+        
+        if (fieldWhitelist != null) {
+            return fieldWhitelist.contains(field.getName());
+        } else {
+            return true;
+        }            
+    }
+
+    /**
+     * Returns the object that this LocalObject represents.
+     */
+    public Object getObject()
+    {
+        return object;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalShortArray.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalShortArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f4c983dbe7a2e170c6d24e42690bc302ef72a0e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/localdebugger/LocalShortArray.java
@@ -0,0 +1,41 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.localdebugger;
+
+/**
+ * Represent an array of short as a DebuggerObject.
+ * 
+ * @author Davin McCall
+ */
+public class LocalShortArray extends LocalArray
+{
+    public LocalShortArray(short [] array)
+    {
+        super(array, array.length);
+    }
+    
+    @Override
+    public String getElementValueString(int index)
+    {
+        return Integer.toString(((short []) object)[index]);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ActorDelegate.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ActorDelegate.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9d610454079cd4edcd3fd8f9b88ed25e6df1b7d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ActorDelegate.java
@@ -0,0 +1,38 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms;
+
+import greenfoot.GreenfootImage;
+
+/**
+ * Interface to classes that contain specialized behaviour for the Actors
+ * depending on where and how the greenfoot project is running.
+ * 
+ * @author Poul Henriksen
+ */
+public interface ActorDelegate
+{
+    /**
+     * Get the default image for objects of this class. May return null.
+     */
+    public GreenfootImage getImage(String name);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/GreenfootUtilDelegate.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/GreenfootUtilDelegate.java
new file mode 100644
index 0000000000000000000000000000000000000000..daaecdfe73878ee40a16308510cf164577bb3f07
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/GreenfootUtilDelegate.java
@@ -0,0 +1,110 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms;
+
+import greenfoot.GreenfootImage;
+import greenfoot.UserInfo;
+
+import java.awt.Component;
+import java.net.URL;
+import java.util.List;
+
+/**
+ * Interface to classes that contain specialized behaviour for the GreenfootUtil
+ * class depending on where and how the greenfoot project is running.
+ * 
+ * @author Poul Henriksen
+ */
+public interface GreenfootUtilDelegate
+{
+    /**
+     * Get some resource from the project, specified by a relative path.
+     */
+    public URL getResource(String path);
+    
+    /**
+     * Gets a list of sound files (as plain names, e.g. "foo.wav") that
+     * accompany this scenario.  For the IDE version, this scans the filesystem,
+     * and for the standalone version it looks at a list that's included
+     * in the exported JAR.
+     * <p>
+     * The return value will not be null, but it may have no contents if there
+     * was an error (e.g. problem reading the directory/JAR, or no list of sounds in the JAR)
+     * and you should not rely on it being accurate (e.g. if files were just added/removed in the sounds directory,
+     * or the JAR has been modified since export). 
+     */
+    public Iterable<String> getSoundFiles();
+
+    /**
+     * Get the project-relative path of the Greenfoot logo.
+     */
+    public String getGreenfootLogoPath();
+
+    /**
+     * Display a message to the user; how the message is displayed is dependent
+     * upon the platform context. In the Greenfoot IDE, the message will be displayed
+     * in a dialog; otherwise it will be written to the terminal/console/log.
+     * 
+     * @param parent  The parent component (if a dialog is used to display the message)
+     * @param messageText   The message text itself.
+     */
+    public void displayMessage(Component parent, String messageText);
+
+    /**
+     * Find out whether storage is supported in the current setting
+     */
+    public boolean isStorageSupported();
+
+    /**
+     * null if an error or not supported, blank values if no previous storage
+     */
+    public UserInfo getCurrentUserInfo();
+
+    /**
+     * returns whether it was successful
+     */
+    public boolean storeCurrentUserInfo(UserInfo data);
+
+    /**
+     * null if problem, empty list if simply no data
+     * 
+     * Returns highest data when sorted by integer index 0
+     */
+    public List<UserInfo> getTopUserInfo(int limit);
+
+    /**
+     * returns null if storage not supported or if there was an error.
+     */
+    public GreenfootImage getUserImage(String userName);
+
+    /**
+     * returns null if storage is not supported (or there was an error)
+     */
+    public String getUserName();
+
+    /**
+     * null if problem, empty list if simply no data.
+     * 
+     * Returns data near the current player when sorted by integer index 0
+     */
+    public List<UserInfo> getNearbyUserInfo(int maxAmount);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/SimulationDelegate.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/SimulationDelegate.java
new file mode 100644
index 0000000000000000000000000000000000000000..fea5d49279b0b9c1992ffac14e2bfda0a90733d2
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/SimulationDelegate.java
@@ -0,0 +1,38 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms;
+
+/**
+ * Interface for handling the simulation differently for the IDE and standalone 
+ * versions of Greenfoot.
+ * 
+ * @author Poul Henriksen
+ */
+public interface SimulationDelegate
+{
+    /** 
+     * This method will be called at speed changes.
+     * 
+     * @param speed The new speed.
+     */
+    public void setSpeed(int speed);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/WorldHandlerDelegate.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/WorldHandlerDelegate.java
new file mode 100644
index 0000000000000000000000000000000000000000..51d59b98a78c007d893572aa8507ca19f72f3632
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/WorldHandlerDelegate.java
@@ -0,0 +1,78 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms;
+
+import greenfoot.Actor;
+import greenfoot.World;
+import greenfoot.core.WorldHandler;
+import greenfoot.gui.input.InputManager;
+
+import java.awt.event.MouseEvent;
+
+
+/**
+ * Interface to classes that contain specialized behaviour for the WorldHandler
+ * depending on where and how the Greenfoot project is running.
+ * 
+ * @author Poul Henriksen
+ */
+public interface WorldHandlerDelegate
+{
+    /**
+     * Show the popup menu if the MouseEvent is a popup trigger.
+     */
+    boolean maybeShowPopup(MouseEvent e);
+
+    void mouseClicked(MouseEvent e);
+
+    void mouseMoved(MouseEvent e);
+    
+    /**
+     * A new world has been set as the active world.
+     * @param oldWorld   The previously active world
+     * @param newWorld   The new active world
+     */
+    void setWorld(World oldWorld, World newWorld);
+
+    void setWorldHandler(WorldHandler handler);
+    
+    void addActor(Actor actor, int x, int y); 
+    
+    /**
+     * Instantiate a new world and do any initialisation needed to activate that world.
+     */
+    void instantiateNewWorld();
+
+    InputManager getInputManager();
+
+    void discardWorld(World world);
+    
+    /**
+     * An actor was dragged to a new location. Called with the world locked.
+     */
+    public void actorDragged(Actor actor, int xCell, int yCell);
+    
+    /**
+     * An actor was added into the world (by any means, possibly programmatically). Called with the world locked.
+     */
+    public void objectAddedToWorld(Actor actor);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/ActorDelegateIDE.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/ActorDelegateIDE.java
new file mode 100644
index 0000000000000000000000000000000000000000..c9735ff14e600b438f690202b709dd0bc9fd419e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/ActorDelegateIDE.java
@@ -0,0 +1,56 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms.ide;
+
+import greenfoot.ActorVisitor;
+import greenfoot.GreenfootImage;
+import greenfoot.core.GProject;
+import greenfoot.platforms.ActorDelegate;
+
+/**
+ * Delegate for the Actor when it is running in the Greenfoot IDE.
+ * 
+ * @author Poul Henriksen <polle@polle.org>
+ *
+ */
+public class ActorDelegateIDE implements ActorDelegate
+{
+    private GProject project;
+    
+    private ActorDelegateIDE(GProject project)
+    {
+    	this.project = project;
+    }
+    
+    /**
+     * Register this class as the delegate for Actor.
+     */
+    public static void setupAsActorDelegate(GProject project)
+    {
+        ActorVisitor.setDelegate(new ActorDelegateIDE(project));
+    }
+    
+    public GreenfootImage getImage(String name)
+    {
+        return project.getProjectProperties().getImage(name);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/GreenfootUtilDelegateIDE.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/GreenfootUtilDelegateIDE.java
new file mode 100644
index 0000000000000000000000000000000000000000..6418327b589cba85b0bb2473c8ed8d375f628536
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/GreenfootUtilDelegateIDE.java
@@ -0,0 +1,484 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms.ide;
+
+import greenfoot.GreenfootImage;
+import greenfoot.UserInfo;
+import greenfoot.UserInfoVisitor;
+import greenfoot.platforms.GreenfootUtilDelegate;
+
+import java.awt.Component;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import au.com.bytecode.opencsv.CSVReader;
+import au.com.bytecode.opencsv.CSVWriter;
+import bluej.Config;
+import bluej.runtime.ExecServer;
+import bluej.utility.BlueJFileReader;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+/**
+ * GreenfootUtilDelegate implementation for the Greenfoot IDE.
+ */
+public class GreenfootUtilDelegateIDE implements GreenfootUtilDelegate
+{
+    private static GreenfootUtilDelegateIDE instance;
+    
+    static {
+        instance = new GreenfootUtilDelegateIDE();
+    }
+    
+    /**
+     * Get the GreenfootUtilDelegateIDE instance.
+     */
+    public static GreenfootUtilDelegateIDE getInstance()
+    {
+        return instance;
+    }
+    
+    private GreenfootUtilDelegateIDE()
+    {
+        // Nothing to do.
+    }
+    
+    /**
+     * Creates the skeleton for a new class
+     */
+    public void createSkeleton(String className, String superClassName, File file,
+            String templateFileName, String projCharsetName)
+        throws IOException
+    {
+        Charset projCharset;
+        try
+        {
+            projCharset = Charset.forName(projCharsetName);
+        }
+        catch (UnsupportedCharsetException uce) {
+            projCharset = Charset.forName("UTF-8");
+        }
+        catch (IllegalCharsetNameException icne) {
+            projCharset = Charset.forName("UTF-8");
+        }
+        
+        Dictionary<String, String> translations = new Hashtable<String, String>();
+        translations.put("CLASSNAME", className);
+        if(superClassName != null) {
+            translations.put("EXTENDSANDSUPERCLASSNAME", "extends " + superClassName);
+        } else {
+            translations.put("EXTENDSANDSUPERCLASSNAME", "");
+        }
+        String baseName = "greenfoot/templates/" +  templateFileName;
+        File template = Config.getLanguageFile(baseName);
+        
+        if(!template.canRead()) {
+            template = Config.getDefaultLanguageFile(baseName);
+        }
+        BlueJFileReader.translateFile(template, file, translations, Charset.forName("UTF-8"), projCharset);
+    }
+    
+    @Override
+    public URL getResource(String path) 
+    {
+        return ExecServer.getCurrentClassLoader().getResource(path);
+    }
+    
+    @Override
+    public Iterable<String> getSoundFiles()
+    {
+        ArrayList<String> files = new ArrayList<String>();
+        try
+        {
+            URL url = getResource("sounds");
+            if (url != null && "file".equals(url.getProtocol()))
+            {
+                for (String file : new File(url.toURI()).list())
+                {
+                    files.add(file);
+                }
+            }
+        }
+        catch (URISyntaxException e)
+        {
+            Debug.reportError("Bad URI in getResources", e);
+        }
+        // May be a blank list if something went wrong:
+        return files;
+    }
+    
+    /**
+     * Returns the path to a small version of the greenfoot logo.
+     */
+    @Override
+    public  String getGreenfootLogoPath()
+    {        
+        File libDir = Config.getGreenfootLibDir();
+        return libDir.getAbsolutePath() + "/imagelib/other/greenfoot.png";        
+    }
+    
+    @Override
+    public void displayMessage(Component parent, String messageText)
+    {
+        DialogManager.showText(parent, messageText);
+    }
+
+    @Override
+    public boolean isStorageSupported()
+    {
+        return getUserName() != null && !getUserName().isEmpty();
+    }
+    
+    public String getUserName()
+    {
+        return Config.getPropString("greenfoot.player.name", "Player1");
+    }
+
+    @Override
+    public UserInfo getCurrentUserInfo()
+    {
+        if (getUserName() == null || getUserName().isEmpty())
+            return null;
+        
+        ArrayList<UserInfo> all = getAllDataSorted(true);
+        
+        if (all == null)
+            return null; // Error reading file
+        
+        for (int i = 0; i < all.size();i++)
+        {
+            if (getUserName().equals(all.get(i).getUserName()))
+            {
+                return all.get(i);
+            }
+        }
+        
+        // Couldn't find them anywhere, return blank:
+        return UserInfoVisitor.allocate(getUserName(), -1, getUserName());
+    }
+
+    private UserInfo makeStorage(String[] line, int rank, boolean useSingleton)
+    {
+        UserInfo r = null;
+        try
+        {
+            int column = 0; 
+            r = UserInfoVisitor.allocate(line[column++], rank, useSingleton ? getUserName() : null);
+            r.setScore(Integer.parseInt(line[column++]));
+            for (int i = 0; i < UserInfo.NUM_INTS; i++)
+            {
+                r.setInt(i, Integer.parseInt(line[column++]));
+            }
+            
+            for (int i = 0; i < UserInfo.NUM_STRINGS; i++)
+            {
+                r.setString(i, line[column++]);
+            }
+        }
+        catch (IndexOutOfBoundsException e)
+        {
+            // If we run out of the line, just stop setting the values in storage
+        }
+        
+        return r;
+    }
+    
+
+    private String[] makeLine(String userName, UserInfo data)
+    {
+        String[] line = new String[1 + 1 + UserInfo.NUM_INTS + UserInfo.NUM_STRINGS];
+        int column = 0;
+        line[column++] = userName;
+        line[column++] = Integer.toString(data.getScore());
+        try
+        {
+            for (int i = 0; i < UserInfo.NUM_INTS; i++)
+            {
+                line[column++] = Integer.toString(data.getInt(i));
+            }
+            
+            for (int i = 0; i < UserInfo.NUM_STRINGS; i++)
+            {
+                line[column++] = data.getString(i);
+            }
+        }
+        catch (IndexOutOfBoundsException e)
+        {
+            // Can't happen
+        }        
+        return line;
+    }
+
+    @Override
+    public boolean storeCurrentUserInfo(UserInfo data)
+    {
+        if (getUserName() == null || getUserName().isEmpty())
+            return false;
+        
+        List<String[]> all;
+        try
+        {
+            CSVReader csv = new CSVReader(new InputStreamReader(new FileInputStream("storage.csv"), "UTF-8"));
+            all = csv.readAll();
+            csv.close();
+        }
+        catch (FileNotFoundException e)
+        {
+            // No previous storage, make a new blank one:
+            all = new ArrayList<String[]>();
+        }
+        catch (IOException e)
+        {
+            Debug.message("Error reading user data: " + e.getMessage());
+            return false;
+        }
+        
+        // First, remove any existing line:
+        Iterator<String[]> lineIt = all.iterator();
+        while (lineIt.hasNext())
+        {
+            String[] line = lineIt.next();
+            if (line.length > 1 && getUserName().equals(line[0]))
+            {
+                lineIt.remove();
+                break;
+            }
+        }
+        
+        // Then add a line on to the end:
+        if (data != null)
+        {
+            // No line for that user, add a new one:
+            all.add(makeLine(getUserName(), data));
+        }
+        
+        try
+        {
+            CSVWriter csvOut = new CSVWriter(new OutputStreamWriter(new FileOutputStream("storage.csv"), "UTF-8"));
+            csvOut.writeAll(all);
+            csvOut.close();
+            
+            return true;
+        }
+        catch (IOException e)
+        {
+            Debug.message("Error storing user data: " + e.getMessage());
+            return false;
+        }
+    }
+    
+    private ArrayList<UserInfo> getAllDataSorted(boolean useSingleton)
+    {
+        try
+        {
+            ArrayList<UserInfo> ret = new ArrayList<UserInfo>();
+            
+            CSVReader csv = new CSVReader(new InputStreamReader(new FileInputStream("storage.csv"), "UTF-8"));
+            
+            List<String[]> all = csv.readAll();
+            
+            Collections.sort(all, new Comparator<String[]>() {
+                @Override
+              public Comparator<String[]> reversed() {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<String[]> thenComparing(
+                  Comparator<? super String[]> other) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public <U> Comparator<String[]> thenComparing(
+                  Function<? super String[], ? extends U> keyExtractor,
+                  Comparator<? super U> keyComparator) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public <U extends Comparable<? super U>> Comparator<String[]> thenComparing(
+                  Function<? super String[], ? extends U> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<String[]> thenComparingInt(
+                  ToIntFunction<? super String[]> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<String[]> thenComparingLong(
+                  ToLongFunction<? super String[]> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+              @Override
+              public Comparator<String[]> thenComparingDouble(
+                  ToDoubleFunction<? super String[]> keyExtractor) {
+                // TODO Auto-generated method stub
+                return null;
+              }
+
+                @Override
+                public int compare(String[] o1, String[] o2)
+                {
+                    // Sort in reverse order:
+                    return -(Integer.parseInt(o1[1]) - Integer.parseInt(o2[1]));
+                }
+            });
+            
+            int rank = 1;
+            for (String[] line : all)
+            {
+                ret.add(makeStorage(line, rank, useSingleton));
+                rank++;
+            }
+            
+            return ret;
+        }
+        catch (FileNotFoundException e)
+        {
+            // No previous storage, return the blank list:
+            return new ArrayList<UserInfo>();
+        }
+        catch (IOException e)
+        {
+            Debug.message("Error reading user data: " + e.getMessage());
+            return null;
+        }
+    }
+
+    @Override
+    public List<UserInfo> getTopUserInfo(int limit)
+    {
+        ArrayList<UserInfo> ret = getAllDataSorted(false);
+        if (ret == null)
+            return null;
+        else if (ret.size() <= limit || limit <= 0)
+            return ret;
+        else
+            return ret.subList(0, limit);
+    }
+
+    @Override
+    public GreenfootImage getUserImage(String userName)
+    {
+        // GreenfootUtil will take care of making a dummy image:
+        return null;
+    }
+
+    @Override
+    public List<UserInfo> getNearbyUserInfo(int maxAmount)
+    {
+        if (getUserName() == null || getUserName().isEmpty())
+            return null;
+        
+        ArrayList<UserInfo> all = getAllDataSorted(false);
+        
+        if (all == null)
+            return null;
+        
+        int index = -1;
+        
+        for (int i = 0; i < all.size();i++)
+        {
+            if (getUserName() != null && getUserName().equals(all.get(i).getUserName()))
+            {
+                index = i;
+                break;
+            }
+        }
+        
+        if (index == -1 || maxAmount == 0)
+            return new ArrayList<UserInfo>();
+        
+        int availableBefore = index;
+        int availableAfter = all.size() - 1 - index;
+        
+        int desiredBefore = maxAmount / 2;
+        int desiredAfter = Math.max(0, maxAmount - 1) / 2;
+        
+        // maxAmount | desiredBefore | desiredAfter | before+after+1
+        // 1 | 0 | 0 | 1
+        // 2 | 1 | 0 | 2
+        // 3 | 1 | 1 | 3
+        // 4 | 2 | 1 | 4
+        // 5 | 2 | 2 | 5
+        // 6 | 3 | 2 | 6
+        // and so on...
+        
+        if (availableAfter + availableBefore + 1 <= maxAmount)
+        {
+            //Less overall that we want, use everything:
+            return all;
+        }
+        else if (availableBefore <= desiredBefore)
+        {
+            // Not enough available before-hand, but must be enough in total:
+            return all.subList(index - availableBefore, index - availableBefore + maxAmount + 1);
+        }
+        else if (availableAfter <= desiredAfter)
+        {
+            // Not enough available after, but must be enough in total:
+            return all.subList(index + availableAfter - maxAmount, index + availableAfter + 1);
+        }
+        else
+        {
+            // Must have enough available before and after:
+            return all.subList(index - desiredBefore, index + desiredAfter + 1);
+        }
+    }
+    
+    
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/SimulationDelegateIDE.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/SimulationDelegateIDE.java
new file mode 100644
index 0000000000000000000000000000000000000000..90c52a57444152d7ffcc6c766fc82f1a0109ba73
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/SimulationDelegateIDE.java
@@ -0,0 +1,49 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms.ide;
+
+import greenfoot.core.GProject;
+import greenfoot.core.GreenfootMain;
+import greenfoot.core.ProjectProperties;
+import greenfoot.core.Simulation;
+import greenfoot.platforms.SimulationDelegate;
+
+/**
+ * IDE version of the Simulation delegates.
+ * This class implements the setSpeed method to store the speed setting to the project properties.
+ * 
+ * @author Poul Henriksen
+ */
+public class SimulationDelegateIDE
+    implements SimulationDelegate
+{
+
+    public void setSpeed(int speed)
+    {
+        GProject project = GreenfootMain.getInstance().getProject();
+        if(project != null) {
+            ProjectProperties props = project.getProjectProperties();
+            props.setInt("simulation.speed", Simulation.getInstance().getSpeed());
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/WorldHandlerDelegateIDE.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/WorldHandlerDelegateIDE.java
new file mode 100644
index 0000000000000000000000000000000000000000..c2f942bd19e42441fd5d56c1c8845194943e47af
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/ide/WorldHandlerDelegateIDE.java
@@ -0,0 +1,610 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms.ide;
+
+import greenfoot.Actor;
+import greenfoot.ObjectTracker;
+import greenfoot.World;
+import greenfoot.actions.SaveWorldAction;
+import greenfoot.core.ClassStateManager;
+import greenfoot.core.GClass;
+import greenfoot.core.GNamedValue;
+import greenfoot.core.GProject;
+import greenfoot.core.ImageCache;
+import greenfoot.core.Simulation;
+import greenfoot.core.WorldHandler;
+import greenfoot.core.WorldInvokeListener;
+import greenfoot.event.SimulationUIListener;
+import greenfoot.gui.DragGlassPane;
+import greenfoot.gui.GreenfootFrame;
+import greenfoot.gui.MessageDialog;
+import greenfoot.gui.input.InputManager;
+import greenfoot.localdebugger.LocalObject;
+import greenfoot.platforms.WorldHandlerDelegate;
+import greenfoot.record.GreenfootRecorder;
+import greenfoot.record.InteractionListener;
+import greenfoot.util.GreenfootUtil;
+
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.rmi.RemoteException;
+import java.util.List;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+
+import rmiextension.wrappers.RObject;
+import bluej.Config;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.gentype.JavaType;
+import bluej.debugmgr.inspector.InspectorManager;
+import bluej.debugmgr.objectbench.ObjectBenchEvent;
+import bluej.debugmgr.objectbench.ObjectBenchInterface;
+import bluej.debugmgr.objectbench.ObjectBenchListener;
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.Debug;
+import bluej.views.CallableView;
+
+
+/**
+ * Implementation for running in the Greenfoot IDE.
+ * 
+ * @author Poul Henriksen
+ */
+public class WorldHandlerDelegateIDE
+    implements WorldHandlerDelegate, ObjectBenchInterface, InteractionListener, SimulationUIListener
+{
+    protected final Color envOpColour = Config.ENV_COLOUR;
+
+    private final static String missingConstructorTitle = Config.getString("world.missing.constructor.title");
+    private final static String missingConstructorMsg = Config.getString("world.missing.constructor.msg");
+    private final static String continueButtonText = Config.getString("greenfoot.continue");
+
+    private WorldHandler worldHandler;
+
+    private GProject project;
+    
+    private GreenfootFrame frame;
+    private InspectorManager inspectorManager;
+    
+    // Records actions manually performed on the world:
+    private GreenfootRecorder greenfootRecorder;
+    private SaveWorldAction saveWorldAction;
+
+    private boolean worldInitialising;
+
+    public WorldHandlerDelegateIDE(GreenfootFrame frame, InspectorManager inspectorManager,
+            ClassStateManager classStateManager)
+    {
+        this.frame = frame;
+        this.inspectorManager = inspectorManager;
+        greenfootRecorder = new GreenfootRecorder();
+        saveWorldAction = new SaveWorldAction(greenfootRecorder, classStateManager);
+        saveWorldAction.setRecordingValid(false);
+    }
+
+    /**
+     * Make a popup menu suitable for calling methods on, inspecting and
+     * removing an object in the world.
+     */
+    private JPopupMenu makeActorPopupMenu(final Actor obj)
+    {
+        JPopupMenu menu = new JPopupMenu();
+
+        ObjectWrapper.createMethodMenuItems(menu, obj.getClass(),
+                new WorldInvokeListener(frame, obj, this, inspectorManager, this, project),
+                LocalObject.getLocalObject(obj), null, false);
+
+        // "inspect" menu item
+        JMenuItem m = getInspectMenuItem(obj);
+        menu.add(m);
+
+        // "remove" menu item
+        m = new JMenuItem(Config.getString("world.handlerDelegate.remove"));
+        m.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                worldHandler.getWorld().removeObject(obj);
+                removedActor(obj);
+                worldHandler.repaint();
+            }
+        });
+        m.setFont(PrefMgr.getStandoutMenuFont());
+        m.setForeground(envOpColour);
+        menu.add(m);
+        return menu;
+    }
+
+    /**
+     * Create a pop-up allowing the user to call methods, inspect and "Save the World"
+     * on the World object.
+     */
+    private JPopupMenu makeWorldPopupMenu(final World world)
+    {
+        if (world == null)
+            return null;
+        
+        JPopupMenu menu = new JPopupMenu();
+        
+        ObjectWrapper.createMethodMenuItems(menu, world.getClass(),
+                new WorldInvokeListener(frame, world, WorldHandlerDelegateIDE.this,
+                        inspectorManager, this, project),
+                LocalObject.getLocalObject(world), null, false);
+        // "inspect" menu item
+        JMenuItem m = getInspectMenuItem(world);
+
+        // "save the world" menu item
+        JMenuItem saveTheWorld = new JMenuItem(saveWorldAction);
+        saveTheWorld.setFont(PrefMgr.getStandoutMenuFont());
+        saveTheWorld.setForeground(envOpColour);
+        
+        menu.add(m);
+        menu.add(saveTheWorld);
+        return menu;
+    }
+
+    /**
+     * Create a menu item to inspect an object.
+     */
+    private JMenuItem getInspectMenuItem(final Object obj)
+    {
+        JMenuItem m = new JMenuItem(Config.getString("world.handlerDelegate.inspect"));
+        m.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e)
+            {
+                JFrame parent = (JFrame) worldHandler.getWorldCanvas().getTopLevelAncestor();
+                DebuggerObject dObj = LocalObject.getLocalObject(obj);
+                String instanceName = "";
+                try {
+                    RObject rObject = ObjectTracker.getRObject(obj);
+                    if (rObject != null) {
+                        instanceName = rObject.getInstanceName();
+                    }
+                }
+                catch (RemoteException e1) {
+                    Debug.reportError("Could not get instance name for inspection", e1);
+                }
+                inspectorManager.getInspectorInstance(dObj, instanceName, null, null, parent);
+            }
+        });
+        m.setFont(PrefMgr.getStandoutMenuFont());
+        m.setForeground(envOpColour);
+        return m;
+    }
+
+    /**
+     * Shows a pop-up menu if the MouseEvent is a pop-up trigger.
+     * Pop-up menu depends on if the MouseEvent occurred on an Actor
+     * or the world.
+     */
+    @Override
+    public boolean maybeShowPopup(MouseEvent e)
+    {
+        if (e.isPopupTrigger()) {
+            JPopupMenu menu;
+            Actor obj = worldHandler.getObject(e.getX(), e.getY());
+            // if null then the user clicked on the world
+            if (obj == null) {
+                menu = makeWorldPopupMenu(worldHandler.getWorld());
+            } else {
+                menu = makeActorPopupMenu(obj);
+            }
+            if (menu != null) {
+                menu.show(worldHandler.getWorldCanvas(), e.getX(), e.getY());
+            }
+            return true;
+
+        }
+        return false;
+    }
+    
+    /**
+     * Displays the world pop-up menu in the location specified
+     * by the parameter MouseEvent.
+     * @param e Used to get the component to display in as well as the x
+     * and y coordinates.
+     */
+    public void showWorldPopupMenu(MouseEvent e)
+    {
+        JPopupMenu menu = makeWorldPopupMenu(worldHandler.getWorld());
+        if (menu != null) {
+            menu.show(e.getComponent(), e.getX(), e.getY());
+        }
+    }
+
+    /**
+     * Clear the world from the cache.
+     * @param world  World to discard
+     */
+    @Override
+    public void discardWorld(World world)
+    {        
+        ObjectTracker.clearRObjectCache();
+    }
+    
+    @Override
+    public void setWorld(final World oldWorld, final World newWorld)
+    {
+        greenfootRecorder.clearCode(false);
+        greenfootRecorder.setWorld(newWorld);
+        if (oldWorld != null) {
+            discardWorld(oldWorld);
+        }
+        
+        GClass lastWorld = null;
+        if (project != null && newWorld != null) {
+            String lastWorldClass = newWorld.getClass().getName();
+            if (lastWorldClass != null) {
+                lastWorld = project.getDefaultPackage().getClass(lastWorldClass);
+            }
+        }
+
+        saveWorldAction.setLastWorldGClass(lastWorld);
+    }
+    
+    /**
+     * Fire an object event for the named object. This will
+     * notify all listeners that have registered interest for
+     * notification on this event type.
+     */
+    public void fireObjectEvent(Actor actor)
+    {
+        GNamedValue value =null;
+        try {
+            RObject rObj = ObjectTracker.getRObject(actor);
+            if (rObj != null) {
+                value =  new GNamedValue(rObj.getInstanceName(), null);
+            }
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Error when trying to get object instance name", e);
+        }
+        
+        if (value != null) {
+            // guaranteed to return a non-null array
+            Object[] listeners = worldHandler.getListenerList().getListenerList();
+            // process the listeners last to first, notifying
+            // those that are interested in this event
+            for (int i = listeners.length-2; i>=0; i-=2) { 
+                if (listeners[i] == ObjectBenchListener.class) {
+                    ((ObjectBenchListener)listeners[i+1]).objectEvent(
+                            new ObjectBenchEvent(this,
+                                    ObjectBenchEvent.OBJECT_SELECTED, value));
+                }
+            }
+        }
+    }
+    
+    @Override
+    public void addObjectBenchListener(ObjectBenchListener listener)
+    {
+        worldHandler.getListenerList().add(ObjectBenchListener.class, listener);
+    }
+    
+    @Override
+    public void removeObjectBenchListener(ObjectBenchListener listener)
+    {
+        worldHandler.getListenerList().remove(ObjectBenchListener.class, listener);
+    }
+    
+    @Override
+    public boolean hasObject(String name)
+    {
+        return false;
+    }
+
+    @Override
+    public void mouseClicked(MouseEvent e)
+    {
+        if (SwingUtilities.isLeftMouseButton(e)) {
+            Actor actor = worldHandler.getObject(e.getX(), e.getY());
+            if (actor != null) {
+                fireObjectEvent(actor);
+            }
+        }
+    }
+    
+    @Override
+    public void mouseMoved(MouseEvent e)
+    {
+        // While dragging, other methods set the mouse cursor instead:
+        if (false == worldHandler.isDragging()) {
+            Actor actor = worldHandler.getObject(e.getX(), e.getY());
+            if (actor == null) {
+                worldHandler.getWorldCanvas().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+            } else {
+                worldHandler.getWorldCanvas().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+            }
+        }
+    }
+
+    /**
+     * Attach to a particular project. This should be called whenever the project
+     * changes.
+     */
+    public void attachProject(Object project)
+    {
+        this.project = (GProject) project;
+    }
+
+    @Override
+    public void setWorldHandler(WorldHandler handler)
+    {
+        this.worldHandler = handler;
+    }
+
+    @Override
+    public void instantiateNewWorld()
+    {
+        greenfootRecorder.reset();
+        worldInitialising = true;
+        Class<? extends World> cls = getLastWorldClass();
+        GClass lastWorldGClass = getLastWorldGClass();
+        
+        if (lastWorldGClass == null) {
+            // Either the last instantiated world no longer exists, or there is no record
+            // of a last instantiated world class. Find a world arbitrarily.
+            List<Class<? extends World>> worldClasses = project.getDefaultPackage().getWorldClasses();
+            if(worldClasses.isEmpty() ) {
+                return;
+            }
+            
+            for (Class<? extends World> wclass : worldClasses) {
+                try {
+                    wclass.getConstructor(new Class<?>[0]);
+                    cls = wclass;
+                    break;
+                }
+                catch (LinkageError le) { }
+                catch (NoSuchMethodException nsme) { }
+            }
+            if (cls == null) {
+                // Couldn't find a world with a suitable constructor
+                showMissingConstructorDialog();
+                return;
+            }
+        }
+        
+        if (cls == null) {
+            // Can occur if last instantiated world class is not compiled.
+            return;
+        }
+        
+        final Class<? extends World> icls = cls;
+        Simulation.getInstance().runLater(new Runnable() {
+            @Override
+            public void run()
+            {
+                try {
+                    Constructor<?> cons = icls.getConstructor(new Class<?>[0]);
+                    WorldHandler.getInstance().clearWorldSet();
+                    World newWorld = (World) Simulation.newInstance(cons);
+                    if (! WorldHandler.getInstance().checkWorldSet()) {
+                        ImageCache.getInstance().clearImageCache();
+                        WorldHandler.getInstance().setWorld(newWorld);
+                    }
+                    saveWorldAction.setRecordingValid(true);
+                    project.setLastWorldClassName(icls.getName());
+                }
+                catch (LinkageError e) { }
+                catch (NoSuchMethodException nsme) {
+                    showMissingConstructorDialog();
+                }
+                catch (InstantiationException e) {
+                    // abstract class; shouldn't happen
+                }
+                catch (IllegalAccessException e) {
+                    showMissingConstructorDialog();
+                }
+                catch (InvocationTargetException ite) {
+                    // This can happen if a static initializer block throws a Throwable.
+                    // Or for other reasons.
+                    ite.getCause().printStackTrace();
+                }
+                worldInitialising = false;
+            }
+        });
+    }
+
+    private void showMissingConstructorDialog()
+    {
+        JButton button = new JButton(continueButtonText);
+        MessageDialog msgDialog = new MessageDialog(frame, missingConstructorMsg, missingConstructorTitle, 50, new JButton[]{button});
+        msgDialog.display();
+    }
+    
+    /**
+     * Get the last-instantiated world class if known and possible. May return null.
+     */
+    public GClass getLastWorldGClass()
+    {
+        if (project == null) {
+            return null;
+        }
+        
+        String lastWorldClass = project.getLastWorldClassName();
+        if(lastWorldClass == null) {
+            return null;
+        }
+        
+        return project.getDefaultPackage().getClass(lastWorldClass);
+    }
+    
+    /**
+     * Get the last world class that was instantiated, if it can (still) be instantiated.
+     * May return null.
+     */
+    @SuppressWarnings("unchecked")
+    private Class<? extends World> getLastWorldClass()
+    {
+        GClass gclass = getLastWorldGClass();
+        if (gclass != null) {
+            Class<? extends World> rclass = (Class<? extends World>) gclass.getJavaClass();
+            if (GreenfootUtil.canBeInstantiated(rclass)) {
+                return  rclass;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public InputManager getInputManager()
+    {
+        InputManager inputManager = new InputManager();       
+        DragGlassPane.getInstance().addMouseListener(inputManager);
+        DragGlassPane.getInstance().addMouseMotionListener(inputManager);
+        DragGlassPane.getInstance().addKeyListener(inputManager);        
+        inputManager.setIdleListeners(worldHandler, worldHandler, worldHandler);
+        inputManager.setDragListeners(null, DragGlassPane.getInstance(), DragGlassPane.getInstance());
+        inputManager.setMoveListeners(worldHandler, worldHandler, worldHandler);
+        
+        return inputManager;
+    }
+    
+    @Override
+    public void beginCallExecution(CallableView callableView)
+    {
+        if (callableView.isConstructor() && World.class.isAssignableFrom(callableView.getDeclaringView().getViewClass())) {
+            worldInitialising = true;
+            greenfootRecorder.reset();
+            saveWorldAction.setRecordingValid(true);            
+        }
+    }
+    
+    @Override
+    public void worldConstructed(Object world)
+    {
+        worldInitialising = false;
+        if (project != null) {
+            project.setLastWorldClassName(world.getClass().getName());
+        }
+    }
+    
+    @Override
+    public void addActor(Actor actor, int x, int y)
+    {
+        greenfootRecorder.addActorToWorld(actor, x, y);
+    }
+
+    @Override
+    public void createdActor(Object actor, String[] args, JavaType[] argTypes)
+    {
+        greenfootRecorder.createActor(actor, args, argTypes);
+    }
+
+    @Override
+    public void methodCall(Object obj, String actorName, String name, String[] args, JavaType[] argTypes)
+    {
+        if (obj != null) {
+            greenfootRecorder.callActorMethod(obj, actorName, name, args, argTypes);
+        }
+        else {
+            greenfootRecorder.callStaticMethod(actorName, name, args, argTypes);
+        }
+    }
+    
+    @Override
+    public void actorDragged(Actor actor, int xCell, int yCell)
+    {
+        greenfootRecorder.moveActor(actor, xCell, yCell);
+    }
+
+    @Override
+    public void removedActor(Actor obj)
+    {
+        greenfootRecorder.removeActor(obj);        
+    }
+
+    @Override
+    public void objectAddedToWorld(Actor object)
+    {
+        if (worldInitialising) {
+            // This code is nasty; we look at the stack trace to see if
+            // we have been called from the prepare() method of the world class.
+            //
+            // We do this so that when the prepare() method is called again from the
+            // code, we give the first names to those objects that are created in the prepare()
+            // method -- which should then be identical to the names the objects had when
+            // they were first recorded.  That way we can record additional code,
+            // and the names of the live objects will be the same as the names of the objects
+            // when the code was initially recorded.
+            //
+            // I don't know if getting the stack trace is slow, but it's probably
+            // still more efficient (in time and memory) than giving every actor a name.
+            // Also, this code only runs in the IDE, not in the stand-alone version
+            // And I've now added a check above to make sure this is only done while the 
+            // world is being initialised (which is when prepare() would be called).
+            StackTraceElement[] methods = Thread.currentThread().getStackTrace();
+
+            boolean gonePastUs = false;
+            GClass lastWorldGClass = getLastWorldGClass();
+            if (lastWorldGClass == null) {
+                return;
+            }
+            String lastWorldClassName = getLastWorldGClass().getName();
+            
+            for (StackTraceElement item : methods) {
+                if (GreenfootRecorder.METHOD_NAME.equals(item.getMethodName()) &&
+                        item.getClassName().equals(lastWorldClassName)) {
+                    // This call gives the object a name,
+                    // which will be necessary for appending operations with the object to the world's code:
+                    greenfootRecorder.nameActor(object);
+                    return;
+                }
+
+                if (gonePastUs && item.getClassName().startsWith("java.")) {
+                    //We won't find any java.* classes between us and the prepare method, so if
+                    //we do hit one, we know we won't find anything; this should speed things up a bit:
+                    return;
+                }
+
+                gonePastUs = gonePastUs || "objectAddedToWorld".equals(item.getMethodName());
+            }
+        }
+    }
+
+    /**
+     * Notify that the simulation has become active ("act" or "run" pressed). Any recorded interaction
+     * then becomes invalid.
+     */
+    @Override
+    public void simulationActive()
+    {
+        greenfootRecorder.clearCode(true);
+        saveWorldAction.setRecordingValid(false);
+    }
+
+    public SaveWorldAction getSaveWorldAction()
+    {
+        return saveWorldAction;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/ActorDelegateStandAlone.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/ActorDelegateStandAlone.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d49e0cc5096e15938eafc2b4c5c9dde9436a8e5
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/ActorDelegateStandAlone.java
@@ -0,0 +1,59 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms.standalone;
+
+import greenfoot.ActorVisitor;
+import greenfoot.GreenfootImage;
+import greenfoot.core.ProjectProperties;
+import greenfoot.platforms.ActorDelegate;
+
+/**
+ * Delegate for the Actor when it is running in a stand alone project created by
+ * the "export" functionality in Greenfoot.
+ * 
+ * @author Poul Henriksen <polle@polle.org>
+ */
+public class ActorDelegateStandAlone
+    implements ActorDelegate
+{
+    private static ActorDelegateStandAlone instance = new ActorDelegateStandAlone();
+    private ProjectProperties properties;
+    
+    /**
+     * Register this class as the delegate for Actor.
+     *
+     */
+    public static void setupAsActorDelegate()
+    {
+        ActorVisitor.setDelegate(instance);
+    }
+
+    public static void initProperties(ProjectProperties properties)
+    {
+        instance.properties = properties;
+    }
+
+    public GreenfootImage getImage(String name)
+    {
+        return properties.getImage(name);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/GreenfootUtilDelegateStandAlone.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/GreenfootUtilDelegateStandAlone.java
new file mode 100644
index 0000000000000000000000000000000000000000..377c45549766f5f5f44350ef4a590b2f43af19d9
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/GreenfootUtilDelegateStandAlone.java
@@ -0,0 +1,592 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms.standalone;
+
+import greenfoot.GreenfootImage;
+import greenfoot.UserInfoVisitor;
+import greenfoot.UserInfo;
+import greenfoot.platforms.GreenfootUtilDelegate;
+import greenfoot.util.GreenfootStorageException;
+
+import java.awt.Component;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of GreenfootUtilDelegate for standalone applications.
+ */
+public class GreenfootUtilDelegateStandAlone implements GreenfootUtilDelegate
+{
+    private SocketChannel socket;
+    private boolean failedLastConnection;
+    private boolean firstStorageException = true;
+    private boolean storageStandalone;
+    private String storageHost;
+    private String storagePort;
+    private String storagePasscode;
+    private String storageScenarioId;
+    private String storageUserId;
+    private String storageUserName;
+    
+    public GreenfootUtilDelegateStandAlone(boolean storageStandalone,
+            String storageHost, String storagePort, String storagePasscode,
+            String storageScenarioId, String storageUserId,
+            String storageUserName)
+    {
+        this.storageStandalone = storageStandalone;
+        this.storageHost = storageHost;
+        this.storagePort = storagePort;
+        this.storagePasscode = storagePasscode;
+        this.storageScenarioId = storageScenarioId;
+        this.storageUserId = storageUserId;
+        this.storageUserName = storageUserName;
+    }
+    
+    @Override
+    public URL getResource(String path)
+    {
+        // Resources from the standalone should always be in a jar, which means
+        // they should contain the character "!". If we do get a URL back, and
+        // it doesn't contain a ! it is probably because it didn't exists, but
+        // the webserver produced an error page at the given URL instead of
+        // returning a fail. Therefore, we need to explicitly test for the
+        // existence of a ! in the returned URL.
+        URL res = this.getClass().getClassLoader().getResource(path);
+        if (res != null && res.toString().contains("!")) {  
+            return res;
+        }
+        else {
+            if (path.indexOf('\\') != -1) {
+                // Looks suspiciously like a Windows path.
+                path = path.replace('\\', '/');
+                res = this.getClass().getClassLoader().getResource(path);
+                if (res != null && res.toString().contains("!")) {  
+                    return res;
+                }
+            }
+            return null;
+        }
+    }
+    
+    @Override
+    public Iterable<String> getSoundFiles()
+    {
+        InputStream is = this.getClass().getClassLoader().getResourceAsStream("soundindex.list");
+        ArrayList<String> r = new ArrayList<String>();
+        
+        if (is != null)
+        {
+            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+            String line;
+            try
+            {
+                while ((line = reader.readLine()) != null)
+                {
+                    r.add(line);
+                }
+            }
+            catch (IOException e)
+            {
+                //Silently stop
+            }
+        }
+        
+        // May just be blank if there's a problem:
+        return r;
+    }    
+
+    /**
+     * Returns the path to a small version of the greenfoot logo.
+     */
+    @Override
+    public String getGreenfootLogoPath()
+    {    
+        return this.getClass().getClassLoader().getResource("greenfoot.png").toString();
+    }
+    
+    @Override
+    public void displayMessage(Component parent, String messageText)
+    {
+        System.err.println(messageText);
+    }
+    
+    /**
+     * Closes the connection (well, silently drops it), but allows
+     * a subsequent connection attempt
+     */
+    private void closeConnection(Exception e)
+    {
+        e.printStackTrace();
+        socket = null;
+        failedLastConnection = false;
+    }
+
+    @Override
+    public boolean isStorageSupported()
+    {
+        try
+        {
+            ensureStorageConnected();
+            return getCurrentUserInfo() != null;
+        }
+        catch (GreenfootStorageException e)
+        {
+            // Let the user know why it didn't connect.  This will go to the Java console,
+            // which is only shown if the user has specifically turned it on.
+            // Make sure we only print one exception from this method, otherwise
+            // someone who calls it a lot will see lots of console spam (esp in standalone
+            // applets):
+            if (firstStorageException)
+            {
+                e.printStackTrace();
+            }
+            firstStorageException = false;
+            return false;
+        }
+    }
+    
+    /**
+     * Tries to connect to the server, if not already connected.
+     * 
+     * If it returns without throwing an exception, you can assume you are connected.
+     * 
+     * @throws GreenfootStorageException if there is a problem
+     */
+    private void ensureStorageConnected() throws GreenfootStorageException
+    {
+        if (socket != null && socket.isConnected())
+            return; //Already connected
+        
+        if ((socket == null || !socket.isConnected()) && failedLastConnection)
+            throw new GreenfootStorageException("Already failed to connect to storage server on last attempt");
+            // We don't continually try to reconnect -- probably a firewall blocked us
+        
+        if (!storageStandalone)
+            throw new GreenfootStorageException("Standalone storage not supported");
+            // This means the gallery didn't give us the go-ahead via an applet param
+        
+        System.err.println("Attempting to reconnect to storage server");
+        
+        int userId;
+        try
+        {
+            userId = Integer.parseInt(storageUserId);
+            if (userId < 0)
+                throw new GreenfootStorageException("User not logged in");
+        }
+        catch (NumberFormatException e)
+        {
+            throw new GreenfootStorageException("Invalid user ID");
+        }
+        
+        short port;
+        try
+        {
+            port = Short.parseShort(storagePort); 
+        }
+        catch (NumberFormatException e)
+        {
+            throw new GreenfootStorageException("Error connecting to storage server -- invalid port: " + e.getMessage());
+        }
+        
+        try
+        {
+            if (storagePasscode == null)
+                throw new GreenfootStorageException("Could not find passcode to send back to server");
+            
+            failedLastConnection = true; // True unless we reach the end
+            
+            socket = SocketChannel.open();
+            if (!socket.connect(new InetSocketAddress(storageHost, port)))
+            {
+                socket = null;
+                throw new GreenfootStorageException("Could not connect to storage server");
+            }
+            
+            ByteBuffer buffer = makeRequest((storagePasscode.length() / 2) + 4 + 4);
+            for (int i = 0; i < storagePasscode.length() / 2; i++)
+            {
+                // Because bytes are parsed as signed, we must use short to be able to pass bytes above 0x80
+                byte b = (byte)(0xFF & Short.parseShort(storagePasscode.substring(i * 2, i * 2 + 2), 16));
+                buffer.put(b);
+            }
+            try
+            {
+                buffer.putInt(Integer.parseInt(storageScenarioId));
+                buffer.putInt(userId);
+            }
+            catch (NumberFormatException e)
+            {
+                socket = null;
+                throw new GreenfootStorageException("Invalid scenario ID: " + e.getMessage());
+            }
+            buffer.flip();
+            socket.write(buffer);
+            
+            failedLastConnection = false; // We succeeded, so didn't fail!
+        }
+        catch (IOException e)
+        {
+            socket = null;
+            throw new GreenfootStorageException("Error connecting to storage server: " + e.getMessage());
+        }
+    }
+    
+    private ByteBuffer makeRequest(int plusBytes)
+    {
+        ByteBuffer buf = ByteBuffer.allocate(4 + plusBytes);
+        buf.putInt(plusBytes); // bytes after this point
+        
+        return buf;
+    }
+    
+    private void readFullBuffer(ByteBuffer buf, int amount) throws IOException
+    {
+        int totalBytes = 0;
+        while (totalBytes < amount)
+        {
+            int bytesRead = socket.read(buf);
+            if (bytesRead > 0)
+                totalBytes += bytesRead;
+            else
+                throw new IOException("Zero or negative bytes read from socket");
+        }
+        buf.flip();
+    }
+    
+    private ByteBuffer readResponse() throws IOException
+    {
+        ByteBuffer buf = ByteBuffer.allocate(4);
+        readFullBuffer(buf, 4);
+        int size = buf.getInt();
+        buf = ByteBuffer.allocate(size);
+        readFullBuffer(buf, size);
+        return buf;
+    }
+
+    @Override
+    public UserInfo getCurrentUserInfo()
+    {
+        try
+        {
+            ensureStorageConnected();
+            ByteBuffer buf = makeRequest(1);
+            buf.put((byte) 1);
+            buf.flip();
+            socket.write(buf);
+            
+            buf = readResponse();
+            if (1 != buf.getInt()) // Should be exactly one user
+                return null; // Error, or we're not logged in
+            return readLines(buf, 1, true)[0];
+        }
+        catch (IOException e)
+        {
+            closeConnection(e);
+            //throw new GreenfootStorageException("Error communicating with server: " + e.getMessage());
+            return null;
+        }
+        catch (BufferUnderflowException e)
+        {
+            closeConnection(e);
+            //throw new GreenfootStorageException("Server sent aborted message");
+            return null;
+        }
+        catch (GreenfootStorageException e)
+        {
+            closeConnection(e);
+            return null;
+        }
+    }
+    
+    private static String getString(ByteBuffer buf) throws BufferUnderflowException
+    {
+        int len = buf.getShort(); //2-bytes for length
+        if (len == -1)
+            return null;
+        
+        char[] cs = new char[len];
+        for (int i = 0; i < len; i++)
+        {
+            cs[i] = buf.getChar();
+        }
+        return new String(cs);
+    }
+    
+    private static void putString(ByteBuffer buf, String value)
+    {
+        if (value == null)
+        {
+            buf.putShort((short) -1);
+        }
+        else
+        {
+            buf.putShort((short)value.length()); //2-bytes for length
+            for (int i = 0; i < value.length(); i++)
+            {
+                buf.putChar(value.charAt(i));
+            }
+        }
+    }
+
+    private UserInfo[] readLines(ByteBuffer buf, int numLines, boolean useSingleton) throws BufferUnderflowException
+    {
+        // Read number of ints then number of Strings (username not included)
+        int numInts = buf.getInt();
+        int numStrings = buf.getInt();
+        
+        UserInfo[] r = new UserInfo[numLines]; 
+        
+        for (int line = 0; line < numLines; line++)
+        {
+            String userName = getString(buf);
+            int score = buf.getInt();
+            int rank = buf.getInt();
+            r[line] = UserInfoVisitor.allocate(userName, rank, useSingleton ? getUserName() : null);
+            r[line].setScore(score);
+            for (int i = 0; i < numInts; i++)
+            {
+                int x = buf.getInt();
+                if (i < UserInfo.NUM_INTS)
+                    r[line].setInt(i, x);
+            }
+            for (int i = 0; i < numStrings; i++)
+            {
+                String s = getString(buf);
+                if (i < UserInfo.NUM_STRINGS)
+                    r[line].setString(i, s);
+            }
+        }
+        return r;
+    }
+
+    @Override
+    public boolean storeCurrentUserInfo(UserInfo data)
+    {
+        try
+        {
+            ensureStorageConnected();
+            int payloadLength = 0;
+            payloadLength += 4 + 4 + (1 + UserInfo.NUM_INTS) * 4;
+            for (int i = 0; i < UserInfo.NUM_STRINGS; i++)
+                payloadLength += stringSize(data.getString(i));
+            
+            ByteBuffer buf = makeRequest(1 + payloadLength);
+            buf.put((byte) 2);
+            buf.putInt(data.getScore());
+            buf.putInt(UserInfo.NUM_INTS);
+            buf.putInt(UserInfo.NUM_STRINGS);
+            for (int i = 0; i < UserInfo.NUM_INTS; i++)
+                buf.putInt(data.getInt(i));
+            for (int i = 0; i < UserInfo.NUM_STRINGS; i++)
+                putString(buf, data.getString(i));
+            buf.flip();
+            socket.write(buf);
+            
+            buf = readResponse();
+            byte code = buf.get();
+            if (code != 0)
+            {
+                // Connection will be closed in catch block beneath:
+                throw new GreenfootStorageException("Error storing data, code: " + Byte.toString(code));
+            }
+            
+            return true;
+        }
+        catch (IOException e)
+        {
+            closeConnection(e);
+            //throw new GreenfootStorageException("Error communicating with server: " + e.getMessage());
+            return false;
+        }
+        catch (BufferUnderflowException e)
+        {
+            closeConnection(e);
+            //throw new GreenfootStorageException("Server sent aborted message");
+            return false;
+        }
+        catch (GreenfootStorageException e)
+        {
+            closeConnection(e);
+            return false;
+        }
+    }
+
+    private static int stringSize(String string)
+    {
+        if (string == null)
+            return 2;
+        else
+            return 2 + (2 * string.length());
+    }
+
+    @Override
+    public List<UserInfo> getTopUserInfo(int limit)
+    {
+        try
+        {
+            ensureStorageConnected();
+            ByteBuffer buf = makeRequest(1 + 4);
+            buf.put((byte) 3);
+            buf.putInt(limit);
+            buf.flip();
+            socket.write(buf);
+            
+            buf = readResponse();
+            int numUsers = buf.getInt();
+            UserInfo[] storage = readLines(buf, numUsers, false);
+            
+            List<UserInfo> r = new ArrayList<UserInfo>();
+            for (UserInfo s : storage)
+            {
+                r.add(s);
+            }
+            return r;
+        }
+        catch (IOException e)
+        {
+            closeConnection(e);
+            //System.err.println("Error communicating with server: " + e.getMessage());
+            return null;
+        }
+        catch (BufferUnderflowException e)
+        {
+            closeConnection(e);
+            //throw new GreenfootStorageException("Server sent aborted message");
+            return null;
+        }
+        catch (GreenfootStorageException e)
+        {
+            closeConnection(e);
+            return null;
+        }
+    }
+    
+    @Override
+    public List<UserInfo> getNearbyUserInfo(int limit)
+    {
+        try
+        {
+            ensureStorageConnected();
+            ByteBuffer buf = makeRequest(1 + 4);
+            buf.put((byte) 5);
+            buf.putInt(limit);
+            buf.flip();
+            socket.write(buf);
+            
+            buf = readResponse();
+            int numUsers = buf.getInt();
+            if (numUsers < 0)
+                return null; // Error, or we're not logged in
+            
+            UserInfo[] storage = readLines(buf, numUsers, false);
+            
+            List<UserInfo> r = new ArrayList<UserInfo>();
+            for (UserInfo s : storage)
+            {
+                r.add(s);
+            }
+            return r;
+        }
+        catch (IOException e)
+        {
+            closeConnection(e);
+            //System.err.println("Error communicating with server: " + e.getMessage());
+            return null;
+        }
+        catch (BufferUnderflowException e)
+        {
+            closeConnection(e);
+            //throw new GreenfootStorageException("Server sent aborted message");
+            return null;
+        }
+        catch (GreenfootStorageException e)
+        {
+            closeConnection(e);
+            return null;
+        }
+    }
+
+    @Override
+    public GreenfootImage getUserImage(String userName)
+    {
+        if (userName == null || userName.equals(""))
+            userName = storageUserName;
+        
+        try
+        {
+            ensureStorageConnected();
+            ByteBuffer buf = makeRequest(1 + 2 + (2*userName.length()));
+            buf.put((byte) 4);
+            putString(buf, userName);
+            buf.flip();
+            socket.write(buf);
+            
+            buf = readResponse();
+            int numBytes = buf.getInt();
+            byte[] fileData = new byte[numBytes];
+            buf.get(fileData);
+            
+            // We can't create a temporary file and read that back in,
+            // because we are in an applet, so we must pass the file contents
+            // directly to a hidden constructor:
+        
+            try
+            {
+                return UserInfoVisitor.readImage(fileData);
+            }
+            catch (IllegalArgumentException e)
+            {
+                // We can't read the image, not a permanent failure:
+                return null;
+            }
+        }
+        catch (IOException e)
+        {
+            closeConnection(e);
+            //throw new GreenfootStorageException("Error communicating with server: " + e.getMessage());
+            return null;
+        }
+        catch (GreenfootStorageException e)
+        {
+            closeConnection(e);
+            return null;
+        }
+    }
+
+    @Override
+    public String getUserName()
+    {
+        return storageUserName;
+    }
+    
+    
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/SimulationDelegateStandAlone.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/SimulationDelegateStandAlone.java
new file mode 100644
index 0000000000000000000000000000000000000000..c13d9c608a2bd7468dad90463bc5daf3e9cae0d0
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/SimulationDelegateStandAlone.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms.standalone;
+
+import greenfoot.platforms.SimulationDelegate;
+
+/**
+ * Stand alone version of the Simulation delegate.
+ *
+ * Implements an empty stub for the setSpeed() method which is not used.
+ * 
+ * @author Poul Henriksen
+ */
+public class SimulationDelegateStandAlone
+    implements SimulationDelegate
+{
+    public void setSpeed(int speed)
+    {
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/WorldHandlerDelegateStandAlone.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/WorldHandlerDelegateStandAlone.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e923e965fbe7e36027a0f1d7e4e507a398cbc0b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/platforms/standalone/WorldHandlerDelegateStandAlone.java
@@ -0,0 +1,121 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.platforms.standalone;
+
+import greenfoot.Actor;
+import greenfoot.World;
+import greenfoot.core.WorldHandler;
+import greenfoot.export.GreenfootScenarioViewer;
+import greenfoot.gui.input.InputManager;
+import greenfoot.platforms.WorldHandlerDelegate;
+
+import java.awt.event.MouseEvent;
+
+
+/**
+ * Implementation for running scenarios in a standalone application or applet.
+ * 
+ * @author Poul Henriksen
+ */
+public class WorldHandlerDelegateStandAlone implements WorldHandlerDelegate
+{    
+    private WorldHandler worldHandler;
+    private GreenfootScenarioViewer viewer;
+    private boolean lockScenario;
+    
+    public WorldHandlerDelegateStandAlone (GreenfootScenarioViewer viewer, boolean lockScenario) 
+    {
+        this.viewer = viewer;
+        this.lockScenario = lockScenario;
+    }
+    
+    public boolean maybeShowPopup(MouseEvent e)
+    {
+        // Not used in standalone
+        return false;
+    }
+
+    public void mouseClicked(MouseEvent e)
+    {
+        // Not used in standalone
+    }
+    
+    public void mouseMoved(MouseEvent e)
+    {
+        // Not used in standalone
+    }
+
+    @Override
+    public void setWorld(final World oldWorld, final World newWorld)
+    {
+        // Not needed
+    }
+
+    public void setWorldHandler(WorldHandler handler)
+    {
+        this.worldHandler = handler;
+    }
+
+    public void instantiateNewWorld()
+    {
+        WorldHandler.getInstance().clearWorldSet();
+        World newWorld = viewer.instantiateNewWorld();
+        if (! WorldHandler.getInstance().checkWorldSet()) {
+            WorldHandler.getInstance().setWorld(newWorld);
+        }
+    }
+
+    public InputManager getInputManager()
+    {
+        InputManager inputManager = new InputManager();
+        inputManager.setDragListeners(null, null, null);
+        if (lockScenario) {
+            inputManager.setIdleListeners(null, null, null);
+            inputManager.setMoveListeners(null, null, null);
+        }
+        else {
+            inputManager.setIdleListeners(worldHandler, worldHandler, worldHandler);
+            inputManager.setMoveListeners(worldHandler, worldHandler, worldHandler);
+        }
+        return inputManager;
+    }
+
+    public void discardWorld(World world)
+    {
+        // Nothing special to do.    
+    }
+
+    public void addActor(Actor actor, int x, int y)
+    {
+        // Nothing to be done
+    }
+
+    @Override
+    public void actorDragged(Actor actor, int xCell, int yCell)
+    {
+    }
+    
+    @Override
+    public void objectAddedToWorld(Actor actor)
+    {
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/record/GreenfootRecorder.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/record/GreenfootRecorder.java
new file mode 100644
index 0000000000000000000000000000000000000000..49e033728af88c18acacde907f18766f084ac436
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/record/GreenfootRecorder.java
@@ -0,0 +1,255 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2010,2011 Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.record;
+
+import greenfoot.Actor;
+import greenfoot.ObjectTracker;
+import greenfoot.World;
+
+import java.rmi.RemoteException;
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+import rmiextension.wrappers.RObject;
+import bluej.debugger.gentype.JavaType;
+import bluej.utility.Debug;
+
+/**
+ * Builder for code sequences representing a recording of what the user has
+ * done interactively to the world.
+ */
+public class GreenfootRecorder
+{
+    /** A map of known objects to their name as it appears in the code */
+    private IdentityHashMap<Object, String> objectNames;
+    private LinkedList<String> code;
+    private World world;
+    
+    public static final String METHOD_NAME = "prepare";
+    
+    /**
+     * Construct a new GreenfootRecorder instance.
+     */
+    public GreenfootRecorder()
+    {
+        objectNames = new IdentityHashMap<Object, String>();
+        code = new LinkedList<String>();
+    }
+
+    /**
+     * Record the interactive construction of an actor object.
+     * @param actor   The newly constructed actor
+     * @param args     The arguments supplied to the actor's constructor, as Java expresssions
+     * @param paramTypes  The parameter types of the called constructor
+     */
+    public synchronized void createActor(Object actor, String[] args, JavaType[] paramTypes)
+    {
+        Class<?> theClass = actor.getClass();
+        String name = nameActor(actor);
+        if (name != null) {
+            code.add(theClass.getCanonicalName() + " " + name + " = new " + theClass.getCanonicalName() + "(" + withCommas(args, paramTypes) + ");");
+        }
+    }
+    
+    /**
+     * Called when the prepare method is replayed to indicate that the actor's name should be recorded.
+     * Returns the name assigned to the actor (or null on failure).
+     * 
+     * <p>This is called from the simulation thread (with the world locked), or from the createActor method
+     * above, which is called from the Swing EDT.
+     */
+    public synchronized String nameActor(Object actor)
+    {
+        try {
+            RObject rObject = ObjectTracker.getRObject(actor);
+            if (rObject != null) {
+                String name = rObject.getInstanceName();
+                objectNames.put(actor, name);
+                return name;
+            } else {
+                return null;
+            }
+        }
+        catch (RemoteException e) {
+            Debug.reportError("Error naming actor", e);
+            return null;
+        }
+    }
+    
+    /**
+     * Insert commas and other necessary syntax into an argument list
+     * @param args      The arguments to a method or constructor call (as Java expressions)
+     * @param paramTypes  The parameter types of the method/constructor
+     * @return  The arguments as a comma-separated list
+     */
+    private static String withCommas(String[] args, JavaType[] paramTypes)
+    {
+        if (args == null) {
+            return "";
+        }
+        
+        StringBuffer commaArgs = new StringBuffer();
+        
+        for (int i = 0; i < args.length;i++) {
+            String arg = args[i].trim();
+            if (arg.startsWith("{") && arg.endsWith("}")) {
+                arg = "new " + paramTypes[i] + " " + arg;
+            }
+            commaArgs.append(arg);
+            if (i != args.length - 1) {
+                commaArgs.append(", ");
+            }
+        }
+        return commaArgs.toString();
+    }
+    
+    /**
+     * An actor was interactively added to the world: record the interaction
+     * @param actor   The added actor
+     * @param x       The actor's x position
+     * @param y       The actor's y position
+     */
+    public synchronized void addActorToWorld(Actor actor, int x, int y)
+    {
+        String actorObjectName = objectNames.get(actor);
+        if (null == actorObjectName) {
+            //An actor that we don't know about is being added to the world: ignore
+            return;
+        }
+        code.add("addObject(" + actorObjectName + ", " + x + ", " + y + ");");
+    }
+
+    /**
+     * Record an interactive method call on object (actor or world). Called after the method
+     * successfully returns.
+     * 
+     * @param obj        The object on which the method was invoked
+     * @param actorName  The assigned object name
+     * @param methodName  The method name
+     * @param args       The arguments to the method, as Java expressions
+     * @param paramTypes  The parameter types of the method
+     */
+    public synchronized void callActorMethod(Object obj, String actorName, String methodName,
+            String[] args, JavaType[] paramTypes)
+    {
+        if (obj != null && null == objectNames.get(obj) && obj != world) {
+            //Method is being called on an actor we don't know about: ignore
+            return;
+        }
+        
+        if (world != null && world == obj) {
+            // Called on the world, so don't use the world's object name before the call:
+            code.add(methodName + "(" + withCommas(args, paramTypes) + ");");
+        }
+        else {
+            code.add(actorName + "." + methodName + "(" + withCommas(args, paramTypes) + ");");
+        }
+    }
+
+    /**
+     * Record an interactive static method call. Called after the method
+     * successfully returns.
+     * 
+     * @param className  The name of the class to which the called method belongs
+     * @param methodName  The method name
+     * @param args       The arguments to the method, as a
+     * @param argTypes
+     */
+    public void callStaticMethod(String className, String name, String[] args, JavaType[] argTypes)
+    {
+        // No difference in syntax, so no need to replicate the code:
+        callActorMethod(null, className, name, args, argTypes);
+    }
+    
+    /**
+     * Notify the recorder that it should clear its recording.
+     * 
+     * @param simulationStarted  Whether the simulation is now running.
+     */
+    public synchronized void clearCode(boolean simulationStarted)
+    {
+        code.clear();
+        if (simulationStarted) {
+            objectNames.clear();
+        }
+    }
+
+    /**
+     * Notify the recorder that a new world is being initialised. This is currently called from the
+     * simulation thread (with the current world locked).
+     */
+    public synchronized void reset()
+    {
+        objectNames.clear();
+        clearCode(false);
+    }
+    
+    /**
+     * Notify the recorder that a new world has become the current world.
+     * Called from the simulation thread.
+     */
+    public synchronized void setWorld(World newWorld)
+    {
+        world = newWorld;
+    }
+
+    /**
+     * Record a dragged actor interaction. This is currently called from the simulation
+     * thread (i.e. with the world locked).
+     */
+    public synchronized void moveActor(Actor actor, int xCell, int yCell)
+    {        
+        String actorObjectName = objectNames.get(actor);
+        if (null == actorObjectName) {
+            // This could happen with programmatically generated actors (e.g. in a World's method)
+            // if the user drags them around afterwards.
+            // We'll just have to ignore it
+            return;
+        }
+        code.add(actorObjectName + ".setLocation(" + xCell + ", " + yCell + ");");
+    }
+
+    /**
+     * Record a remove actor interaction.
+     */
+    public void removeActor(Actor obj)
+    {
+        String actorObjectName = objectNames.get(obj);
+        if (null == actorObjectName) {
+            // This could happen with programmatically generated actors (e.g. in a World's method)
+            // if the user tries to remove them afterwards.
+            // We'll just have to ignore it
+            return;
+        }
+        code.add("removeObject(" + actorObjectName + ");");
+        objectNames.remove(obj);
+    }
+
+    /**
+     * Retrieve the Java code representing the interactions recorded up to this point.
+     */
+    public synchronized List<String> getCode()
+    {
+        return new LinkedList<String>(code);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/record/InteractionListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/record/InteractionListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..38cb670a74d5f25beae78f6aefb2e1934541b80f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/record/InteractionListener.java
@@ -0,0 +1,68 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.record;
+
+import greenfoot.Actor;
+import bluej.debugger.gentype.JavaType;
+import bluej.views.CallableView;
+
+/**
+ * An interface currently used to provide hooks for recording the save-the-world.
+ */
+public interface InteractionListener
+{
+    /**
+     * An interactive method/constructor call has begun execution.
+     */
+    public void beginCallExecution(CallableView callableView);
+    
+    /**
+     * Notify that an actor was constructed interactively by the user.
+     * @param actor   The actor object
+     * @param String[] args   The constructor arguments (as Java expressions)
+     */
+    public void createdActor(Object actor, String[] args, JavaType[] argTypes);
+
+    /**
+     * A world was constructed interactively. This would normally, but not necessarily,
+     * mean that the constructed world is now the current world.
+     * 
+     * @param world  The newly constructed world
+     */
+    public void worldConstructed(Object world);
+    
+    /**
+     * A method was called and successfully returned (no exception was
+     * thrown).
+     * 
+     * @param obj  The target of the method call - will be null for a static method
+     * @param targetName   The name of the target object or class 
+     * @param methodName   The name of the called method
+     * @param args       The method arguments (as java expressions)
+     * @param argTypes   The argument types of the method. For a varargs method the last type will be an array.
+     */
+    public void methodCall(Object obj, String targetName, String methodName, String[] args, JavaType[] argTypes);
+
+    public void removedActor(Actor obj);
+
+    public void objectAddedToWorld(Actor object);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/AudioLine.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/AudioLine.java
new file mode 100644
index 0000000000000000000000000000000000000000..326da97bd1c63dbdf0cc4b289f3effe3f7832a83
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/AudioLine.java
@@ -0,0 +1,358 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.FloatControl;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.SourceDataLine;
+
+/**
+ * Wraps a SourceDataLine to work around all the different bugs that happens on
+ * different systems.
+ * <p>
+ * To work around all the different problems listed below, this class minimises
+ * the use of open and close and never uses drain. Instead we use the fact that
+ * we know how long it takes to play a certain number of bytes and use this to
+ * implement our own drain method. By using this timing we also don't have to
+ * open and close on the line in order to reset the framecount of the line when
+ * restarting, since it is not used anyway.
+ * 
+ * <p>
+ * <p>
+ * There are several inconsistencies between different platforms that means that
+ * this class is more complicated than it really should be if everything worked
+ * as it should. Below is listed the different problems observed on various
+ * platforms:
+ * <p>
+ * Windows XP on Poul's home PC (SP3, Sun JDK 1.6.11, SB Live Sound Card) and
+ * Windows Vista on Poul's office PC (dell build in soundcard) and Windows XP on
+ * Poul's office PC (SP2, dell onboard soundcard)
+ * <ul>
+ * <li>Line does not receive a stop signal when end of media has been reached.</li>
+ * <li>Line is reported as active even when end of media has been reached. If
+ * invoking stop, then start again, it seems to remain inactive though (this
+ * does not generate a START event, only a stop)</li>
+ * <li>The frame position reported by line.getLongFramePosition() is incorrect.
+ * After reaching the last frame, it will, after a while, start over at frame
+ * position 0 and count up to the last frame again. It will repeat this forever.
+ * </li>
+ * </ul>
+ * <p>
+ * Linux on Poul's home PC (Ubuntu 8.10, Sun JDK 1.6.10, SB Live Sound Card):
+ * <ul>
+ * <li>Line does not receive a stop signal when end of media has been reached.</li>
+ * <li>Line is reported as active even when end of media has been reached.</li>
+ * <li>Hangs if line.drain() is used (need to confirm this, saw it a long time
+ * ago, and it might have been because of timing issues resulting in drain()
+ * being invoked on a stopped line)</li>
+ * <li>The frame position reported by line.getLongFramePosition() is correct and
+ * seems to be the only way of detecting when the end of the media has been
+ * reached.</li>
+ * </ul>
+ * <p>
+ * <p>
+ * Linux on Poul's office PC (Ubuntu 8.10, Sun JDK 1.6.10 / 1.5.16, SB Live
+ * Sound Card):
+ * <ul>
+ * <li>Repeatedly calling close and open makes it hang in close.</li>
+ * <li>Haven't tested whether line.drain() works.</li>
+ * 
+ * </ul>
+ * <p>
+ * Mac (OS 10.5.6, JDK 1.5.0_16
+ * <ul>
+ * <li>Closing and opening a line repeatedly crashes the JVM with this error.
+ * Can be reproduced in the piano scenario if you quickly press the same button
+ * about 10-20 times in row. (JDK 1.5 prints the error below, 1.6 just crashes
+ * silently): <br>
+ * java(3382,0xb1b4e000) malloc: *** mmap(size=1073745920) failed (error
+ * code=12)<br>
+ * error: can't allocate region<br>
+ * set a breakpoint in malloc_error_break to debug</li>
+ * <li>It skips START events if the line is closed before we have received the
+ * START event.</li>
+ * </ul>
+ * 
+ * 
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class AudioLine
+{
+
+    private static void printDebug(String s)
+    {
+        // Comment this line out if you don't want debug info.
+        // System.out.println(s);
+    }
+    /**
+     * Extra delay in ms added to the sleep time before stopping the sound. This
+     * is just an extra buffer of time to make sure we don't close it too soon.
+     * This helps avoid stopping the sound too soon which seems to happen on
+     * some Linux systems.
+     */
+    private final static int EXTRA_SLEEP_DELAY = 50;
+    /**
+     * The actual line that we wrap. I assume this object is thread-safe,
+     * because it has methods that only makes sense in a multi-threaded
+     * environment (drain()).
+     */
+    private volatile SourceDataLine line;
+    private AudioFormat format;
+    /** Total bytes written since playback started. */
+    private long totalWritten;
+    /** Whether the line is open. */
+    private boolean open;
+    /** Whether the line has been started. */
+    private boolean started;
+    private int masterVolume;
+    /**
+     * Whether data is currently being written to the line (or blocked on
+     * write).
+     */
+    private boolean writing;
+    /**
+     * Whether the line is reset. As soon as data has been written, the line is
+     * no longer reset.
+     */
+    private boolean reset;
+    /** Keeps track of how much time have been spend on active playback. */
+    private TimeTracker timeTracker;
+
+    public AudioLine(SourceDataLine line, AudioFormat format)
+    {
+        this.line = line;
+        this.format = format;
+        timeTracker = new TimeTracker();
+    }
+
+    /**
+     * Opens the line. If already open, this method does nothing.
+     * 
+     * @throws LineUnavailableException if the line cannot be opened due to
+     *             resource restrictions
+     * @throws IllegalArgumentException if <code>format</code> is not fully
+     *             specified or invalid
+     * @throws SecurityException if the line cannot be opened due to security
+     *             restrictions
+     */
+    public synchronized void open()
+            throws LineUnavailableException, IllegalArgumentException, IllegalStateException, SecurityException
+    {
+        if (!open) {
+            line.open(format);
+            open = true;
+            reset = true;
+        }
+    }
+
+    /**
+     * Closes the line. If the line is not open, this method does nothing.
+     */
+    public synchronized void close()
+    {
+        if (open) {
+            open = false;
+            reset();
+            line.close();
+        }
+    }
+
+    /**
+     * Starts the line. Can be used to resume playback that have been stopped.
+     * Unlike SourceDataLine this method does NOT have to be called before
+     * writing to the line.
+     */
+    public synchronized void start()
+    {
+        if (!started && open) {
+            line.start();
+            started = true;
+            if (getTimeLeft() > 0) {
+                // If we haven't finished playback of bytes already written, we
+                // should start the tracker again.
+                timeTracker.start();
+            }
+        }
+    }
+
+    /**
+     * Stops the line. Playback will stop. It can later be resumed by calling
+     * start.
+     */
+    public synchronized void stop()
+    {
+        if (open) {
+            //stop = true;
+            notifyAll();
+            started = false;
+            line.stop();
+            timeTracker.pause();
+        }
+    }
+
+    /**
+     * Resets this line by stopping playback and clearing all the data in the
+     * buffer. The line will remain open. If the line is not open, this method
+     * does nothing.
+     */
+    public synchronized void reset()
+    {
+        printDebug("reset() start");
+
+        if (open) {
+            if (started) {
+                line.stop();
+            }
+            if (!reset) {
+                line.flush();
+            }
+            totalWritten = 0;
+            // TODO: totalWritten might be updated after this in write method.
+            started = false;
+            timeTracker.reset();
+            notifyAll();
+        }
+        reset = true;
+        printDebug("reset() end");
+    }
+
+    /**
+     * Will attempt to write the given bytes to the line. This method might
+     * block if it can't write it all at once. If the line is not open then this
+     * method will return 0 immediately.
+     * 
+     * @return The number of bytes written (different from len if the line was
+     *         stopped while writing).
+     */
+    public int write(byte[] b, int off, int len)
+    {
+        synchronized (this) {
+            if (!open) {
+                return 0;
+            }
+
+            writing = true;
+            started = true;
+            reset = false;
+            timeTracker.start();
+        }
+        line.start();
+        int written = line.write(b, off, len);
+        synchronized (this) {
+            // drain() might be waiting, so we should wake it up.
+            notifyAll();
+            writing = false;
+            if (!reset) {
+                totalWritten += written;
+            }
+            else if (reset && open) {
+                // Flush what we just wrote to keep it reset.
+                line.flush();
+            }
+            return written;
+        }
+    }
+
+    /**
+     * Wait for the line to finish playback. If this line is closed or reset it
+     * will return immediately. If the line is stopped, this method will not
+     * return until the line is started again.
+     * 
+     * @return True if we successfully drained all the data, false if the line
+     *         was closed before playback finished.
+     */
+    public synchronized boolean drain()
+    {
+        printDebug("Draining start");
+        printDebug(" totalWritten: " + totalWritten);
+        long timeLeft = getTimeLeft();
+        while (timeLeft > 0 && open) {
+            printDebug(" timeLeft: " + timeLeft);
+            if (started && timeLeft > 0) {
+                try {
+                    wait(timeLeft);
+                }
+                catch (InterruptedException e) {
+                }
+            }
+            else if (!started || writing) {
+                try {
+                    // Line is stopped, or we are currently writing to the line
+                    // so we wait until waken up again.
+                    wait();
+                }
+                catch (InterruptedException e) {
+                }
+            }
+            timeLeft = getTimeLeft();
+        }
+
+        printDebug("Draining end: " + timeLeft);
+        if (timeLeft > 0) {
+            return false;
+        }
+        else {
+            return true;
+        }
+    }
+
+    public synchronized boolean isOpen()
+    {
+        return open;
+    }
+
+    private synchronized long getTimeLeft()
+    {
+        return SoundUtils.getTimeToPlayBytes(totalWritten, format) - timeTracker.getTimeTracked() + EXTRA_SLEEP_DELAY;
+    }
+
+    public long getLongFramePosition()
+    {
+        return line.getLongFramePosition();
+    }
+
+    public synchronized void setVolume(int masterVolume)
+    {
+        this.masterVolume = masterVolume;
+        try {
+            open();
+            if (line != null) {
+                if (line.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
+                    FloatControl volume = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN);
+                    float val = SoundUtils.convertMinMax(masterVolume, volume.getMinimum(), volume.getMaximum());
+                    volume.setValue(val);
+                }
+            }
+        }
+        catch (LineUnavailableException ex) {
+            SoundExceptionHandler.handleLineUnavailableException(ex);
+        }
+    }
+
+    public synchronized int getVolume()
+    {
+        return masterVolume;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipCache.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..62699f04d5103f9c59ae8671c773926afd8b2b60
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipCache.java
@@ -0,0 +1,112 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * A cache for soundclip data.
+ * 
+ * @author Davin McCall
+ */
+public class ClipCache
+{
+    /** Data for clips that aren't currently in use */
+    private LinkedHashMap<String,ClipData> freeClips = new LinkedHashMap<String,ClipData>();
+    private int numberFreeClips = 0;
+    
+    private static int MAX_CACHED_CLIPS = 20;
+    
+    /** Data for clips that are in use */
+    private Map<String,ClipData> cachedClips = new HashMap<String,ClipData>();
+    
+    public synchronized ClipData getCachedClip(URL url)
+        throws IOException, UnsupportedAudioFileException
+    {
+        String urlStr = url.toString();
+        ClipData data = cachedClips.get(urlStr);
+        if (data == null) {
+            // Maybe we have a free clip
+            data = freeClips.remove(urlStr);
+            if (data != null) {
+                numberFreeClips --;
+                cachedClips.put(urlStr, data);
+            }
+        }
+        if (data == null) {
+            // We need to create a new clip
+            AudioInputStream ais = AudioSystem.getAudioInputStream(url);
+            AudioFormat af = ais.getFormat();
+            long frameLength = ais.getFrameLength();
+            
+            int total = (int)(af.getFrameSize() * frameLength);
+            byte[] allBytes = new byte[(int)(af.getFrameSize() * frameLength)];
+            int pos = 0;
+            
+            try {
+                while (pos < total) {
+                    int r = ais.read(allBytes, pos, total - pos);
+                    if (r == -1) {
+                        break;
+                    }
+                    pos += r;
+                }
+            }
+            finally {
+                ais.close();
+            }
+            
+            data = new ClipData(urlStr, allBytes, af, (int) frameLength);
+        }
+        else {
+            data.addUser();
+        }
+        
+        return data;
+    }
+    
+    public synchronized void releaseClipData(ClipData data)
+    {
+        if (data.release()) {
+            cachedClips.remove(data.getUrl());
+            freeClips.put(data.getUrl(), data);
+            numberFreeClips++;
+            if (numberFreeClips > MAX_CACHED_CLIPS) {
+                // remove least recently used free clip
+                Iterator<ClipData> it = freeClips.values().iterator();
+                it.next();
+                it.remove();
+                numberFreeClips = MAX_CACHED_CLIPS;
+            }
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipCloserThread.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipCloserThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..da6e4270ddf19a15658578b0f53f98373efdbb1a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipCloserThread.java
@@ -0,0 +1,77 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.util.LinkedList;
+
+import javax.sound.sampled.Clip;
+
+/**
+ * On OpenJDK/IcedTea (pulseaudio, 2012-03-26) it seems that clips take a long time to close
+ * after they have finished playing. To prevent this from blocking us, we have a dedicated thread
+ * (this class) to close old clips.
+ * 
+ * @author Davin McCall
+ */
+public class ClipCloserThread implements Runnable
+{
+    private LinkedList<Clip> clips = new LinkedList<Clip>();
+    
+    private Thread thread;
+    
+    public ClipCloserThread()
+    {
+    }
+    
+    public void addClip(Clip clip)
+    {
+        synchronized (clips) {
+            clips.add(clip);
+            clips.notify();
+            
+            if (thread == null || ! thread.isAlive()) {
+                thread = new Thread(this);
+                thread.setDaemon(true);
+                thread.start();
+            }
+        }
+    }
+    
+    @Override
+    public void run()
+    {
+        try {
+            while (true) {
+                Clip clip;
+                synchronized (clips) {
+                    while (clips.isEmpty()) {
+                        clips.wait();
+                    }
+                    clip = clips.removeFirst();
+                }
+                
+                clip.close();
+            }
+        }
+        catch (InterruptedException ie) {}
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipData.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipData.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf1d8a36018a5045d4788219f15e5767ebbc6339
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipData.java
@@ -0,0 +1,80 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import javax.sound.sampled.AudioFormat;
+
+/**
+ * Data for a sound clip.
+ * 
+ * @author Davin McCall
+ */
+public class ClipData
+{
+    private String url;
+    private byte[] buffer;
+    private AudioFormat format;
+    private int activeUsers;
+    private int length; // length in sample frames
+    
+    /**
+     * Construct a ClipData with a single active user.
+     */
+    public ClipData(String url, byte[] buffer, AudioFormat format, int length)
+    {
+        this.url = url;
+        this.buffer = buffer;
+        this.format = format;
+        this.length = length;
+        this.activeUsers = 1;
+    }
+    
+    public void addUser()
+    {
+        activeUsers++;
+    }
+    
+    public boolean release()
+    {
+        return --activeUsers == 0;
+    }
+    
+    public String getUrl()
+    {
+        return url;
+    }
+    
+    public byte[] getBuffer()
+    {
+        return buffer;
+    }
+    
+    public AudioFormat getFormat()
+    {
+        return format;
+    }
+    
+    public int getLength()
+    {
+        return length;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipProcessThread.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipProcessThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c2102026d4afe71b03d567e940b1b3b7366cb6d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/ClipProcessThread.java
@@ -0,0 +1,79 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.util.LinkedList;
+
+/**
+ * A thread to process certain sound commands, which for some reason
+ * must be processed in a separate thread.
+ * 
+ * @author Davin McCall
+ */
+public class ClipProcessThread implements Runnable
+{
+    private Thread thread;
+    
+    private LinkedList<SoundClip> queue = new LinkedList<SoundClip>();
+    
+    public ClipProcessThread()
+    {
+        thread = new Thread(this);
+        thread.setDaemon(true);
+        thread.start();
+    }
+    
+    public void addToQueue(SoundClip clip)
+    {
+        synchronized (queue) {
+            queue.add(clip);
+            queue.notify();
+            
+            // When running online, threads can be terminated willy-nilly, but
+            // static state is kept. We need to check for this:
+            if (! thread.isAlive()) {
+                thread = new Thread(this);
+                thread.setDaemon(true);
+                thread.start();
+            }
+        }
+    }
+    
+    @Override
+    public void run()
+    {
+        try {
+            SoundClip item;
+            while (true) {
+                synchronized (queue) {
+                    while (queue.isEmpty()) {
+                        queue.wait();
+                    }
+                    item = queue.removeFirst();
+                }
+
+                item.processState();
+            }
+        }
+        catch (InterruptedException ie) { }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/GreenfootAudioInputStream.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/GreenfootAudioInputStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..42f99803ea31f6e6f5be61653479fa89c6d831c4
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/GreenfootAudioInputStream.java
@@ -0,0 +1,213 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * Interface for AudioInputStreams as used in Greenfoot. It is basically just an
+ * interface for InputStream but with the getFormat method from AudioInputStream
+ * added and three other useful methods: open, restart and getSource.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public interface GreenfootAudioInputStream extends Closeable
+{
+    /**
+     * Opens this stream.
+     * 
+     * @throws UnsupportedAudioFileException
+     *             if the stream does not point to valid audio file data
+     *             recognised by the system
+     * @throws IOException
+     *             if an I/O exception occurs
+     */
+    public void open() throws IOException, UnsupportedAudioFileException;
+
+    /**
+     * Restarts this stream by repositioning to the beginning of the stream.
+     * 
+     * @throws UnsupportedAudioFileException
+     *             if the stream does not point to valid audio file data
+     *             recognised by the system
+     * @throws IOException
+     *             if an I/O exception occurs
+     */
+    public void restart() throws IOException, UnsupportedAudioFileException;
+
+    /**
+     * Gets the source where this stream comes from. Typically a filename on a
+     * URL.
+     */
+    public String getSource();
+
+    // ================================================================
+    // Interface for AudioInputStream
+    // ================================================================
+
+    /**
+     * Obtains the audio format of the sound data in this audio input stream.
+     * 
+     * @return an audio format object describing this stream's format
+     */
+    public AudioFormat getFormat();
+
+    // ================================================================
+    // Interface for InputStream
+    // ================================================================
+
+    /**
+     * Reads the next byte of data from the audio input stream.  The audio input
+     * stream's frame size must be one byte, or an <code>IOException</code>
+     * will be thrown.
+     *
+     * @return the next byte of data, or -1 if the end of the stream is reached
+     * @throws IOException if an input or output error occurs
+     * @see #read(byte[], int, int)
+     * @see #read(byte[])
+     * @see #available
+     * <p>
+     * @see javax.sound.sampled.AudioInputStream#read()
+     */
+    public int read() throws IOException;
+
+
+    /**
+     * Reads some number of bytes from the audio input stream and stores them into
+     * the buffer array <code>b</code>. The number of bytes actually read is
+     * returned as an integer. This method blocks until input data is
+     * available, the end of the stream is detected, or an exception is thrown.
+     * <p>This method will always read an integral number of frames.
+     * If the length of the array is not an integral number
+     * of frames, a maximum of <code>b.length - (b.length % frameSize)
+     * </code> bytes will be read.
+     *
+     * @param b the buffer into which the data is read
+     * @return the total number of bytes read into the buffer, or -1 if there
+     * is no more data because the end of the stream has been reached
+     * @throws IOException if an input or output error occurs
+     * @see #read(byte[], int, int)
+     * @see #read()
+     * @see #available
+     * @see javax.sound.sampled.AudioInputStream#read(byte[]))
+     */
+    public int read(byte b[]) throws IOException;
+
+    /**
+     * Reads up to a specified maximum number of bytes of data from the audio
+     * stream, putting them into the given byte array.
+     * <p>This method will always read an integral number of frames.
+     * If <code>len</code> does not specify an integral number
+     * of frames, a maximum of <code>len - (len % frameSize)
+     * </code> bytes will be read.
+     *
+     * @param b the buffer into which the data is read
+     * @param off the offset, from the beginning of array <code>b</code>, at which
+     * the data will be written
+     * @param len the maximum number of bytes to read
+     * @return the total number of bytes read into the buffer, or -1 if there
+     * is no more data because the end of the stream has been reached
+     * @throws IOException if an input or output error occurs
+     * @see #read(byte[])
+     * @see #read()
+     * @see #skip
+     * @see #available
+     * @see javax.sound.sampled.AudioInputStream#read(byte[], int, int)
+     */
+    public int read(byte b[], int off, int len) throws IOException;
+
+
+    /**
+     * Skips over and discards a specified number of bytes from this
+     * audio input stream.
+     * @param n the requested number of bytes to be skipped
+     * @return the actual number of bytes skipped
+     * @throws IOException if an input or output error occurs
+     * @see #read
+     * @see #available
+     * @see javax.sound.sampled.AudioInputStream#skip(long)
+     */
+    public long skip(long n) throws IOException;
+
+    /**
+     * Returns the maximum number of bytes that can be read (or skipped over) from this
+     * audio input stream without blocking.  This limit applies only to the next invocation of
+     * a <code>read</code> or <code>skip</code> method for this audio input stream; the limit
+     * can vary each time these methods are invoked.
+     * Depending on the underlying stream,an IOException may be thrown if this
+     * stream is closed.
+     * @return the number of bytes that can be read from this audio input stream without blocking
+     * @throws IOException if an input or output error occurs
+     * @see #read(byte[], int, int)
+     * @see #read(byte[])
+     * @see #read()
+     * @see #skip
+     * @see javax.sound.sampled.AudioInputStream#available()
+     */
+    public int available() throws IOException;
+
+
+    /**
+     * Closes this audio input stream and releases any system resources associated
+     * with the stream.
+     * @throws IOException if an input or output error occurs
+     * @see javax.sound.sampled.AudioInputStream#close
+     */
+    public void close() throws IOException;
+
+    /**
+     * Marks the current position in this audio input stream.
+     * @param readlimit the maximum number of bytes that can be read before
+     * the mark position becomes invalid.
+     * @see #reset
+     * @see #markSupported
+     * @see javax.sound.sampled.AudioInputStream#mark(int)
+     */
+    public void mark(int readlimit);
+
+    /**
+     * Repositions this audio input stream to the position it had at the time its
+     * <code>mark</code> method was last invoked.
+     * @throws IOException if an input or output error occurs.
+     * @see #mark
+     * @see #markSupported
+     * @see javax.sound.sampled.AudioInputStream#reset()
+     */
+    public void reset() throws IOException;
+
+    /**
+     * Tests whether this audio input stream supports the <code>mark</code> and
+     * <code>reset</code> methods.
+     * @return <code>true</code> if this stream supports the <code>mark</code>
+     * and <code>reset</code> methods; <code>false</code> otherwise
+     * @see #mark
+     * @see #reset
+     * @see javax.sound.sampled.AudioInputStream#markSupported()
+     */
+    public boolean markSupported();
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/JavaAudioInputStream.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/JavaAudioInputStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..357488b651ebdbe2762a0d40b4b7b95a03847e3c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/JavaAudioInputStream.java
@@ -0,0 +1,175 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import bluej.utility.Debug;
+
+/**
+ * Wrapper classer for a AudioInputStream. It just delegates all method to the
+ * wrapped class except for restart().
+ * 
+ * @author Poul Henriksen
+ */
+public class JavaAudioInputStream implements GreenfootAudioInputStream
+{
+    private AudioInputStream stream;
+    private URL url;
+    private boolean readingHasStarted = false;
+    private boolean open;
+
+    public JavaAudioInputStream(URL url) throws UnsupportedAudioFileException,
+    IOException
+    {
+        this.url = url;
+        open();
+    }
+
+    public void open() throws UnsupportedAudioFileException, IOException
+    {
+        if (!open) {
+            readingHasStarted = false;
+
+            if (stream != null) {
+                try {
+                    stream.close();
+                } catch (IOException e) {
+                    // An exception here is probably not fatal, so we just log
+                    // it and continue.
+                    Debug.reportError(
+                            "Exception while closing java audio input stream.",
+                            e);
+                }
+            }
+            stream = AudioSystem.getAudioInputStream(url);
+            open = true;
+        }
+
+    }
+
+    public void restart() throws UnsupportedAudioFileException, IOException
+    {
+        if(!open || readingHasStarted() || stream == null) {
+            open = false;
+            open();
+        }		
+    }
+
+    /**
+     * Whether reading from this stream has begun.
+     * 
+     * @return True if it has been restarted and no reading has been done since.
+     *         False otherwise.
+     */
+    private boolean readingHasStarted()
+    {
+        return readingHasStarted;
+    }
+
+    public String getSource()
+    {
+        return url.toString();
+    }
+
+    public int available() throws IOException
+    {
+        return stream.available();
+    }
+
+    public void close() throws IOException
+    {
+        open = false;
+        stream.close();
+    }
+
+    public boolean equals(Object obj)
+    {
+        return stream.equals(obj);
+    }
+
+    public AudioFormat getFormat()
+    {
+        return stream.getFormat();
+    }
+
+    public long getFrameLength()
+    {
+        return stream.getFrameLength();
+    }
+
+    public int hashCode()
+    {
+        return stream.hashCode();
+    }
+
+    public void mark(int readlimit)
+    {
+        stream.mark(readlimit);
+    }
+
+    public boolean markSupported()
+    {
+        return stream.markSupported();
+    }
+
+    public int read() throws IOException
+    {
+        readingHasStarted = true;
+        return stream.read();
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException
+    {
+        readingHasStarted = true;
+        return stream.read(b, off, len);
+    }
+
+    public int read(byte[] b) throws IOException
+    {
+        readingHasStarted = true;
+        return stream.read(b);
+    }
+
+    public void reset() throws IOException
+    {
+        stream.reset();
+    }
+
+    public long skip(long n) throws IOException
+    {
+        readingHasStarted = true;
+        return stream.skip(n);
+    }
+
+    public String toString()
+    {
+        return stream.toString();
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/MemoryAudioInputStream.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/MemoryAudioInputStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..5fbe53f0f89e874eeb9342fb59e9355c645059bc
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/MemoryAudioInputStream.java
@@ -0,0 +1,158 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.io.IOException;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * An implementation of GreenfootAudioInputStream that reads from a memory buffer
+ * 
+ * @author neil
+ */
+public class MemoryAudioInputStream implements GreenfootAudioInputStream
+{
+    private byte[] sound;
+    private int startOffset;
+    private int endOffset;
+    private AudioFormat format;
+    private int markIndex;
+    private int curIndex;
+    
+    public MemoryAudioInputStream(byte[] sound, AudioFormat format)
+    {
+        curIndex = 0;
+        markIndex = 0;
+        startOffset = 0;
+        endOffset = sound.length;
+        this.sound = sound;
+        this.format = format;
+    }
+    
+    public MemoryAudioInputStream(byte[] sound, int offset, int length, AudioFormat format)
+    {
+        curIndex = offset;
+        markIndex = curIndex;
+        startOffset = offset;
+        endOffset = offset + length;
+        this.sound = sound;
+        this.format = format;
+    }
+    
+    private int getFrameSize()
+    {
+        return format.getFrameSize();
+    }
+    
+    public int available() throws IOException
+    {
+        return endOffset - curIndex;
+    }
+
+    public void close() throws IOException
+    {
+    }
+
+    public AudioFormat getFormat()
+    {
+        return format;
+    }
+
+    public String getSource()
+    {
+        return "Internal buffer";
+    }
+
+    public void mark(int readlimit)
+    {
+        markIndex = curIndex;
+
+    }
+
+    public boolean markSupported()
+    {
+        return true;
+    }
+
+    public void open() throws IOException, UnsupportedAudioFileException
+    {
+        curIndex = startOffset;
+    }
+
+    public int read() throws IOException
+    {
+        if (getFrameSize() != 1)
+            throw new IOException("Attempted to read single byte but frame size is not 1");
+        
+        if (curIndex < endOffset)
+            return sound[curIndex++];
+        else
+            return -1;
+    }
+
+    public int read(byte[] b) throws IOException
+    {
+        return read(b, 0, b.length);
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException
+    {
+        if (curIndex >= endOffset)
+            return -1;
+        
+        int maxRead = len - (len % getFrameSize());
+        
+        if (curIndex + maxRead > endOffset) {
+            int left = endOffset - curIndex;
+            maxRead = left - (left % getFrameSize());
+        }
+        
+        System.arraycopy(sound, curIndex, b, off, maxRead);
+        curIndex += maxRead;
+        
+        return maxRead;
+    }
+
+    public void reset() throws IOException
+    {
+        curIndex = markIndex;
+    }
+
+    public void restart() throws IOException, UnsupportedAudioFileException
+    {
+        curIndex = startOffset;
+    }
+
+    public long skip(long n) throws IOException
+    {
+        if (curIndex + n <= endOffset) {
+            curIndex += n;
+            return n;
+        } else {
+            int diff = endOffset - curIndex;
+            curIndex = endOffset;
+            return diff;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/MicLevelGrabber.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/MicLevelGrabber.java
new file mode 100644
index 0000000000000000000000000000000000000000..80eb6f91fe1a05a6378ba9135189a11da34fb588
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/MicLevelGrabber.java
@@ -0,0 +1,132 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.TargetDataLine;
+
+/**
+ * Gets the overall level of the default microphone plugged into the system.
+ * @author Michael
+ */
+public class MicLevelGrabber
+{
+    private static final MicLevelGrabber INSTANCE = new MicLevelGrabber();
+    private final AudioFormat format;
+    private int level;
+    private final Runnable updator;
+    private volatile boolean running;
+    private boolean reportedFailure;
+
+    /**
+     * Create a new mic level grabber and initialise the updator.
+     */
+    private MicLevelGrabber()
+    {
+        format = new AudioFormat(22050, 8, 1, true, true);
+        updator = new Runnable() {
+
+            public void run() {
+                try {
+                    TargetDataLine line = (TargetDataLine) AudioSystem.getLine(new DataLine.Info(TargetDataLine.class, format));
+                    line.open();
+                    line.start();
+                    int bufferSize = (int) (format.getSampleRate() / 20) * format.getFrameSize();
+                    byte buffer[] = new byte[bufferSize];
+                    int bytesRead = line.read(buffer, 0, bufferSize);
+                    line.stop();
+                    level = (int) ((getRMS(buffer, bytesRead) / 127) * 100);
+                    reportedFailure = false;
+                }
+                catch (LineUnavailableException ex) {
+                    if (! reportedFailure) {
+                        System.err.println("Couldn't get mic level: line unavailable");
+                        reportedFailure = true;
+                    }
+                }
+                catch (IllegalArgumentException iae) {
+                    if (! reportedFailure) {
+                        System.err.println("Couldn't get mic level: can't match 22050,8,1 audio format");
+                        reportedFailure = true;
+                    }
+                }
+                finally {
+                    running = false;
+                }
+            }
+        };
+    }
+
+    /**
+     * Get the singleton instance of this class.
+     * @return the instance.
+     */
+    public static MicLevelGrabber getInstance()
+    {
+        return INSTANCE;
+    }
+
+    /**
+     * Update the microphone level (spawns off a new thread) and return the
+     * level. It will most likely be the previous result that's returned,
+     * however for things like meters where the level is being constantly
+     * monitored this shouldn't be a problem.
+     * 
+     * @return  a microphone input level, between 0 and 100
+     */
+    public int getLevel()
+    {
+        updateLevel();
+        return level;
+    }
+
+    /**
+     * Spawn off the thread to update the mic level value, if it isn't already
+     * running.
+     */
+    private synchronized void updateLevel()
+    {
+        if (!running) {
+            running = true;
+            new Thread(updator).start();
+        }
+    }
+
+    /**
+     * Get the root mean square average of an array of bytes.
+     * @param arr the array of bytes.
+     * @param lim the index to read up to in the array.
+     * @return the root mean square of the values.
+     */
+    private static double getRMS(byte[] arr, int lim)
+    {
+        double average = 0;
+        for (int i = 0; i < arr.length && i < lim; i++) {
+            average += arr[i] * arr[i];
+        }
+        average /= arr.length;
+        return Math.sqrt(average);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/MidiFileSound.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/MidiFileSound.java
new file mode 100644
index 0000000000000000000000000000000000000000..fcead3302ac2ccd509c4b0eda37026862c270d57
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/MidiFileSound.java
@@ -0,0 +1,248 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.sound.midi.InvalidMidiDataException;
+import javax.sound.midi.MetaEventListener;
+import javax.sound.midi.MetaMessage;
+import javax.sound.midi.MidiSystem;
+import javax.sound.midi.MidiUnavailableException;
+import javax.sound.midi.Receiver;
+import javax.sound.midi.Sequence;
+import javax.sound.midi.Sequencer;
+import javax.sound.midi.ShortMessage;
+import javax.sound.midi.Synthesizer;
+import javax.sound.midi.Transmitter;
+
+/**
+ * Plays sound from a MIDI file.
+ * 
+ * TODO: maybe keep it open for a while, instead of closing as soon as playback
+ * has stopped.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class MidiFileSound implements Sound
+{
+    private void printDebug(String s)
+    {
+        //System.out.println(s);
+    }
+    private URL url;
+    private SoundPlaybackListener playbackListener;
+    private Sequencer sequencer;
+    private Synthesizer synthesizer;
+    private Sequence sequence;
+    private boolean pause = false;
+    private int level;
+    private Receiver receiver;
+
+    public MidiFileSound(final URL url, SoundPlaybackListener listener)
+    {
+        this.url = url;
+        playbackListener = listener;
+        try {
+            /*
+             * We read in the MIDI file to a Sequence object. This object is set
+             * at the Sequencer later.
+             */
+            sequence = MidiSystem.getSequence(url);
+
+            /*
+             * Now, we need a Sequencer to play the sequence. Here, we simply
+             * request the default sequencer without an implicitly connected
+             * synthesizer
+             */
+            sequencer = MidiSystem.getSequencer(false);
+
+            synthesizer = MidiSystem.getSynthesizer();
+
+            /*
+             * To free system resources, it is recommended to close the
+             * synthesizer and sequencer properly.
+             *
+             * To accomplish this, we register a Listener to the Sequencer. It
+             * is called when there are "meta" events. Meta event 47 is end of
+             * track.
+             *
+             * Thanks to Espen Riskedal for finding this trick.
+             */
+            sequencer.addMetaEventListener(new MetaEventListener()
+            {
+
+                public void meta(MetaMessage event)
+                {
+                    if (event.getType() == 47) {
+                        close();
+                    }
+                }
+            });
+
+        }
+        catch (InvalidMidiDataException e) {
+            SoundExceptionHandler.handleInvalidMidiDataException(e, url.toString());
+        }
+        catch (IOException e) {
+            SoundExceptionHandler.handleIOException(e, url.toString());
+        }
+        catch (MidiUnavailableException e) {
+            SoundExceptionHandler.handleLineUnavailableException(e);
+        }
+    }
+
+    @Override
+    public synchronized void play()
+    {
+        sequencer.setLoopCount(0);
+
+        if (!isPlaying()) {
+            startPlayback();
+        }
+    }
+
+    /**
+     * Start playback if it hasn't been started yet.
+     */
+    private synchronized void startPlayback()
+    {
+        try {
+            pause = false;
+            open();
+            sequencer.setSequence(sequence);
+            if (sequencer.isOpen()) {
+                sequencer.start();
+                playbackListener.playbackStarted(this);
+            }
+        }
+        catch (SecurityException e) {
+            SoundExceptionHandler.handleSecurityException(e, url.toString());
+        }
+        catch (InvalidMidiDataException e) {
+            SoundExceptionHandler.handleInvalidMidiDataException(e, url.toString());
+        }
+    }
+
+    private synchronized void open()
+    {
+        try {
+            if (!sequencer.isOpen()) {
+                receiver = MidiSystem.getReceiver();
+                /*
+                 * The Sequencer is still a dead object. We have to open() it to
+                 * become live. This is necessary to allocate some resources in
+                 * the native part.
+                 */
+                synthesizer.open();
+                sequencer.open();
+                Transmitter seqTransmitter = sequencer.getTransmitter();
+                seqTransmitter.setReceiver(receiver);
+            }
+        }
+        catch (MidiUnavailableException e) {
+            SoundExceptionHandler.handleLineUnavailableException(e);
+        }
+    }
+
+    @Override
+    public synchronized void loop()
+    {
+        sequencer.setLoopStartPoint(0);
+        sequencer.setLoopEndPoint(-1);
+        sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
+        startPlayback();
+    }
+
+    @Override
+    public synchronized void pause()
+    {
+        pause = true;
+        sequencer.stop();
+        playbackListener.playbackPaused(this);
+    }
+
+    @Override
+    public synchronized void stop()
+    {
+        pause = false;
+        close();
+    }
+
+    @Override
+    public synchronized void close()
+    {
+        playbackListener.playbackStopped(this);
+        pause = false;
+        printDebug(" playback ended: " + url);
+        if (sequencer != null) {
+            sequencer.close();
+        }
+        if (synthesizer != null) {
+            synthesizer.close();
+        }
+        playbackListener.soundClosed(this);
+    }
+
+    @Override
+    public synchronized boolean isPaused()
+    {
+        return pause;
+    }
+
+    @Override
+    public synchronized boolean isPlaying()
+    {
+        return sequencer.isRunning();
+    }
+
+    @Override
+    public synchronized boolean isStopped()
+    {
+        return !isPaused() && !isPlaying();
+    }
+
+    @Override
+    public void setVolume(int level)
+    {
+        open();
+        this.level = level;
+        ShortMessage volMessage = new ShortMessage();
+        for (int i = 0; i < 16; i++) {
+            try {
+                volMessage.setMessage(ShortMessage.CONTROL_CHANGE, i, 7, level);
+            }
+            catch (InvalidMidiDataException e) {
+                e.printStackTrace();
+            }
+            receiver.send(volMessage, -1);
+        }
+    }
+
+    @Override
+    public int getVolume()
+    {
+        return level;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/Mp3AudioInputStream.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/Mp3AudioInputStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f6d1cdfcd1d278e430e97ed5ce90c2aae8dbe73
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/Mp3AudioInputStream.java
@@ -0,0 +1,279 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import javazoom.jl.decoder.Bitstream;
+import javazoom.jl.decoder.BitstreamException;
+import javazoom.jl.decoder.Decoder;
+import javazoom.jl.decoder.DecoderException;
+import javazoom.jl.decoder.Header;
+import javazoom.jl.decoder.SampleBuffer;
+import bluej.utility.Debug;
+
+public class Mp3AudioInputStream implements GreenfootAudioInputStream
+{
+    private static void printDebug(String s)
+    {
+        // Comment this line out if you don't want debug info.
+        //System.out.println(s);
+    }
+
+    /** The MPEG audio bitstream. */
+    private Bitstream bitstream;
+    /** The MPEG audio decoder. */
+    private Decoder decoder;
+    /** URL of the resource */
+    private URL url;
+    private boolean readingHasStarted = false;
+    private BufferedInputStream inputStream;
+    private AudioFormat format;
+    private SampleBuffer unreadSample;
+
+    /** Whether the stream is open or not. */
+    private boolean open;
+
+    public Mp3AudioInputStream(URL url) throws IOException,
+    UnsupportedAudioFileException
+    {
+        this.url = url;
+        open();
+
+        // TODO: is this the correct way to get the format?
+        Header header = null;
+        try {
+            header = bitstream.readFrame();
+            bitstream.unreadFrame();
+        } catch (BitstreamException e) {
+            throw new IOException(e.toString());
+        }
+        if (header == null) {
+            bitstream.closeFrame();
+            format = new AudioFormat(decoder.getOutputFrequency(), 16, decoder
+                    .getOutputChannels(), true, false);
+        } else {
+            int mode = header.mode();
+            int channels = mode == Header.SINGLE_CHANNEL ? 1 : 2;
+            format = new AudioFormat(header.frequency(), 16, channels, true,
+                    false);
+        }
+        printDebug(" Created mp3 stream with audioFormat: " + format);
+    }
+
+    public String getSource()
+    {
+        return url.toString();
+    }
+
+
+    public void open() throws IOException, UnsupportedAudioFileException
+    {
+        if (!open) {
+            readingHasStarted = false;
+            unreadSample = null;
+
+            if (bitstream != null) {
+                try {
+                    bitstream.close();
+                } catch (BitstreamException e) {
+                    // An exception here is probably not fatal, so we just log
+                    // it and continue.) {
+                    Debug.reportError(
+                            "Exception while closing mp3 audio input stream.",
+                            e);
+                }
+            }
+            inputStream = new BufferedInputStream(url.openStream());
+            bitstream = new Bitstream(inputStream);
+
+            decoder = new Decoder();
+            open = true;
+        }
+    }
+
+    public void restart() throws IOException, UnsupportedAudioFileException
+    {
+        if(!open || readingHasStarted() || bitstream == null) {
+            open = false;
+            open();
+        }
+    }
+
+    /**
+     * Whether reading from this stream has begun.
+     * 
+     * @return True if it has been restarted and no reading has been done since.
+     *         False otherwise.
+     */
+    private boolean readingHasStarted()
+    {
+        return readingHasStarted;
+    }
+
+    public int available() throws IOException
+    {
+        return inputStream.available();
+    }
+
+    public void close() throws IOException
+    {
+        open = false;
+        try {
+            bitstream.close();
+        } catch (BitstreamException e) {
+            throw new IOException(e.toString());
+        }
+    }
+
+    public AudioFormat getFormat()
+    {
+        return format;
+    }
+
+    public void mark(int readlimit)
+    {
+        // not supported
+    }
+
+    public boolean markSupported()
+    {
+        return false;
+    }
+
+    public int read() throws IOException
+    {
+        byte [] b = new byte[1];
+
+        int bytesRead = read(b, 0, 1);
+        if(bytesRead < 0) {
+            return -1;
+        }
+        else if(bytesRead == 0) {
+            throw new IOException("cannot read a single byte if frame size > 1");
+        } else {
+            return b[0] & 0xFF;
+        }
+    }
+
+    public int read(byte[] b) throws IOException
+    {
+        return read(b, 0, b.length);
+    }
+
+    public int read(final byte[] b, final int off, final int len) throws IOException
+    {
+
+        if(off < 0) {
+            throw new IllegalArgumentException("The offset must be positive. It was: " + off);
+        }
+        if(len < 0) {
+            throw new IllegalArgumentException("The length must be positive. It was: " + len);
+        }
+        if(off+len>b.length) {
+            throw new IllegalArgumentException("Lenght + offset must not be bigger than the array length.");
+        }
+        readingHasStarted = true;
+
+        printDebug("read() called with params: off:" + off + "  len:" + len);
+
+        Header header = null;
+
+        int read = 0;
+        if(unreadSample != null) {
+            int sampleLength = unreadSample.getBufferLength();
+            int sampleLengthInBytes = sampleLength * 2;
+            if(sampleLengthInBytes > len) {
+                printDebug("unreadSample too big. ");
+                return 0;
+            }            
+            toByteArray(unreadSample.getBuffer(), sampleLength, b, off);
+            printDebug("UNREAD SAMPLE just read.");
+            read += sampleLengthInBytes;
+            unreadSample = null;
+            bitstream.closeFrame();
+        }
+        try {
+            header = bitstream.readFrame();
+        } catch (BitstreamException e) {
+            throw new IOException(e.toString());
+        }
+        while (header != null) {
+
+            // decode the frame
+            SampleBuffer sample = null;
+            try {
+                sample = (SampleBuffer) decoder.decodeFrame(header, bitstream);
+            } catch (DecoderException e) {
+                throw new IOException(e.toString());
+            }
+
+            printDebug("Read: " + read);
+            int sampleLength = sample.getBufferLength();
+            int sampleLengthInBytes = sampleLength * 2;
+            printDebug("Buffer length: " + sampleLength);
+            if(read + (sampleLengthInBytes) > len) {
+                unreadSample = sample;
+                printDebug(" saving unreadSample for later.");
+                break;
+            }
+            toByteArray(sample.getBuffer(), sampleLength, b, off + read);
+            printDebug("Just read bytes: " + sampleLengthInBytes);
+            read += sampleLengthInBytes;
+            bitstream.closeFrame();
+            try {
+                header = bitstream.readFrame();
+            } catch (BitstreamException e) {
+                throw new IOException(e.toString());
+            }
+        }
+
+        return read;
+    }
+
+    final private void toByteArray(short[] samples, int len, byte[] b,  int off)
+    {
+        int shortIndex = 0;
+        short s;
+        while (len-- > 0) {
+            s = samples[shortIndex++];
+            b[off++] = (byte) s;
+            b[off++] = (byte) (s >>> 8);
+        }
+    }
+
+    public void reset() throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public long skip(long n) throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/Sound.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/Sound.java
new file mode 100644
index 0000000000000000000000000000000000000000..203b4b14b3f18d7270310436e212b0eea79ae922
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/Sound.java
@@ -0,0 +1,102 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+/**
+ * Interface for different types of sounds supported by Greenfoot.
+ * 
+ * @see SoundStream
+ * @see MidiFileSound
+ * @see SoundClip
+ * @author Poul Henriksen 
+ *
+ */
+public interface Sound
+{
+
+    /**
+     * Closes this sound. Will immediately release any resources for the sound.
+     */
+    public abstract void close();
+
+    /**
+     * Stop this sound. 
+     *
+     * After this method has been called: isStopped=true, isPlaying=false, isPaused=false.
+     */
+    public abstract void stop();
+
+    /**
+     * Pause the song. Paused sounds can be resumed.
+     *
+     * After this method has been called: isStopped=false, isPlaying=false, isPaused=true.
+     */
+    public abstract void pause();
+
+    /**
+     * Play this sound. 
+     * 
+     * After this method has been called and no exception occurs: isStopped=false, isPlaying=true, isPaused=false.
+     * If a problem occurs it should be: isStopped=true, isPlaying=false, isPaused=false.
+     * 
+     */
+    public abstract void play();
+
+    /**
+     * Plays this sound in a loop. 
+     * 
+     * After this method has been called and no exception occurs: isStopped=false, isPlaying=true, isPaused=false.
+     * If a problem occurs it should be: isStopped=true, isPlaying=false, isPaused=false.
+     * 
+     */
+    public abstract void loop();
+
+    /**
+     * True if the sound is currently playing.
+     * 
+     */
+    public abstract boolean isPlaying();
+
+    /**
+     * True if the sound is currently paused.
+     * 
+     */
+    public abstract boolean isPaused();
+
+    /**
+     * True if the sound is currently paused.
+     * 
+     */
+    public abstract boolean isStopped();
+
+    /**
+     * Set the sound volume.
+     * @param level the level between 0-100 of the sound.
+     */
+    public abstract void setVolume(int level);
+
+    /**
+     * Get the current volume of the sound.
+     * @return the sound volume, between 0-100.
+     */
+    public abstract int getVolume();
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundClip.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundClip.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8fdcb666a8ed96a513f4cfed716e4ced5e6a03a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundClip.java
@@ -0,0 +1,442 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.FloatControl;
+import javax.sound.sampled.LineEvent;
+import javax.sound.sampled.LineListener;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * Plays sound from a URL. The sound is loaded into memory the first time it is
+ * played.
+ * 
+ * @author Poul Henriksen
+ */
+public class SoundClip implements Sound, LineListener
+{
+    private static ClipCache clipCache = new ClipCache();
+    private static ClipProcessThread processThread = new ClipProcessThread();
+    private static ClipCloserThread closerThread = new ClipCloserThread();
+
+    /** URL of the sound data. */
+    private final URL url;
+    
+    /** Data for the clip (used for caching) */
+    private ClipData clipData;
+    
+    /**
+     * The clip that this SoundClip represents. Can be null (when state is
+     * CLOSED)
+     */
+    private Clip soundClip;
+
+    /** The states a clip can be in. */
+    private enum ClipState
+    {
+        STOPPED, PLAYING, PAUSED_LOOPING, PAUSED_PLAYING, CLOSED, LOOPING
+    };
+    
+    /** requested clip state */
+    private ClipState clipState = ClipState.CLOSED;
+    
+    /** actual state playing vs looping */
+    private ClipState currentState = ClipState.CLOSED;
+    
+    /**
+     * The master volume of the sound clip.
+     */
+    private int masterVolume = 100;
+    
+    /** Listener for state changes. */
+    private SoundPlaybackListener playbackListener;
+    private boolean resumedLoop;
+
+    /**
+     * Creates a new sound clip
+     */
+    public SoundClip(String name, URL url, SoundPlaybackListener listener)
+    {
+        this.url = url;
+        playbackListener = listener;
+    }
+
+    /**
+     * Load the sound file supplied by the parameter into this sound engine.
+     */
+    private boolean open()
+    {
+        try {
+            load();
+            soundClip.addLineListener(this);
+            return true;
+        }
+        catch (SecurityException e) {
+            SoundExceptionHandler.handleSecurityException(e, url.toString());
+        }
+        catch (IllegalArgumentException e) {
+            SoundExceptionHandler.handleIllegalArgumentException(e, url.toString());
+        }
+        catch (FileNotFoundException e) {
+            SoundExceptionHandler.handleFileNotFoundException(e, url.toString());
+        }
+        catch (IOException e) {
+            SoundExceptionHandler.handleIOException(e, url.toString());
+        }
+        catch (UnsupportedAudioFileException e) {
+            SoundExceptionHandler.handleUnsupportedAudioFileException(e,
+                    url.toString());
+        }
+        catch (LineUnavailableException e) {
+            SoundExceptionHandler.handleLineUnavailableException(e);
+        }
+        return false;
+    }
+
+    private void load() throws UnsupportedAudioFileException, IOException,
+            LineUnavailableException
+    {
+        clipData = clipCache.getCachedClip(url);
+        InputStream is = new ByteArrayInputStream(clipData.getBuffer());
+        AudioFormat format = clipData.getFormat();
+        AudioInputStream stream = new AudioInputStream(is, format, clipData.getLength());
+        DataLine.Info info = new DataLine.Info(Clip.class, format);
+
+        // getLine throws illegal argument exception if it can't find a line.
+        soundClip = (Clip) AudioSystem.getLine(info);
+        soundClip.open(stream);
+        
+        // Note we don't use soundClip.getMicrosecondLength() due to an IcedTea bug:
+        // http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=902
+        setVolume(masterVolume);
+    }
+    
+    /**
+     * Preloads the clip, by opening it.
+     */
+    public synchronized void preLoad()
+    {
+        //Ignore all exceptions when pre-loading
+        try
+        {
+            clipData = clipCache.getCachedClip(url);
+            clipCache.releaseClipData(clipData);
+        }
+        catch (IOException e) {
+            
+        }
+        catch (UnsupportedAudioFileException e) {
+            
+        }
+    }
+
+    /*
+     * @see greenfoot.sound.Sound#play()
+     */
+    @Override
+    public synchronized void play()
+    {
+        if (clipState == ClipState.PLAYING) {
+            return;
+        }
+        else if (soundClip == null) {
+            // Open the clip in another thread
+            processThread.addToQueue(this);
+            currentState = ClipState.STOPPED;
+        }
+        else if (isPaused()) {
+            soundClip.start();
+        }
+        else if (clipState == ClipState.LOOPING) {
+            soundClip.loop(0);
+        }
+        else {
+            // play from the start
+            soundClip.setFramePosition(0);
+            soundClip.loop(0);
+            soundClip.start();
+        }
+        setState(ClipState.PLAYING);
+        if (soundClip != null) {
+            currentState = ClipState.PLAYING;
+        }
+    }
+
+    /**
+     * Play this sound from the beginning of the sound and loop around when the
+     * end have been reached.
+     */
+    @Override
+    public synchronized void loop()
+    {
+        if (clipState == ClipState.LOOPING) {
+            return;
+        }
+        else if (soundClip == null) {
+            // Open the clip in another thread
+            processThread.addToQueue(this);
+            currentState = ClipState.STOPPED;
+        }
+        else if (isPaused()) {
+            soundClip.start();
+            resumedLoop = true; // loop explicitly from beginning
+        }
+        else if (clipState == ClipState.PLAYING) {
+            resumedLoop = true;
+        }
+        else {
+            // loop from the start
+            soundClip.setFramePosition(0);
+            soundClip.setLoopPoints(0, -1);
+            soundClip.loop(Clip.LOOP_CONTINUOUSLY);
+            soundClip.start();
+        }
+        setState(ClipState.LOOPING);
+        if (soundClip != null) {
+            currentState = ClipState.LOOPING;
+        }
+    }
+    
+    public void processState()
+    {
+        ClipState toState;
+
+        synchronized (this) {
+            toState = clipState;
+            if (clipState == ClipState.PLAYING) {
+                if (currentState != ClipState.PLAYING) {
+                    if (!open()) {
+                        return;
+                    }
+                    soundClip.start();
+                    currentState = ClipState.PLAYING;
+                }
+            }
+            else if (clipState == ClipState.LOOPING) {
+                if (currentState != ClipState.LOOPING) {
+                    if (!open()) {
+                        return;
+                    }
+                    soundClip.setFramePosition(0);
+                    soundClip.setLoopPoints(0, -1);
+                    soundClip.loop(Clip.LOOP_CONTINUOUSLY);
+                    resumedLoop = false;
+                    currentState = ClipState.LOOPING;
+                }
+            }
+            else if (isPaused() || clipState == ClipState.STOPPED) {
+                if (currentState == ClipState.PLAYING || currentState == ClipState.LOOPING) {
+                    currentState = clipState;
+                }
+                else {
+                    return; // prevent code below from executing
+                }
+            }
+        }
+        
+        if (toState == ClipState.STOPPED
+                || toState == ClipState.PAUSED_LOOPING
+                || toState == ClipState.PAUSED_PLAYING) {
+            // We have to do this outside of 'synchronized' - OpenJDK seems
+            // to callback the listener on a different thread, but nevertheless
+            // waits for it to return before returning from soundClip.stop() below,
+            // which means we'll get a deadlock if we're sync'd now.
+            // Also, stop() can take quite a while to execute on OpenJDK.
+            soundClip.stop();
+            if (toState == ClipState.STOPPED) {
+                soundClip.setMicrosecondPosition(0);
+            }
+        }
+    }
+    
+    /**
+     * Set the volume level for this sound.
+     * @param level the volume level.
+     */
+    @Override
+    public synchronized void setVolume(int level)
+    {
+        this.masterVolume = level;
+        if (soundClip != null) {
+            if (soundClip.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
+                FloatControl volume = (FloatControl) soundClip.getControl(FloatControl.Type.MASTER_GAIN);
+                volume.setValue(SoundUtils.convertMinMax(level, volume.getMinimum(), volume.getMaximum()));
+            }
+        }
+    }
+
+    /**
+     * Get the volume level.
+     * @return the volume level.
+     */
+    @Override
+    public synchronized int getVolume()
+    {
+        return masterVolume;
+    }
+
+    /**
+     * Stop this sound.
+     */
+    @Override
+    public synchronized void stop()
+    {
+        if (isStopped()) {
+            return;
+        }
+        setState(ClipState.STOPPED);
+        if (soundClip != null) {
+            processThread.addToQueue(this);
+        }
+    }
+
+    /**
+     * Closes this sound. It will release all the resources for this sound
+     * immediately.
+     */
+    @Override
+    public synchronized void close()
+    {
+        if (clipState != ClipState.CLOSED) {
+            if (soundClip != null) {
+                setVolume(0);
+                clipCache.releaseClipData(clipData);
+                closerThread.addClip(soundClip);
+                soundClip = null;
+            }
+            setState(ClipState.CLOSED);
+        }
+    }
+
+    /**
+     * Pause the clip. Paused sounds can be resumed.
+     */
+    @Override
+    public synchronized void pause()
+    {
+        resumedLoop = false;
+        if (soundClip == null) {
+            return;
+        }
+        if (clipState == ClipState.PLAYING) {
+            setState(ClipState.PAUSED_PLAYING);
+            processThread.addToQueue(this);
+        }
+        if (clipState == ClipState.LOOPING) {
+            setState(ClipState.PAUSED_LOOPING);
+            processThread.addToQueue(this);
+        }
+    }
+
+    private void setState(ClipState newState)
+    {
+        if (clipState != newState) {
+            clipState = newState;
+            switch (clipState) {
+                case PLAYING:
+                    playbackListener.playbackStarted(this);
+                    break;
+                case STOPPED:
+                    playbackListener.playbackStopped(this);
+                    break;
+                case PAUSED_LOOPING:
+                    playbackListener.playbackPaused(this);
+                    break;
+                case PAUSED_PLAYING:
+                    playbackListener.playbackPaused(this);
+                    break;
+                case LOOPING:
+                    playbackListener.playbackStarted(this);
+                    break;
+                case CLOSED:
+                    playbackListener.soundClosed(this);
+            }
+        }
+    }
+
+    /**
+     * True if the sound is currently playing.
+     */
+    @Override
+    public synchronized boolean isPlaying()
+    {
+        return clipState == ClipState.PLAYING || clipState == ClipState.LOOPING;
+    }
+
+    /**
+     * True if the sound is currently paused.
+     */
+    @Override
+    public synchronized boolean isPaused()
+    {
+        return clipState == ClipState.PAUSED_PLAYING || clipState == ClipState.PAUSED_LOOPING;
+    }
+
+    /**
+     * True if the sound is currently stopped.
+     */
+    @Override
+    public synchronized boolean isStopped()
+    {
+        return clipState == ClipState.STOPPED || clipState == ClipState.CLOSED;
+    }
+
+    @Override
+    public void update(LineEvent event)
+    {
+        if (event.getType() == LineEvent.Type.STOP) {
+            synchronized (this) {
+                if (resumedLoop && clipState == ClipState.LOOPING) {
+                    // Avoid restarting on this thread to avoid OpenJDK pulseaudio deadlock:
+                    processThread.addToQueue(this);
+                }
+                else if (! isPaused()) {
+                    setState(ClipState.STOPPED);
+                    // May have been restarted by a listener:
+                    if (clipState == ClipState.STOPPED && soundClip != null) {
+                        // If not, we'll close.
+                        closerThread.addClip(soundClip);
+                        soundClip = null;
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return url + " " + super.toString();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundCollection.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundCollection.java
new file mode 100644
index 0000000000000000000000000000000000000000..b424c22953c2d3826e56b46487dc57a3fa990fb1
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundCollection.java
@@ -0,0 +1,134 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import greenfoot.event.SimulationEvent;
+import greenfoot.event.SimulationListener;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Contains a collection of sounds that are currently open (playing or paused).
+ * 
+ * @author Poul Henriksen
+ */
+public class SoundCollection implements SimulationListener, SoundPlaybackListener
+{
+    /** Sounds currently playing or paused by this SoundCollection. */
+    private Set<Sound> playingSounds = new HashSet<Sound>();
+    
+    /** Sounds paused by the user code. */
+    private Set<Sound> pausedSounds = new HashSet<Sound>(); 
+    
+    /** Sounds closed by the user code. */
+    private Set<Sound> stoppedSounds = new HashSet<Sound>();     
+    
+    private volatile boolean ignoreEvents = false;
+    
+    /**
+     * Stop sounds when simulation is disabled (a new world is created).
+     */
+    public void simulationChanged(SimulationEvent e)
+    {
+        if (e.getType() == SimulationEvent.DISABLED) {
+            close();
+        }
+    }
+
+    /**
+     * Stops all sounds and makes them release the resources.
+     * 
+     */
+    private void close()
+    {    	
+        synchronized (this) {
+            ignoreEvents = true;
+        }
+        
+        Iterator<Sound> iter = playingSounds.iterator();
+        while (iter.hasNext() ) {
+            Sound sound = iter.next();
+            sound.close();
+        }
+        
+        iter = pausedSounds.iterator();
+        while (iter.hasNext() ) {
+            Sound sound = iter.next();
+            sound.close();
+        }
+        
+
+        iter = stoppedSounds.iterator();
+        while (iter.hasNext() ) {
+            Sound sound = iter.next();
+            sound.close();
+        }
+        
+        playingSounds.clear();
+        pausedSounds.clear();
+        stoppedSounds.clear();
+
+        synchronized (this) {
+            ignoreEvents = false;
+        }
+    }
+
+    // Listener callbacks
+
+    public synchronized void playbackStarted(Sound sound)
+    {
+        if (!ignoreEvents) {
+            playingSounds.add(sound);
+            pausedSounds.remove(sound);
+            stoppedSounds.remove(sound);
+        }
+    }
+
+    public synchronized void playbackStopped(Sound sound)
+    {       
+        if (!ignoreEvents) {
+            playingSounds.remove(sound);
+            pausedSounds.remove(sound);
+            stoppedSounds.add(sound);
+        }
+    }
+
+    public synchronized void playbackPaused(Sound sound)
+    {
+        if (!ignoreEvents) {
+            pausedSounds.add(sound);
+            playingSounds.remove(sound);
+            stoppedSounds.remove(sound);
+        }
+    }
+    
+    public synchronized void soundClosed(Sound sound) 
+    {
+        if (!ignoreEvents) {
+            pausedSounds.remove(sound);
+            playingSounds.remove(sound);
+            stoppedSounds.remove(sound);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundExceptionHandler.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundExceptionHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..44f8ab9dade22251b354ed05e2fc9471e945b1df
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundExceptionHandler.java
@@ -0,0 +1,116 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import greenfoot.core.WorldHandler;
+import greenfoot.util.GreenfootUtil;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import javax.sound.midi.InvalidMidiDataException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+import bluej.Config;
+
+/**
+ * This class should be forwarded some of the common sound exceptions. It keeps
+ * track of which type of exceptions has already been shown to the user, and
+ * makes sure not to repeatedly show the same exception which would otherwise be
+ * likely to happen. For instance, it is enough to tell the user once, if a
+ * soundcard can't be found, not every time a sound is attempted to be played.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class SoundExceptionHandler
+{
+    // Whether we have handled certain exceptions. We use these flags to ensure
+    // we only print an error message once to avoid flooding the error output.
+    private static volatile boolean lineUnavailableHandled;
+    private static volatile boolean illegalArgumentHandled;
+    private static volatile boolean securityHandled;
+    private static boolean mp3LibHandled;
+
+    public static void handleUnsupportedAudioFileException(UnsupportedAudioFileException e, String filename)
+    {
+        throw new IllegalArgumentException("Format of sound file not supported: " + filename, e);
+    }
+
+    public static void handleFileNotFoundException(FileNotFoundException e, String filename)
+    {
+        throw new IllegalArgumentException("Could not find sound file: " + filename, e);
+    }
+
+    public static void handleIOException(IOException e, String filename)
+    {
+        throw new IllegalArgumentException("Could not open sound file: " + filename, e);
+    }
+
+    public static void handleLineUnavailableException(Exception e)
+    {
+        // We only want to print this error message once.
+        if (!lineUnavailableHandled) {
+            lineUnavailableHandled = true;
+            String errMsg = Config.getString("sound-line-unavailable");
+            GreenfootUtil.displayMessage(WorldHandler.getInstance().getWorldCanvas(), errMsg);
+        }
+    }
+
+    public static void handleIllegalArgumentException(IllegalArgumentException e, String filename)
+    {
+        // We only want to print this error message once.
+        if (!illegalArgumentHandled) {
+            illegalArgumentHandled = true;
+            System.err.println("Could not play sound file: " + filename);
+            System.err.println("If you have a sound card installed, check your system settings.");
+            e.printStackTrace();
+        }
+    }
+
+    public static void handleSecurityException(SecurityException e, String filename)
+    {
+        // We only want to print this error message once.
+        if (!securityHandled) {
+            securityHandled = true;
+            System.err.println("Could not play sound file due to security restrictions: " + filename);
+            System.err.println("If you have a sound card installed, check your system settings.");
+            e.printStackTrace();
+        }
+    }
+
+    public static void handleInvalidMidiDataException(InvalidMidiDataException e, String filename)
+    {
+        throw new IllegalArgumentException("Invalid data in MIDI file: " + filename, e);
+    }
+
+    public static void handleMp3LibNotAvailable()
+    {
+        if (!mp3LibHandled) {
+            mp3LibHandled = true;
+            System.err.println("MP3 library not available." + " You will not be able to play any mp3 audio files."
+                    + " This is most likely happening because you are using a non-standard Greenfoot installation."
+                    + " To get the standard version, go to http://www.greenfoot.org");
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundFactory.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..258a85e37f79f873e886bd5a4d5f1fb3055a9e72
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundFactory.java
@@ -0,0 +1,148 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import greenfoot.util.GreenfootUtil;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * Class responsible for creating Sounds and loading them.
+ * 
+ * @author Poul Henriksen
+ */
+public class SoundFactory 
+{
+    /** singleton */
+    private static SoundFactory instance;    
+
+    /**
+     * Collection of all sounds, which can be used to affect the state of all
+     * sounds, for instance it can pause/resume all sounds.
+     */
+    private SoundCollection soundCollection;
+    
+    /**
+     * Only use clips when the size of the clip is below this value (size of the
+     * file in bytes). 
+     * TODO: make this user configurable for platforms where
+     * clips don't work so well. What about applets?
+     */
+    private static final int maxClipSize = 500 * 1000;
+
+    private SoundFactory()
+    {
+        soundCollection = new SoundCollection();
+        
+        for (String soundFile : GreenfootUtil.getSoundFiles())
+        {
+            // This loads the file, and if it's a SoundClip, puts it in
+            // the sound cache.  It also happens to make objects for
+            // non-SoundClip items, but since they are all streams,
+            // that shouldn't cause a big slowdown or waste of resources.
+            Sound s = createSound(soundFile, true);
+            
+            if (s instanceof SoundClip)
+                ((SoundClip)s).preLoad();
+            
+            // if (!soundCache.hasFreeSpace())
+            //    return; // No point continuing
+        }
+    }
+
+    public synchronized static SoundFactory getInstance()
+    {
+        if (instance == null) {
+            instance = new SoundFactory();
+        }
+        return instance;
+    }
+    
+    public SoundCollection getSoundCollection()
+    {
+        return soundCollection;
+    }
+   
+    /**
+     * Creates the sound from file.
+     * 
+     * @param file Name of a file or an url
+     * @param quiet   if true, failure is silent; otherwise an IllegalArgumentException may be thrown
+     * @throws IllegalArgumentException if the specified sound is invalid or cannot be played, unless quiet is true
+     * @return  a sound, or if quiet is true, possibly null
+     */
+    public Sound createSound(final String file, boolean quiet)
+    {      
+        try {
+            URL url = GreenfootUtil.getURL(file, "sounds");
+            int size = url.openConnection().getContentLength();
+            if (isMidi(url)) {
+                return new MidiFileSound(url, soundCollection);
+            }
+            else if(!GreenfootUtil.isMp3LibAvailable() && isMp3(url)) {
+                // This is an mp3 file but we don't have the mp3 library available.
+                SoundExceptionHandler.handleMp3LibNotAvailable();
+            }   
+            else if(isMp3(url)) {
+                return new SoundStream(new Mp3AudioInputStream(url), soundCollection);
+            }            
+            else if (isJavaAudioStream(size)) {
+                return new SoundStream(new JavaAudioInputStream(url), soundCollection);
+            } 
+            else {
+                // The sound is small enough to be loaded into memory as a clip.
+                return new SoundClip(file, url, soundCollection);
+            }
+        } catch (IOException e) {
+            if (! quiet) {
+                SoundExceptionHandler.handleIOException(e, file);
+            }
+        } catch (UnsupportedAudioFileException e) {
+            if (! quiet) {
+                SoundExceptionHandler.handleUnsupportedAudioFileException(e, file);
+            }
+        }  
+        return null;
+    }
+    
+    private boolean isJavaAudioStream(int size)
+    {
+        // If we can not get the size, or if it is a big file we stream
+        // it in a thread.
+        return size == -1 || size > maxClipSize;
+    }    
+
+    private boolean isMidi(URL url)
+    {
+        String lowerCaseName = url.toString().toLowerCase();
+        return lowerCaseName.endsWith("mid") || lowerCaseName.endsWith("midi");
+    }    
+
+    private boolean isMp3(URL url)
+    {
+        String lowerCaseName = url.toString().toLowerCase();
+        return lowerCaseName.endsWith("mp3");
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundPlaybackListener.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundPlaybackListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a2d8397c0ff45b07ba06e2767efe11c1421ddec
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundPlaybackListener.java
@@ -0,0 +1,35 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+/**
+ * Interface for listeners that wants to get notified when playback of a sound has started or stopped.
+ * 
+ * @author Poul Henriksen
+ */
+public interface SoundPlaybackListener
+{
+    public void playbackStarted(Sound sound);
+    public void playbackPaused(Sound sound);
+    public void playbackStopped(Sound sound);
+    public void soundClosed(Sound sound);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundRecorder.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundRecorder.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba7204db6ecee86145ec79f6b022275cb9f7265b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundRecorder.java
@@ -0,0 +1,231 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.TargetDataLine;
+
+import bluej.utility.Debug;
+
+/**
+ * A class that handles recording sound from the user's microphone.
+ * 
+ * @author neil
+ */
+public class SoundRecorder
+{
+    private AudioFormat format;
+    private AtomicBoolean keepRecording = new AtomicBoolean();
+    private TargetDataLine line;
+    private BlockingQueue<byte []> recordedResultQueue = new ArrayBlockingQueue<byte[]>(1);
+    private byte[] recorded;
+    
+    public SoundRecorder()
+    {
+        format = new AudioFormat(22050, 8, 1, true, true);
+    }
+
+    /**
+     * Starts recording.  You should make sure to call stop() exactly once after
+     * each call to start().
+     * 
+     * The method returns a reference from which you can pick out the current state
+     * of the recording. It will first be set to null, then to be a list with the first part of the recording,
+     * then a list with the first and second parts, then a list with the first, second
+     * and third parts.  This is the easiest way to control
+     * the concurrency involved in the sound recorder that reads from this list.
+     * The internal list is cloned in this method (which is therefore thread-safe), and
+     * thereafter the lists put in the reference can all be accessed individually
+     * without worrying about them being modified.  So any list got by a call to a get
+     * won't be being used again by this method.
+     * 
+     * The reference should be updated roughly every half-second.
+     * 
+     * When the recording has finished, null will be put into the reference.
+     */
+    public AtomicReference<List<byte[]>> startRecording()
+    {
+        try {
+            line = (TargetDataLine)AudioSystem.getLine(new DataLine.Info(TargetDataLine.class, format));
+            line.open();
+            if (!line.getFormat().equals(format))
+                Debug.message("Format is not as expected" + line.getFormat().toString());
+            line.start();
+            
+            keepRecording.set(true);
+            
+            final AtomicReference<List<byte[]>> partialResult = new AtomicReference<List<byte[]>>(null);
+                       
+            Runnable rec = new Runnable() {
+                public void run()
+                {
+                    // We should get a chunk every half second, which is better than every second
+                    // for updating the display as we go:
+                    int bufferSize = (int) (format.getSampleRate()/2) * format.getFrameSize();
+                    LinkedList<byte[]> frames = new LinkedList<byte[]>();
+                    
+                    while (keepRecording.get()) {
+                        byte buffer[] = new byte[bufferSize];
+                    
+                        int bytesRead = line.read(buffer, 0, bufferSize);
+                                           
+                        if (bytesRead != bufferSize) {
+                            keepRecording.set(false);
+                        } else {
+                            frames.addLast(buffer);
+                            partialResult.set(new LinkedList<byte[]>(frames));
+                        }
+                    }
+                    
+                    partialResult.set(null);
+                    
+                    line.stop();
+                    
+                    boolean done = false;
+                    while (!done) {
+                        try {
+                            recordedResultQueue.put(merge(frames));
+                            done = true;
+                        }
+                        catch (InterruptedException e) {
+                        }
+                    }
+                }
+            };
+            
+            new Thread(rec).start();
+            
+            return partialResult;
+        }
+        catch (LineUnavailableException e) {
+            Debug.reportError("Problem capturing sound", e);
+            return null;
+        }
+        
+    }
+
+    /**
+     * Stops recording.  Should be called exactly once for each call to start().
+     */
+    public void stopRecording()
+    {
+        keepRecording.set(false);
+        recorded = null;
+        while (recorded == null) {
+            try {
+                recorded = recordedResultQueue.take();
+            }
+            catch (InterruptedException e) {
+            }
+        }
+        line.close();
+    }
+    
+    /**
+     * Writes the most recent recording to the given file in WAV format
+     */
+    public void writeWAV(File destination)
+    {
+        ByteArrayInputStream baiStream = new ByteArrayInputStream(recorded);
+        AudioInputStream aiStream = new AudioInputStream(baiStream,format,recorded.length);
+        try {
+            AudioSystem.write(aiStream,AudioFileFormat.Type.WAVE,destination);
+            aiStream.close();
+            baiStream.close();
+        }
+        catch (IOException e) {
+            Debug.reportError("Problem writing recorded sound to WAV file", e);
+        }
+        
+
+    }
+    
+    /**
+     * Helper function to merge several arrays into one.
+     */
+    private static byte[] merge(List<byte[]> frames)
+    {
+        int totalLength = 0;
+        for (byte[] frame : frames) {
+            totalLength += frame.length;
+        }
+        
+        byte[] result = new byte[totalLength];
+        int curOffset = 0;
+        for (byte[] frame : frames) {
+            System.arraycopy(frame, 0, result, curOffset, frame.length);
+            curOffset += frame.length;
+        }
+        return result;
+            
+            
+    }
+
+    /**
+     * Gets the raw array of bytes representing the currently recorded sound
+     */
+    public byte[] getRawSound()
+    {
+        return recorded;
+    }
+    
+    /**
+     * Trims the current sound recording (if any) to the given offsets.
+     * 
+     * The offsets are given as floats in the range 0 to 1.
+     */
+    public void trim(float begin, float end)
+    {
+        if (recorded != null)
+        {
+            float length = recorded.length;
+            int beginIndex = (int)(begin * length);
+            int endIndex = (int)(end * length);
+            
+            recorded = Arrays.copyOfRange(recorded, beginIndex, endIndex);
+        }
+    }
+
+    /**
+     * Gets the format that was used to record the sound.
+     */
+    public AudioFormat getFormat()
+    {
+        return format;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundStream.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..60ff3a661b782ab6f3dcb4bccd41f655b15e253c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundStream.java
@@ -0,0 +1,469 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import java.io.IOException;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.SourceDataLine;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import javax.sound.sampled.DataLine.Info;
+
+import bluej.utility.Debug;
+
+/**
+ * Plays sound from a URL. To avoid loading the entire sound clip into memory,
+ * the sound is streamed. The sound can either be a standard sound supported by
+ * the core Java libraries or an MP3.
+ * 
+ * @see Mp3AudioInputStream
+ * @see JavaAudioInputStream
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class SoundStream implements Sound, Runnable
+{
+    private static void printDebug(String s)
+    {
+        // Comment this line out if you don't want debug info.
+        // System.out.println(s);
+    }
+    /**
+     * How long to wait until closing the line and stopping the playback thread
+     * after playback has finished. In ms.
+     */
+    private static final int CLOSE_TIMEOUT = 1000;
+    /**
+     * Signals that the sound should loop.
+     */
+    private boolean loop = false;
+    /**
+     * Signals that the playback should stop. 
+     */
+    private boolean stop = true;
+    /**
+     * Signals that the playback should pause.
+     */
+    private boolean pause = false;
+    /** Signals that playback should start over from the beginning. */
+    private boolean restart = false;
+    /**
+     * Flag that indicates whether the sound is currently stopped (not playing
+     * or paused). Almost the same as the stop signal, except that this flag
+     * will be set to false when the end of the input has been reached.
+     */
+    private boolean stopped = true;
+    /**
+     * Stream where data is read from. This stream should only be accessed from
+     * the playThread.
+     */
+    private final GreenfootAudioInputStream inputStream;
+    /** Listener for state changes. */
+    private final SoundPlaybackListener playbackListener;
+    /** The line that we play the sound through */
+    private volatile AudioLine line;
+    private AudioFormat format;
+    private Info info;
+    /** Thread that handles the actual playback of the sound. */
+    private Thread playThread;
+
+    public SoundStream(GreenfootAudioInputStream inputStream, SoundPlaybackListener playbackListener)
+    {
+        this.playbackListener = playbackListener;
+        this.inputStream = inputStream;
+        try {
+            // Preparing the line here, speeds up the first playback of the
+            // sound.
+            format = inputStream.getFormat();
+            info = new DataLine.Info(SourceDataLine.class, format);
+            line = initialiseLine(info, format);
+        }
+        catch (IllegalArgumentException e) {
+            // Thrown by getLine()
+            SoundExceptionHandler.handleIllegalArgumentException(e, inputStream.getSource());
+        }
+        catch (LineUnavailableException e) {
+            SoundExceptionHandler.handleLineUnavailableException(e);
+        }
+    }
+
+    @Override
+    public synchronized void play()
+    {
+        if (isPlaying()) {
+            // Make sure we no longer loop.
+            loop = false;
+        }
+        else {
+            // We are not playing, so we should start playing.
+            startPlayback();
+        }
+    }
+
+    @Override
+    public synchronized void loop()
+    {
+        // Make sure we loop.
+        loop = true;
+        if (!isPlaying()) {
+            // We are not playing, so we should start playing.
+            startPlayback();
+        }
+    }
+
+    /**
+     * Starts playback by creating the thread if necessary, clearing the
+     * stop, stopped, and pause flags and notifying listeners.
+     */
+    private void startPlayback()
+    {
+        if (!pause) {
+            restart = true;
+            if (playThread == null) {
+                printDebug("Starting new playthread");
+                playThread = new Thread(this, "SoundStream:" + inputStream.getSource());
+                playThread.start();
+            }
+            if (line != null) {
+                line.reset();
+            }
+        }
+        stopped = false;
+        pause = false;
+        stop = false;
+        if (line != null) {
+            line.start();
+        }
+        notifyAll();
+        playbackListener.playbackStarted(this);
+    }
+
+    @Override
+    public synchronized void close()
+    {
+        if (line != null) {
+            reset();
+            line.close();
+            notifyAll();
+            playbackListener.playbackStopped(this);
+        }
+    }
+
+    @Override
+    public synchronized void stop()
+    {
+        if (!stop) {
+            stop = true;
+            stopped = true;
+            pause = false;
+            line.reset();
+            notifyAll();
+            playbackListener.playbackStopped(this);
+        }
+    }
+
+    @Override
+    public synchronized void pause()
+    {
+        if (!stopped && !pause) {
+            line.stop();
+            pause = true;
+            notifyAll();
+            playbackListener.playbackPaused(this);
+        }
+    }
+
+    @Override
+    public synchronized boolean isPlaying()
+    {
+        return !stopped && !pause;
+    }
+
+    @Override
+    public synchronized boolean isStopped()
+    {
+        return stopped && !pause;
+    }
+
+    @Override
+    public synchronized boolean isPaused()
+    {
+        return pause;
+    }
+
+    @Override
+    public String toString()
+    {
+        return inputStream.getSource() + " " + super.toString();
+    }
+
+    @Override
+    public void run()
+    {
+        // Whether the thread should stay alive or die.
+        boolean stayAlive = true;
+
+        try {
+            while (stayAlive) {
+                inputStream.restart();
+                synchronized (this) {
+                    if (line == null || !format.matches(inputStream.getFormat())) {
+                        // If we don't have a line or the format has changed we
+                        // need a new line.
+                        format = inputStream.getFormat();
+                        info = new DataLine.Info(SourceDataLine.class, format);
+                        line = initialiseLine(info, format);
+                    }
+                    line.open();
+                    restart = false;
+                }
+
+                int frameSize = format.getFrameSize();
+                int bufferSize = SoundUtils.getBufferSizeToHold(format, 0.5);
+                if (bufferSize == -1) {
+                    bufferSize = 64 * 1024;
+                }
+
+                byte[] buffer = new byte[bufferSize];
+
+                printDebug("Stream available (in bytes): " + inputStream.available() + " in frames: "
+                        + inputStream.available() / frameSize);
+
+                int bytesRead = inputStream.read(buffer, 0, bufferSize);
+                int bytesInBuffer = bytesRead;
+                printDebug(" read: " + bytesRead);
+                while (bytesInBuffer > 0) {
+                    // Only write in multiples of frameSize
+                    int bytesToWrite = (bytesInBuffer / frameSize) * frameSize;
+
+                    synchronized (this) {
+                        // Handle stop
+                        if (stop) {
+                            break;
+                        }
+
+                        // Handle pause
+                        if (pause) {
+                            doPause();
+                        }
+
+                        // Handle restart
+                        if (restart) {
+                            printDebug("restart in thread");
+                            line.reset();
+                            inputStream.restart();
+                            restart = false;
+                            bytesInBuffer = 0;
+                            bytesRead = 0;
+                            bytesToWrite = 0;
+                            printDebug("inputStream available after restart in thread: " + inputStream.available());
+                        }
+                    }
+                    // Play it
+                    int written = line.write(buffer, 0, bytesToWrite);
+
+                    printDebug(" wrote: " + written);
+
+                    // Copy remaining bytes (if we wrote less than what is in
+                    // the buffer)
+                    int remaining = bytesInBuffer - written;
+                    if (remaining > 0) {
+                        printDebug("remaining: " + remaining + "  written: " + written + "   bytesInBuffer: "
+                                + bytesInBuffer + "   bytesToWrite: " + bytesToWrite);
+                        System.arraycopy(buffer, written, buffer, 0, remaining);
+                    }
+                    bytesInBuffer = remaining;
+
+                    printDebug("remaining: " + remaining + "  written: " + written + "   bytesInBuffer: "
+                            + bytesInBuffer + "   bytesToWrite: " + bytesToWrite);
+                    bytesRead = inputStream.read(buffer, bytesInBuffer, buffer.length - bytesInBuffer);
+                    if (bytesRead != -1) {
+                        bytesInBuffer += bytesRead;
+                    }
+                    printDebug(" read: " + bytesRead);
+                }
+
+                line.drain();
+
+                synchronized (this) {
+
+                    // NOTE: If the size of the stream is a multiple of 64k (=
+                    // 16k frames) then it plays the last 64k twice if I don't
+                    // stop it here.
+                    // It still has a strange clicking sound at the end, which
+                    // is probably because it starts playing a bit of the extra,
+                    // but is stopped before it finishes.
+                    // To make this more explicit, add a delay before
+                    // line.reset.
+                    // For example 4d.wav from piano scenario. Happens on my
+                    // macbook and Ubuntu in the office. Poul.
+
+                    if (!loop || stop) {
+                        line.reset();
+                    }
+
+                    if ((!restart && !loop) || stop) {
+                        stopped = true;
+                        playbackListener.playbackStopped(this);
+                        // Have a short pause before we get rid of the
+                        // thread, in case the sound is played again soon
+                        // after.
+                        try {
+                            if (line.isOpen()) {
+                                printDebug("WAIT");
+                                wait(CLOSE_TIMEOUT);
+                            }
+                        }
+                        catch (InterruptedException e) {
+                        }
+                        // Kill thread if we have not received a signal to
+                        // continue playback.
+                        if ((!restart && !loop) || stop) {
+                            line.close();
+                            stayAlive = false;
+                            reset();
+                            printDebug("KILL THREAD");
+                        }
+                    }
+
+                    printDebug(" 2 restart =  " + restart + "  stop = " + stop);
+
+                    // If a restart was signalled, remove the signal and
+                    // just continue.
+                    if (restart) {
+                        restart = false;
+                    }
+                }
+
+            }
+        }
+        catch (IllegalArgumentException e) {
+            // Thrown by getLine()
+            SoundExceptionHandler.handleIllegalArgumentException(e, inputStream.getSource());
+        }
+        catch (UnsupportedAudioFileException e) {
+            SoundExceptionHandler.handleUnsupportedAudioFileException(e, inputStream.getSource());
+        }
+        catch (LineUnavailableException e) {
+            SoundExceptionHandler.handleLineUnavailableException(e);
+        }
+        catch (IOException e) {
+            SoundExceptionHandler.handleIOException(e, inputStream.getSource());
+        }
+        finally {
+            if (stayAlive == true) {
+                // Abnormal termination, lets reset:
+                reset();
+            }
+            if (line != null) {
+                line.close();
+            }
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                }
+                catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            playbackListener.soundClosed(this);
+        }
+    }
+
+    /**
+     * Pauses as long as the pause signal is true.
+     */
+    private synchronized void doPause()
+    {
+        if (pause) {
+            while (pause) {
+                try {
+                    printDebug("In pause loop");
+                    line.stop();
+                    printDebug("In pause loop 2");
+                    wait();
+                }
+                catch (InterruptedException e) {
+                    Debug.reportError(
+                            "Interrupted while pausing sound: " + inputStream.getSource(), e);
+                }
+            }
+            line.start();
+        }
+    }
+
+    /**
+     * Initialise the line by creating it and setting up listeners.
+     * 
+     * @param info
+     * @throws LineUnavailableException
+     *             if a matching line is not available due to resource
+     *             restrictions
+     * @throws SecurityException
+     *             if a matching line is not available due to security
+     *             restrictions
+     * @throws IllegalArgumentException
+     *             if the system does not support at least one line matching the
+     *             specified
+     */
+    private AudioLine initialiseLine(DataLine.Info info, AudioFormat format)
+            throws LineUnavailableException, IllegalArgumentException
+    {
+        //Throws IllegalArgumentException if it can't find a line
+        SourceDataLine l = (SourceDataLine) AudioSystem.getLine(info);
+        printDebug("buffer size: " + l.getBufferSize());
+        return new AudioLine(l, format);
+    }
+
+    /**
+     * Stops the thread and reset all flags and signals to initial values.
+     */
+    private synchronized void reset()
+    {
+        stopped = true;
+        pause = false;
+        loop = false;
+        stop = true;
+        playThread = null;
+    }
+
+    public long getLongFramePosition()
+    {
+        return line.getLongFramePosition();
+    }
+
+    @Override
+    public void setVolume(int level)
+    {
+        line.setVolume(SoundUtils.logToLin(level));
+    }
+
+    @Override
+    public int getVolume()
+    {
+        return line.getVolume();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundUtils.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..63b199756962036d0fe7130c7f3ffe2193b7e8f2
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/SoundUtils.java
@@ -0,0 +1,105 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioSystem;
+
+public class SoundUtils
+{
+
+    /**
+     * Convert an integer value between 0-100 between the specified floating
+     * point values.
+     * @param val the value to convert.
+     * @param min the minimum floating point value.
+     * @param max the maximum floating point value.
+     * @return a float between the two values assuming val is between 0-100.
+     */
+    public static float convertMinMax(int val, float min, float max)
+    {
+        float range = max - min;
+        float newVal = val / (100 / range);
+        return newVal + min;
+    }
+
+    /**
+     * Convert a value on a logarithmic scale between 0-100 to a linear scale
+     * in the same range.
+     * @param level the logarithmic level.
+     * @return the linear level.
+     */
+    public static int logToLin(int level) {
+        return (int) ((Math.log(level) / Math.log(100)) * 100);
+    }
+
+    /**
+     * Calculate how long it will take to play the given number of bytes.
+     * 
+     * @param bytes Number of bytes.
+     * @param format The format used to play the bytes.
+     * @return time in ms or -1 if it could not be calculated.
+     */
+    public static long getTimeToPlayBytes(long bytes, AudioFormat format)
+    {
+        return getTimeToPlayFrames(bytes / format.getFrameSize(), format);
+    }
+
+    /**
+     * Calculate how long it will take to play the given number of frames.
+     * 
+     * @param bytes Number of bytes.
+     * @param format The format used to play the bytes.
+     * @return time in ms or -1 if it could not be calculated.
+     */
+    public static long getTimeToPlayFrames(long frames, AudioFormat format)
+    {
+        if (format.getFrameRate() != AudioSystem.NOT_SPECIFIED) {
+            return (long) (1000 * frames / format.getFrameRate());
+        }
+        else {
+            return -1;
+        }
+    }
+
+    /**
+     * Will attempt to calculate a buffer size that can hold the given time of
+     * audio data. If unsuccessful it will return -1.
+     * 
+     * @return size in bytes.
+     */
+    public static int getBufferSizeToHold(AudioFormat format, double seconds)
+    {
+        int bufferSize;
+        if (format.getFrameRate() != AudioSystem.NOT_SPECIFIED) {
+            bufferSize = (int) Math.ceil(format.getFrameSize() * format.getFrameRate() * seconds);
+        }
+        else if (format.getSampleRate() != AudioSystem.NOT_SPECIFIED) {
+            bufferSize = (int) Math.ceil((format.getSampleSizeInBits() / 8) * format.getChannels()
+                    * format.getSampleRate() * seconds);
+        }
+        else {
+            bufferSize = -1;
+        }
+        return bufferSize;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/TimeTracker.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/TimeTracker.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f3dd5ce4b78b8dce6430911aca3691ff7de287f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/sound/TimeTracker.java
@@ -0,0 +1,93 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.sound;
+
+/**
+ * A controllable timer, keeps track of time since a mark.
+ */
+public class TimeTracker 
+{
+    private long startTime;
+    private boolean tracking;
+    private long timeElapsed;
+    
+    public void start() 
+    {
+        if(tracking) {
+            return;
+        }
+        startTime = System.currentTimeMillis();    
+        tracking = true;
+    }
+    
+    public void pause()
+    {
+        if(!tracking) {
+            return;
+        }
+        long timeSincestart = getTimeSinceStart();
+        timeElapsed += timeSincestart;
+        tracking = false;
+    }
+
+    /**
+     * Reset time to 0 and stop the timer.
+     */
+    public void reset()
+    {
+        startTime = 0;
+        tracking = false;
+        timeElapsed = 0;
+    }
+    
+    private long getTimeSinceStart()
+    {
+        if(tracking) {
+            return System.currentTimeMillis() - startTime;
+        }
+        else {
+            return 0;
+        }
+    }
+    
+    /**
+     * Get the time tracked, in milliseconds, since the mark.
+     */
+    public long getTimeTracked()
+    {
+        return timeElapsed + getTimeSinceStart();
+    }
+    
+    /**
+     * Reset the time tracked to the given time. The time tracked continues
+     * to count up if the TimeTracker is started.
+     */
+    public void setTimeTracked(long newTime) 
+    {
+        if(tracking) {
+            startTime = System.currentTimeMillis() - newTime;
+            timeElapsed = 0;
+        } else {
+            timeElapsed = newTime;
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Circle.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Circle.java
new file mode 100644
index 0000000000000000000000000000000000000000..c296e1f7f95c5261dde0649b8fc4aee2f13c873d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Circle.java
@@ -0,0 +1,220 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+
+/**
+ * 
+ * Representation of a circle.
+ * 
+ * @author Poul Henriksen
+ *
+ */
+public class Circle
+{
+    private int x;
+    private int y;
+    private int radius;
+    
+    public Circle(int x, int y, int r) {
+        if(r < 0 ) {
+            throw new IllegalArgumentException("Radius must be larger than -1. It was: " + r);
+        }
+        this.setX(x);
+        this.setY(y);
+        setRadius(r);
+    }
+    
+    public Circle() {
+        
+    }
+
+    public boolean equals(Object other)
+    {
+        if (other instanceof Circle) {
+            Circle oCircle = (Circle) other;
+            return oCircle.x == x && oCircle.y == y && oCircle.radius == radius;
+        }
+        return false;
+    }
+    
+    public int hashCode()
+    {
+        int result = 17;
+        result = 37 * result + x;
+        result = 37 * result + y;
+        result = 37 * result + radius;
+        return result;
+    }
+    
+    public double getVolume()
+    {
+        return Math.PI * radius * radius;
+    }
+
+    public void setX(int x)
+    {
+        this.x = x;
+    }
+
+    public int getX()
+    {
+        return x;
+    }
+
+    public void setY(int y)
+    {
+        this.y = y;
+    }
+
+    public int getY()
+    {
+        return y;
+    }
+
+    public void setRadius(int radius)
+    {
+        this.radius = radius;
+    }
+
+    public int getRadius()
+    {
+        return radius;
+    }
+
+    /**
+     * Checks if this circles intersects the other circle.
+     */
+    public boolean intersects(Circle other)
+    {
+        int r1 = getRadius();
+        int r2 = other.getRadius();
+                    
+        int dx = getX() - other.getX();
+        int dy = getY() - other.getY();
+        int dxSq = dx * dx;
+        int dySq = dy * dy;
+        
+        int  circleDistSq = (dxSq + dySq);
+        
+        if( (r1 + r2) * (r1 + r2) >= circleDistSq) {
+            return true;
+        } else {
+            return false;
+        }            
+    }
+
+    /**
+     * Calculates the circle that bounds this circle and the other.
+     * 
+     * @return An new circle bounding this and other.
+     */
+ /*   public Circle merge(Circle other)
+    {
+        Circle mCircle = new Circle();
+        mCircle.merge(this, other);
+       if(true)
+           return mCircle;
+    
+        
+        int dx = getX() - other.getX();
+        int dy = getY() - other.getY();
+        int dxSq = dx * dx;
+        int dySq = dy * dy;        
+        int circleDistSq = (dxSq + dySq);
+        int r2 = (getRadius() - other.getRadius());
+        
+
+        Circle newCircle = null;
+        //check if r1 encloses r2
+        if( r2*r2 >= circleDistSq) {
+            if(getRadius() < other.getRadius()) {
+                newCircle= new Circle(other.getX(), other.getY(), other.getRadius());
+            } else {
+                newCircle = new Circle(x, y, radius);
+            } 
+        } else {        
+            double circleDist =  Math.sqrt(circleDistSq);
+            double r =  (circleDist + getRadius() + other.getRadius()) / 2.;
+            
+            newCircle = new Circle(getX(), getY(), (int) Math.ceil(r));
+            if(circleDist > 0) {
+                double f = ((r - getRadius()) / circleDist);                
+                
+                newCircle.setX(newCircle.getX() - ((int) Math.ceil(f * dx)));
+                newCircle.setY(newCircle.getY() - ((int) Math.ceil(f * dy)));
+            }            
+        }
+        System.out.println(newCircle);
+        System.out.println(mCircle);
+        System.out.println("----------");
+        return newCircle;
+    }    
+    */
+    /**
+     * Calculates the circle that bounds this circle and the other.
+     * 
+     */
+    public void merge(Circle one, Circle two)
+    {
+        int dx = one.getX() - two.getX();
+        int dy = one.getY() - two.getY();
+        int dxSq = dx * dx;
+        int dySq = dy * dy;        
+        int circleDistSq = (dxSq + dySq);
+        int r2 = (one.getRadius() - two.getRadius());
+        
+        //check if r1 encloses r2
+        if( r2*r2 >= circleDistSq) {
+            if(one.getRadius() < two.getRadius()) {
+                setRadius(two.getRadius());
+                setX(two.getX());
+                setY(two.getY());
+                //biggest = new Circle(two.getX(), two.getY(), two.getRadius());
+            } else {
+                setRadius(one.getRadius());
+                setX(one.getX());
+                setY(one.getY());
+                //biggest = new Circle(x, y, radius);
+            } 
+        }
+        else {
+            double circleDist = Math.sqrt(circleDistSq);
+            double r = (circleDist + one.getRadius() + two.getRadius()) / 2.;
+            // Circle newCircle = new Circle(getX(), getY(), (int)
+            // Math.ceil(r));
+            setRadius((int) Math.ceil(r));
+            if (circleDist > 0) {
+                double f = ((r - one.getRadius()) / circleDist);
+                setX(one.getX() - ((int) Math.ceil(f * dx)));
+                setY(one.getY() - ((int) Math.ceil(f * dy)));
+            } else {
+                setX(one.getX());
+                setY(one.getY());
+            }
+        }
+    }
+    
+    public String toString() {
+        return "(" + x + "," + y + ") [" + radius +"]" + super.toString();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/DebugUtil.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/DebugUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b3e291fb6bad1cbf5395dfabfcb596d6fcb6007
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/DebugUtil.java
@@ -0,0 +1,78 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+import greenfoot.Actor;
+import greenfoot.World;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * This class has some helper methods for the debugger in Greenfoot; 
+ * currently, this is information on what fields to hide/show
+ * when looking at objects (via the inspector or debugger).
+ * 
+ * This can be used to hide fields from Actor and World when looking at subclasses of them.
+ *
+ */
+public class DebugUtil
+{
+    public static Map<Class<?>, List<String>> restrictedClasses()
+    {
+        return restricted;
+    }
+    
+    /**
+     * As restrictedClasses, but uses Strings (fully qualified class names)
+     * as the keys rather than Class objects.
+     */
+    public static Map<String, Set<String>> restrictedClassesAsNames()
+    {
+        return restrictedAsNames;
+    }
+    
+    private static final String[] actorIncludeFields = new String[]{"x", "y", "rotation", "image", "world"};
+    private static final String[] worldIncludeFields = new String[]{"width", "height", "cellSize", "backgroundImage"};
+    
+    // Make these static to avoid reallocating the map every time it is asked for:
+    private static final HashMap<Class<?>, List<String>> restricted;
+    private static final HashMap<String, Set<String>> restrictedAsNames;
+    static 
+    {
+        restricted = new HashMap<Class<?>, List<String>>();
+        restricted.put(Actor.class, Arrays.asList(actorIncludeFields));
+        restricted.put(World.class, Arrays.asList(worldIncludeFields));
+        
+        restrictedAsNames = new HashMap<String, Set<String>>();
+        for (Entry<Class<?>, List<String>> e : restricted.entrySet()) {
+            HashSet<String> values = new HashSet<String>();
+            values.addAll(e.getValue());
+            restrictedAsNames.put(e.getKey().getName(), values);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/ExternalAppLauncher.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/ExternalAppLauncher.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c48ade13264b335fb1fd80ca4cae55fa774a07a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/ExternalAppLauncher.java
@@ -0,0 +1,209 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.awt.Desktop;
+
+import bluej.Config;
+import bluej.utility.Debug;
+
+/**
+ * A class containing static methods for the purposes of launching external
+ * programs. This will probably primarily be used for the editing of media
+ * files, i.e. image and sound editing.
+ * 
+ * @author Michael Berry (mjrb4)
+ * @version 18/05/09
+ */
+public class ExternalAppLauncher
+{
+    private static String imageEditor = Config.getPropString("greenfoot.editor.image", null);
+
+    /**
+     * Opens a file using the OS default program for that file type.
+     * 
+     * @param file the file to open.
+     */
+    public static void openFile(File file)
+    {
+        try {
+            if (Desktop.isDesktopSupported()) {
+                Desktop desktop = Desktop.getDesktop();
+                desktop.open(file);
+            }
+            else {
+                throw new RuntimeException(
+                        "Cannot open editor for the file, because the Desktop class is not supported on this platform.");
+            }
+        }
+        catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * Opens an image for editing using the OS default editor for that file
+     * type. Only difference from editFile is that this method uses a specific
+     * override for images as specified in greenfoot.defs.
+     * 
+     * @param file the file to open for editing.
+     */
+    public static void editImage(File file)
+    {
+        boolean success = false;
+        if (imageEditor != null) {
+            success = launchProgram(new File(imageEditor), file.toString());
+            if(!success) {
+                System.err.println("Could not launch the external program: " + imageEditor);
+            } 
+        }
+        if(!success) {
+            editFile(file);
+        }
+    }
+
+    /**
+     * Opens a file for editing using the OS default editor for that file type.
+     * 
+     * @param file the file to open for editing.
+     */
+    private static void editFile(File file)
+    {
+        try {
+            if (Desktop.isDesktopSupported()) {
+                Desktop desktop = Desktop.getDesktop();
+                if (desktop.isSupported(Desktop.Action.EDIT)) {
+                    desktop.edit(file);
+                } else {
+                    // They're probably on Linux; let's take our best guess
+                    // and use GIMP:
+                    Runtime.getRuntime().exec(new String []{"gimp", file.getAbsolutePath()}, null, null);
+                }
+            }
+            else {
+                throw new RuntimeException(
+                        "Cannot open editor for the file, because the Desktop class is not supported on this platform.");
+            }
+        }
+        catch (Exception ex) {
+            Debug.reportError("Error editing image", ex);
+        }
+    }
+
+    /**
+     * Launch an external application with a single parameter. This is usually
+     * the file that the application should open.
+     * 
+     * @param path the path of the application to launch.
+     * @param file the file to open in the application.
+     */
+    public static boolean launchProgram(File program, String file)
+    {
+        if (Config.isMacOS() && program.isDirectory()) {
+            // If we are on a mac, and the program is a directory, we should use
+            // the 'open' command.
+            String[] cmd = new String[4];
+            cmd[0] = "open";
+            cmd[1] = "-a";
+            cmd[2] = program.toString();
+            cmd[3] = file;
+            try {
+                execWithOutput(cmd);
+                return true;
+            }
+            catch (IOException ex) {
+                ex.printStackTrace();
+            }
+        }
+        else if (program.canExecute()) {
+            String[] cmd = new String[2];
+            cmd[0] = program.toString();
+            cmd[1] = file;
+            try {
+                execWithOutput(cmd);
+                return true;
+            }
+            catch (IOException ex) {
+                ex.printStackTrace();
+            }
+        }
+        return false;    
+        
+    }
+
+    /**
+     * Use Runtime.getRuntime().exec to execute the given command and redirect
+     * the output from the process to System.out and errors to System.err.
+     * 
+     */
+    private static void execWithOutput(String[] cmd)
+        throws IOException
+    {
+        Process p = Runtime.getRuntime().exec(cmd);
+        StreamRedirector errRedirector = new StreamRedirector(p.getErrorStream(), System.err);
+        errRedirector.start();
+        StreamRedirector outRedirector = new StreamRedirector(p.getInputStream(), System.out);
+        outRedirector.start();
+    }
+
+    /**
+     * Class that redirects from an inputstream to an outputstream.
+     * 
+     * @author Poul Henriksen
+     */
+    private static class StreamRedirector extends Thread
+    {
+        private OutputStream target;
+        private InputStream source;
+
+        public StreamRedirector(InputStream source, OutputStream target)
+        {
+            this.source = source;
+            this.target = target;
+        }
+
+        public void run()
+        {
+            int len = 0;
+            while (len != -1) {
+                // CharBuffer target = CharBuffer.allocate(20);
+                byte[] bytes = new byte[50];
+                try {
+                    len = source.read(bytes);
+                    if (len != -1) {
+                        target.write(bytes, 0, len);
+                        target.flush();
+                    }
+                }
+                catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/FileChoosers.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/FileChoosers.java
new file mode 100644
index 0000000000000000000000000000000000000000..dcab391c6b6c47897e3fb031581fb4984f3031ca
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/FileChoosers.java
@@ -0,0 +1,86 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+import bluej.Config;
+import java.awt.Component;
+import java.io.File;
+
+
+import javax.swing.JFileChooser;
+
+import bluej.prefmgr.PrefMgr;
+import bluej.utility.PackageChooserStrict;
+
+/**
+ * Class that holds different file choosers that can be used to select files or directories. 
+ * 
+ * @author Poul Henriksen
+ *
+ */
+public class FileChoosers
+{
+    private static JFileChooser  scenarioFileChooser;
+    private static JFileChooser  newFileChooser;
+    
+    /**
+     * Let the user specify a new file name.
+     * 
+     *  @return Returns a File pointing to the chosen file or directory, or null if none selected.
+     */
+    public static File getFileName(Component parent, File defaultFile, String title) {
+        if (newFileChooser == null) {
+            newFileChooser = new JFileChooser();
+            newFileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
+        }
+        newFileChooser.setDialogTitle(title);
+        newFileChooser.setSelectedFile(defaultFile);
+        int result = newFileChooser.showDialog(parent, Config.getString("chooser.newFile.button"));
+        
+        if (result != JFileChooser.APPROVE_OPTION) {
+           return null;
+        }
+        return newFileChooser.getSelectedFile();
+    }
+    
+    /**
+     * Select a Greenfoot scenario by using a file chooser, i.e. a file chooser which
+     * recognises Greenfoot packages and treats them differently.
+     * 
+     * @return Returns a File pointing to the scenario directory, or null if none selected.
+     */
+    public static File getScenario(Component parent)
+    {
+        if(scenarioFileChooser == null) {
+            scenarioFileChooser = new PackageChooserStrict(new File(PrefMgr.getProjectDirectory()));
+            scenarioFileChooser.setDialogTitle(Config.getString("chooser.scenario.title"));
+        }
+        int result = scenarioFileChooser.showDialog(parent, Config.getString("chooser.scenario.button"));
+        
+        if (result != JFileChooser.APPROVE_OPTION) {
+           return null;
+        }
+        PrefMgr.setProjectDirectory(scenarioFileChooser.getSelectedFile().getParentFile().getPath());
+        
+        return scenarioFileChooser.getSelectedFile();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/GraphicsUtilities.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/GraphicsUtilities.java
new file mode 100644
index 0000000000000000000000000000000000000000..b564318005675c2a36c847101ba1c8dd44904f3e
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/GraphicsUtilities.java
@@ -0,0 +1,632 @@
+package greenfoot.util;
+/*
+ * Copyright (c) 2007, Romain Guy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of the TimingFramework project nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.awt.GraphicsConfiguration;
+import java.awt.Transparency;
+import java.awt.Graphics;
+import java.awt.GraphicsEnvironment;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.net.URL;
+import javax.imageio.ImageIO;
+
+/**
+ * <p><code>GraphicsUtilities</code> contains a set of tools to perform
+ * common graphics operations easily. These operations are divided into
+ * several themes, listed below.</p>
+ * <h2>Compatible Images</h2>
+ * <p>Compatible images can, and should, be used to increase drawing
+ * performance. This class provides a number of methods to load compatible
+ * images directly from files or to convert existing images to compatibles
+ * images.</p>
+ * <h2>Creating Thumbnails</h2>
+ * <p>This class provides a number of methods to easily scale down images.
+ * Some of these methods offer a trade-off between speed and result quality and
+ * shouuld be used all the time. They also offer the advantage of producing
+ * compatible images, thus automatically resulting into better runtime
+ * performance.</p>
+ * <p>All these methodes are both faster than
+ * {@link java.awt.Image#getScaledInstance(int, int, int)} and produce
+ * better-looking results than the various <code>drawImage()</code> methods
+ * in {@link java.awt.Graphics}, which can be used for image scaling.</p>
+ * <h2>Image Manipulation</h2>
+ * <p>This class provides two methods to get and set pixels in a buffered image.
+ * These methods try to avoid unmanaging the image in order to keep good
+ * performance.</p>
+ *
+ * @author Romain Guy <romain.guy@mac.com>
+ */
+public class GraphicsUtilities {
+    private GraphicsUtilities() {
+    }
+
+    // Returns the graphics configuration for the primary screen
+    private static GraphicsConfiguration getGraphicsConfiguration() {
+        return GraphicsEnvironment.getLocalGraphicsEnvironment().
+                    getDefaultScreenDevice().getDefaultConfiguration();
+    }
+
+    /**
+     * <p>Returns a new <code>BufferedImage</code> using the same color model
+     * as the image passed as a parameter. The returned image is only compatible
+     * with the image passed as a parameter. This does not mean the returned
+     * image is compatible with the hardware.</p>
+     *
+     * @param image the reference image from which the color model of the new
+     *   image is obtained
+     * @return a new <code>BufferedImage</code>, compatible with the color model
+     *   of <code>image</code>
+     */
+    public static BufferedImage createColorModelCompatibleImage(BufferedImage image) {
+        ColorModel cm = image.getColorModel();
+        return new BufferedImage(cm,
+            cm.createCompatibleWritableRaster(image.getWidth(),
+                                              image.getHeight()),
+            cm.isAlphaPremultiplied(), null);
+    }
+
+    /**
+     * <p>Returns a new compatible image with the same width, height and
+     * transparency as the image specified as a parameter.</p>
+     *
+     * @see java.awt.Transparency
+     * @see #createCompatibleImage(int, int)
+     * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int)
+     * @see #createCompatibleTranslucentImage(int, int)
+     * @see #loadCompatibleImage(java.net.URL)
+     * @see #toCompatibleImage(java.awt.image.BufferedImage)
+     * @param image the reference image from which the dimension and the
+     *   transparency of the new image are obtained
+     * @return a new compatible <code>BufferedImage</code> with the same
+     *   dimension and transparency as <code>image</code>
+     */
+    public static BufferedImage createCompatibleImage(BufferedImage image) {
+        return createCompatibleImage(image, image.getWidth(), image.getHeight());
+    }
+
+    /**
+     * <p>Returns a new compatible image of the specified width and height, and
+     * the same transparency setting as the image specified as a parameter.</p>
+     *
+     * @see java.awt.Transparency
+     * @see #createCompatibleImage(java.awt.image.BufferedImage)
+     * @see #createCompatibleImage(int, int)
+     * @see #createCompatibleTranslucentImage(int, int)
+     * @see #loadCompatibleImage(java.net.URL)
+     * @see #toCompatibleImage(java.awt.image.BufferedImage)
+     * @param width the width of the new image
+     * @param height the height of the new image
+     * @param image the reference image from which the transparency of the new
+     *   image is obtained
+     * @return a new compatible <code>BufferedImage</code> with the same
+     *   transparency as <code>image</code> and the specified dimension
+     */
+    public static BufferedImage createCompatibleImage(BufferedImage image,
+                                                      int width, int height) {
+        return getGraphicsConfiguration().createCompatibleImage(width, height,
+                                                   image.getTransparency());
+    }
+
+    /**
+     * <p>Returns a new opaque compatible image of the specified width and
+     * height.</p>
+     *
+     * @see #createCompatibleImage(java.awt.image.BufferedImage)
+     * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int)
+     * @see #createCompatibleTranslucentImage(int, int)
+     * @see #loadCompatibleImage(java.net.URL)
+     * @see #toCompatibleImage(java.awt.image.BufferedImage)
+     * @param width the width of the new image
+     * @param height the height of the new image
+     * @return a new opaque compatible <code>BufferedImage</code> of the
+     *   specified width and height
+     */
+    public static BufferedImage createCompatibleImage(int width, int height) {
+        return getGraphicsConfiguration().createCompatibleImage(width, height);
+    }
+
+    /**
+     * <p>Returns a new translucent compatible image of the specified width
+     * and height.</p>
+     *
+     * @see #createCompatibleImage(java.awt.image.BufferedImage)
+     * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int)
+     * @see #createCompatibleImage(int, int)
+     * @see #loadCompatibleImage(java.net.URL)
+     * @see #toCompatibleImage(java.awt.image.BufferedImage)
+     * @param width the width of the new image
+     * @param height the height of the new image
+     * @return a new translucent compatible <code>BufferedImage</code> of the
+     *   specified width and height
+     */
+    public static BufferedImage createCompatibleTranslucentImage(int width,
+                                                                 int height) {
+        return getGraphicsConfiguration().createCompatibleImage(width, height,
+                                                   Transparency.TRANSLUCENT);
+    }
+
+    /**
+     * <p>Returns a new compatible image from a URL. The image is loaded from the
+     * specified location and then turned, if necessary into a compatible
+     * image.</p>
+     *
+     * @see #createCompatibleImage(java.awt.image.BufferedImage)
+     * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int)
+     * @see #createCompatibleImage(int, int)
+     * @see #createCompatibleTranslucentImage(int, int)
+     * @see #toCompatibleImage(java.awt.image.BufferedImage)
+     * @param resource the URL of the picture to load as a compatible image
+     * @return a new translucent compatible <code>BufferedImage</code> of the
+     *   specified width and height
+     * @throws java.io.IOException if the image cannot be read or loaded
+     */
+    public static BufferedImage loadCompatibleImage(URL resource)
+            throws IOException {
+        BufferedImage image = ImageIO.read(resource);
+        if (image == null) {
+            throw new IOException("Image format of resource not supported. Resource: " + resource);
+        }
+        return toCompatibleImage(image);
+    }
+    
+    /**
+     * <p>Returns a new compatible image from a URL. The image is loaded from the
+     * specified location and then turned, if necessary into a translucent compatible
+     * image.</p>
+     *
+     * @see #createCompatibleImage(java.awt.image.BufferedImage)
+     * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int)
+     * @see #createCompatibleImage(int, int)
+     * @see #createCompatibleTranslucentImage(int, int)
+     * @see #toCompatibleImage(java.awt.image.BufferedImage)
+     * @param resource the URL of the picture to load as a compatible image
+     * @return a new translucent compatible <code>BufferedImage</code> of the
+     *   specified width and height
+     * @throws java.io.IOException if the image cannot be read or loaded
+     */
+    public static BufferedImage loadCompatibleTranslucentImage(URL resource)
+            throws IOException {
+        BufferedImage image = ImageIO.read(resource);
+        if (image == null) {
+            throw new IOException("Image format of resource not supported. Resource: " + resource);
+        }
+        return toCompatibleTranslucentImage(image);
+    }
+    
+    // As above, but uses given file contents rather than path
+    public static BufferedImage loadCompatibleTranslucentImage(byte[] imageData)
+        throws IOException
+    {
+        BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageData));
+        if (image == null) {
+            throw new IOException("Image format of byte data not supported");
+        }
+        return toCompatibleTranslucentImage(image);
+    }
+
+    /**
+     * <p>Return a new compatible image that contains a copy of the specified
+     * image. This method ensures an image is compatible with the hardware,
+     * and therefore optimized for fast blitting operations.</p>
+     *
+     * @see #createCompatibleImage(java.awt.image.BufferedImage)
+     * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int)
+     * @see #createCompatibleImage(int, int)
+     * @see #createCompatibleTranslucentImage(int, int)
+     * @see #loadCompatibleImage(java.net.URL)
+     * @param image the image to copy into a new compatible image
+     * @return a new compatible copy, with the
+     *   same width and height and transparency and content, of <code>image</code>
+     */
+    public static BufferedImage toCompatibleImage(BufferedImage image) {
+        if (image.getColorModel().equals(
+                getGraphicsConfiguration().getColorModel())) {
+            return image;
+        }
+
+        BufferedImage compatibleImage =
+                getGraphicsConfiguration().createCompatibleImage(
+                    image.getWidth(), image.getHeight(),
+                    image.getTransparency());
+        Graphics g = compatibleImage.getGraphics();
+        g.drawImage(image, 0, 0, null);
+        g.dispose();
+
+        return compatibleImage;
+    }
+    
+    /**
+     * <p>
+     * Return a new compatible image that contains a copy of the specified
+     * image. This method ensures an image is compatible with the hardware, and
+     * therefore optimized for fast blitting operations. It also ensures that
+     * the image is translucent.
+     * </p>
+     * 
+     * @see #createCompatibleImage(java.awt.image.BufferedImage)
+     * @see #createCompatibleImage(java.awt.image.BufferedImage, int, int)
+     * @see #createCompatibleImage(int, int)
+     * @see #createCompatibleTranslucentImage(int, int)
+     * @see #loadCompatibleImage(java.net.URL)
+     * @param image the image to copy into a new compatible image
+     * @return a new compatible copy, with the same width and height and
+     *         transparency and content, of <code>image</code>
+     */
+    public static BufferedImage toCompatibleTranslucentImage(BufferedImage image)
+    {
+        if (image.getColorModel().equals(getGraphicsConfiguration().getColorModel())
+                && image.getColorModel().hasAlpha()) {
+            return image;
+        }
+
+        BufferedImage compatibleImage = getGraphicsConfiguration().createCompatibleImage(
+                    image.getWidth(), image.getHeight(),
+                    Transparency.TRANSLUCENT);
+        Graphics g = compatibleImage.getGraphics();
+        g.drawImage(image, 0, 0, null);
+        g.dispose();
+
+        return compatibleImage;
+    }
+
+    /**
+     * <p>Returns a thumbnail of a source image. <code>newSize</code> defines
+     * the length of the longest dimension of the thumbnail. The other
+     * dimension is then computed according to the dimensions ratio of the
+     * original picture.</p>
+     * <p>This method favors speed over quality. When the new size is less than
+     * half the longest dimension of the source image,
+     * {@link #createThumbnail(BufferedImage, int)} or
+     * {@link #createThumbnail(BufferedImage, int, int)} should be used instead
+     * to ensure the quality of the result without sacrificing too much
+     * performance.</p>
+     *
+     * @see #createThumbnailFast(java.awt.image.BufferedImage, int, int)
+     * @see #createThumbnail(java.awt.image.BufferedImage, int)
+     * @see #createThumbnail(java.awt.image.BufferedImage, int, int)
+     * @param image the source image
+     * @param newSize the length of the largest dimension of the thumbnail
+     * @return a new compatible <code>BufferedImage</code> containing a
+     *   thumbnail of <code>image</code>
+     * @throws IllegalArgumentException if <code>newSize</code> is larger than
+     *   the largest dimension of <code>image</code> or &lt;= 0
+     */
+    public static BufferedImage createThumbnailFast(BufferedImage image,
+                                                    int newSize) {
+        float ratio;
+        int width = image.getWidth();
+        int height = image.getHeight();
+
+        if (width > height) {
+            if (newSize >= width) {
+                throw new IllegalArgumentException("newSize must be lower than" +
+                                                   " the image width");
+            } else if (newSize <= 0) {
+                 throw new IllegalArgumentException("newSize must" +
+                                                    " be greater than 0");
+            }
+
+            ratio = (float) width / (float) height;
+            width = newSize;
+            height = (int) (newSize / ratio);
+        } else {
+            if (newSize >= height) {
+                throw new IllegalArgumentException("newSize must be lower than" +
+                                                   " the image height");
+            } else if (newSize <= 0) {
+                 throw new IllegalArgumentException("newSize must" +
+                                                    " be greater than 0");
+            }
+
+            ratio = (float) height / (float) width;
+            height = newSize;
+            width = (int) (newSize / ratio);
+        }
+
+        BufferedImage temp = createCompatibleImage(image, width, height);
+        Graphics2D g2 = temp.createGraphics();
+        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+                            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+        g2.drawImage(image, 0, 0, temp.getWidth(), temp.getHeight(), null);
+        g2.dispose();
+
+        return temp;
+    }
+
+    /**
+     * <p>Returns a thumbnail of a source image.</p>
+     * <p>This method favors speed over quality. When the new size is less than
+     * half the longest dimension of the source image,
+     * {@link #createThumbnail(BufferedImage, int)} or
+     * {@link #createThumbnail(BufferedImage, int, int)} should be used instead
+     * to ensure the quality of the result without sacrificing too much
+     * performance.</p>
+     *
+     * @see #createThumbnailFast(java.awt.image.BufferedImage, int)
+     * @see #createThumbnail(java.awt.image.BufferedImage, int)
+     * @see #createThumbnail(java.awt.image.BufferedImage, int, int)
+     * @param image the source image
+     * @param newWidth the width of the thumbnail
+     * @param newHeight the height of the thumbnail
+     * @return a new compatible <code>BufferedImage</code> containing a
+     *   thumbnail of <code>image</code>
+     * @throws IllegalArgumentException if <code>newWidth</code> is larger than
+     *   the width of <code>image</code> or if code>newHeight</code> is larger
+     *   than the height of <code>image</code> or if one of the dimensions
+     *   is &lt;= 0
+     */
+    public static BufferedImage createThumbnailFast(BufferedImage image,
+                                                    int newWidth, int newHeight) {
+        if (newWidth >= image.getWidth() ||
+            newHeight >= image.getHeight()) {
+            throw new IllegalArgumentException("newWidth and newHeight cannot" +
+                                               " be greater than the image" +
+                                               " dimensions");
+        } else if (newWidth <= 0 || newHeight <= 0) {
+            throw new IllegalArgumentException("newWidth and newHeight must" +
+                                               " be greater than 0");
+        }
+
+        BufferedImage temp = createCompatibleImage(image, newWidth, newHeight);
+        Graphics2D g2 = temp.createGraphics();
+        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+                            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+        g2.drawImage(image, 0, 0, temp.getWidth(), temp.getHeight(), null);
+        g2.dispose();
+
+        return temp;
+    }
+
+    /**
+     * <p>Returns a thumbnail of a source image. <code>newSize</code> defines
+     * the length of the longest dimension of the thumbnail. The other
+     * dimension is then computed according to the dimensions ratio of the
+     * original picture.</p>
+     * <p>This method offers a good trade-off between speed and quality.
+     * The result looks better than
+     * {@link #createThumbnailFast(java.awt.image.BufferedImage, int)} when
+     * the new size is less than half the longest dimension of the source
+     * image, yet the rendering speed is almost similar.</p>
+     *
+     * @see #createThumbnailFast(java.awt.image.BufferedImage, int, int)
+     * @see #createThumbnailFast(java.awt.image.BufferedImage, int)
+     * @see #createThumbnail(java.awt.image.BufferedImage, int, int)
+     * @param image the source image
+     * @param newSize the length of the largest dimension of the thumbnail
+     * @return a new compatible <code>BufferedImage</code> containing a
+     *   thumbnail of <code>image</code>
+     * @throws IllegalArgumentException if <code>newSize</code> is larger than
+     *   the largest dimension of <code>image</code> or &lt;= 0
+     */
+    public static BufferedImage createThumbnail(BufferedImage image,
+                                                int newSize) {
+        int width = image.getWidth();
+        int height = image.getHeight();
+
+        boolean isWidthGreater = width > height;
+
+        if (isWidthGreater) {
+            if (newSize >= width) {
+                throw new IllegalArgumentException("newSize must be lower than" +
+                                                   " the image width");
+            }
+        } else if (newSize >= height) {
+            throw new IllegalArgumentException("newSize must be lower than" +
+                                               " the image height");
+        }
+
+        if (newSize <= 0) {
+            throw new IllegalArgumentException("newSize must" +
+                                               " be greater than 0");
+        }
+
+        float ratioWH = (float) width / (float) height;
+        float ratioHW = (float) height / (float) width;
+
+        BufferedImage thumb = image;
+
+        do {
+            if (isWidthGreater) {
+                width /= 2;
+                if (width < newSize) {
+                    width = newSize;
+                }
+                height = (int) (width / ratioWH);
+            } else {
+                height /= 2;
+                if (height < newSize) {
+                    height = newSize;
+                }
+                width = (int) (height / ratioHW);
+            }
+
+
+            BufferedImage temp = createCompatibleImage(image, width, height);
+            Graphics2D g2 = temp.createGraphics();
+            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+                                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+            g2.drawImage(thumb, 0, 0, temp.getWidth(), temp.getHeight(), null);
+            g2.dispose();
+
+            thumb = temp;
+        } while (newSize != (isWidthGreater ? width : height));
+
+        return thumb;
+    }
+
+    /**
+     * <p>Returns a thumbnail of a source image.</p>
+     * <p>This method offers a good trade-off between speed and quality.
+     * The result looks better than
+     * {@link #createThumbnailFast(java.awt.image.BufferedImage, int)} when
+     * the new size is less than half the longest dimension of the source
+     * image, yet the rendering speed is almost similar.</p>
+     *
+     * @see #createThumbnailFast(java.awt.image.BufferedImage, int)
+     * @see #createThumbnailFast(java.awt.image.BufferedImage, int, int)
+     * @see #createThumbnail(java.awt.image.BufferedImage, int)
+     * @param image the source image
+     * @param newWidth the width of the thumbnail
+     * @param newHeight the height of the thumbnail
+     * @return a new compatible <code>BufferedImage</code> containing a
+     *   thumbnail of <code>image</code>
+     * @throws IllegalArgumentException if <code>newWidth</code> is larger than
+     *   the width of <code>image</code> or if code>newHeight</code> is larger
+     *   than the height of <code>image or if one the dimensions is not &gt; 0</code>
+     */
+    public static BufferedImage createThumbnail(BufferedImage image,
+                                                int newWidth, int newHeight) {
+        int width = image.getWidth();
+        int height = image.getHeight();
+
+        if (newWidth >= width || newHeight >= height) {
+            throw new IllegalArgumentException("newWidth and newHeight cannot" +
+                                               " be greater than the image" +
+                                               " dimensions");
+        } else if (newWidth <= 0 || newHeight <= 0) {
+            throw new IllegalArgumentException("newWidth and newHeight must" +
+                                               " be greater than 0");
+        }
+
+        BufferedImage thumb = image;
+
+        do {
+            if (width > newWidth) {
+                width /= 2;
+                if (width < newWidth) {
+                    width = newWidth;
+                }
+            }
+
+            if (height > newHeight) {
+                height /= 2;
+                if (height < newHeight) {
+                    height = newHeight;
+                }
+            }
+
+            BufferedImage temp = createCompatibleImage(image, width, height);
+            Graphics2D g2 = temp.createGraphics();
+            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+                                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+            g2.drawImage(thumb, 0, 0, temp.getWidth(), temp.getHeight(), null);
+            g2.dispose();
+
+            thumb = temp;
+        } while (width != newWidth || height != newHeight);
+
+        return thumb;
+    }
+
+    /**
+     * <p>Returns an array of pixels, stored as integers, from a
+     * <code>BufferedImage</code>. The pixels are grabbed from a rectangular
+     * area defined by a location and two dimensions. Calling this method on
+     * an image of type different from <code>BufferedImage.TYPE_INT_ARGB</code>
+     * and <code>BufferedImage.TYPE_INT_RGB</code> will unmanage the image.</p>
+     *
+     * @param img the source image
+     * @param x the x location at which to start grabbing pixels
+     * @param y the y location at which to start grabbing pixels
+     * @param w the width of the rectangle of pixels to grab
+     * @param h the height of the rectangle of pixels to grab
+     * @param pixels a pre-allocated array of pixels of size w*h; can be null
+     * @return <code>pixels</code> if non-null, a new array of integers
+     *   otherwise
+     * @throws IllegalArgumentException is <code>pixels</code> is non-null and
+     *   of length &lt; w*h
+     */
+    public static int[] getPixels(BufferedImage img,
+                                  int x, int y, int w, int h, int[] pixels) {
+        if (w == 0 || h == 0) {
+            return new int[0];
+        }
+
+        if (pixels == null) {
+            pixels = new int[w * h];
+        } else if (pixels.length < w * h) {
+            throw new IllegalArgumentException("pixels array must have a length" +
+                                               " >= w*h");
+        }
+
+        int imageType = img.getType();
+        if (imageType == BufferedImage.TYPE_INT_ARGB ||
+            imageType == BufferedImage.TYPE_INT_RGB) {
+            Raster raster = img.getRaster();
+            return (int[]) raster.getDataElements(x, y, w, h, pixels);
+        }
+
+        // Unmanages the image
+        return img.getRGB(x, y, w, h, pixels, 0, w);
+    }
+
+    /**
+     * <p>Writes a rectangular area of pixels in the destination
+     * <code>BufferedImage</code>. Calling this method on
+     * an image of type different from <code>BufferedImage.TYPE_INT_ARGB</code>
+     * and <code>BufferedImage.TYPE_INT_RGB</code> will unmanage the image.</p>
+     *
+     * @param img the destination image
+     * @param x the x location at which to start storing pixels
+     * @param y the y location at which to start storing pixels
+     * @param w the width of the rectangle of pixels to store
+     * @param h the height of the rectangle of pixels to store
+     * @param pixels an array of pixels, stored as integers
+     * @throws IllegalArgumentException is <code>pixels</code> is non-null and
+     *   of length &lt; w*h
+     */
+    public static void setPixels(BufferedImage img,
+                                 int x, int y, int w, int h, int[] pixels) {
+        if (pixels == null || w == 0 || h == 0) {
+            return;
+        } else if (pixels.length < w * h) {
+            throw new IllegalArgumentException("pixels array must have a length" +
+                                               " >= w*h");
+        }
+
+        int imageType = img.getType();
+        if (imageType == BufferedImage.TYPE_INT_ARGB ||
+            imageType == BufferedImage.TYPE_INT_RGB) {
+            WritableRaster raster = img.getRaster();
+            raster.setDataElements(x, y, w, h, pixels);
+        } else {
+            // Unmanages the image
+            img.setRGB(x, y, w, h, pixels, 0, w);
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/GreenfootStorageException.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/GreenfootStorageException.java
new file mode 100644
index 0000000000000000000000000000000000000000..81dfb35c918e48dcc743e08598f99e1d2567bc4b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/GreenfootStorageException.java
@@ -0,0 +1,47 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+/**
+ * Indicates a problem with accessing the storage
+ * <p>
+ * This indicates that there was a problem reading from/writing to the storage, typically:
+ * 
+ * <ul>
+ * <li>A problem accessing the CSV file in the local storage (e.g. bad permissions, disconnected USB stick)
+ * <li>A problem accessing the Gallery storage (may be caused by maintenance work on the gallery)
+ * <li>If storage is not supported, this exception will be thrown every time.
+ * </ul>
+ * <p>
+ * In general, the way to deal with this exception is to live with not using
+ * storage for this session.  Warn the user that their data cannot be loaded/saved,
+ * and proceed as best as you can.
+ */
+public class GreenfootStorageException extends Exception
+{
+
+    public GreenfootStorageException(String message)
+    {
+        super(message);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/GreenfootUtil.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/GreenfootUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ee8c5414e2fd3de28143415107fb00735df82cc
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/GreenfootUtil.java
@@ -0,0 +1,965 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+import greenfoot.GreenfootImage;
+import greenfoot.UserInfo;
+import greenfoot.core.ImageCache;
+import greenfoot.platforms.GreenfootUtilDelegate;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.RenderingHints;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.font.TextAttribute;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Modifier;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.imageio.ImageIO;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import bluej.Boot;
+import bluej.Config;
+import bluej.utility.Utility;
+
+/**
+ * General utility methods for Greenfoot.
+ * 
+ * @author Davin McCall
+ */
+public class GreenfootUtil
+{
+    // constants for use with createSpacer()
+    public static final int X_AXIS = 0;
+    public static final int Y_AXIS = 1;
+    
+    private static GreenfootUtilDelegate delegate;
+    private static ImageCache imageCache;
+
+    private static final Color urlColor = new Color(0, 90, 200);
+    
+    private static boolean haveCheckedForMp3 = false;
+    private static boolean mp3available = false;
+    
+    public static void initialise(GreenfootUtilDelegate newDelegate)
+    {
+        delegate = newDelegate;
+        imageCache = ImageCache.getInstance();
+    }
+    
+    /**
+     * Extracts the name of a class from the qualified class name.
+     */
+    public static String extractClassName(String qualifiedName)
+    {
+        int index = qualifiedName.lastIndexOf('.');
+        String name = qualifiedName;
+        if (index >= 0) {
+            name = qualifiedName.substring(index + 1);
+        }
+        return name;
+    }
+    
+    /**
+     * Extracts the package of a class from the qualified class name.
+     */
+    public static String extractPackageName(String qualifiedName)
+    {
+        int index = qualifiedName.lastIndexOf('.');
+        String name = "";
+        if (index >= 0) {
+            name = qualifiedName.substring(0, index);
+        }
+        return name;
+    }   
+    
+    /**
+     * Get a spacer along the specified axis and with the specified width.
+     * <p>
+     * A Spacer is like a strut, but with a minimum height/width of 0,
+     * so it will collapse to provide additional space to other
+     * components if necessary.
+     */
+    public static JComponent createSpacer(int axis, int width)
+    {
+        JPanel spacer = new JPanel();
+        
+        spacer.setMinimumSize(new Dimension(0,0));
+        
+        Dimension size = new Dimension();
+        
+        // Preferred size...
+        size.width = 0;
+        size.height = 0;
+        if (axis == X_AXIS) {
+            size.width = width;
+        }
+        else {
+            size.height = width;
+        }
+        spacer.setPreferredSize(size);
+        
+        // Maximum size
+        spacer.setMaximumSize(size);
+
+        spacer.setBorder(null);
+        
+        return spacer;
+    }
+    
+    /**
+     * Create a JLabel suitable for displaying help text (small font).
+     */
+    public static JLabel createHelpLabel()
+    {
+        JLabel helpLabel = new JLabel();
+        Font smallFont = helpLabel.getFont().deriveFont(Font.ITALIC, 11.0f);
+        helpLabel.setFont(smallFont);
+        return helpLabel;
+    }
+
+    /**
+     * Check whether a given file is an image that can be read by Java.
+     * 
+     * @param file the file to check
+     * @return true if the file is a valid image, false otherwise.
+     */
+    public static boolean isImage(File file)
+    {
+        try {
+            BufferedImage img = ImageIO.read(file);
+            if(img==null) return false;
+            return true;
+        }
+        catch(Exception ex) {
+            return false;
+        }
+    }
+    
+    /**
+     * Scale an image, but avoid stretching small images and changing of the image's
+     * aspect ratio. If the input image is smaller than the desired size, it is centered
+     * in the output image.
+     * 
+     * @param inputImage  The image to scale
+     * @param w           The desired width
+     * @param h           The desired height
+     * @return         The scaled image
+     */
+    public static Image getScaledImage(Image inputImage, int w, int h)
+    {
+        ImageWaiter waiter = new ImageWaiter(inputImage);
+        
+        waiter.waitDimensions();
+        int inputw = waiter.width;
+        int inputh = waiter.height;
+        
+        // If the image is already the correct size, return it.
+        if (w == inputw && h == inputh) {
+            return inputImage;
+        }
+        
+        // Otherwise create a new image
+        BufferedImage rImage = GraphicsUtilities.createCompatibleTranslucentImage(w, h);
+        Graphics2D graphics = rImage.createGraphics();
+        // We'd like interpolated image rendering.
+        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+        
+        // if the input image is smaller in both dimensions than the required
+        // image, just stamp it.
+        if (inputw <= w && inputh <= h) {
+            int xoffs = (w - inputw) / 2;
+            int yoffs = (h - inputh) / 2;
+            // graphics.drawImage(inputImage, xoffs, yoffs, null);
+            waiter.drawWait(graphics, xoffs, yoffs);
+        }
+        else {
+            // Otherwise, scale the image, maintaining the aspect ratio
+            float xscale = (float) w / inputw; // required scaling horizontal
+            float yscale = (float) h / inputh; // required scaling vertical
+        
+            // The scale factor we use must be the lower of the required horizontal
+            // scaling and required vertical scaling. We then use the scale for both
+            // horizontal and vertical scaling, thereby preserving aspect ratio.
+            float scale = xscale < yscale ? xscale : yscale;
+            
+            // Scale, and check that rounding hasn't caused problems
+            int neww = (int)(inputw * scale);
+            int newh = (int)(inputh * scale);
+            if (neww > inputw) {
+                neww = inputw;
+            }
+            if (newh > inputh) {
+                newh = inputh;
+            }
+            if (neww < 1) {
+                neww = 1;
+            }
+            if (newh < 1) {
+                newh = 1;
+            }
+            if (neww < w && newh < h) {
+                neww++; newh++;
+            }
+
+            // draw the scaled image centered
+            int xoffs = (w - neww) / 2;
+            int yoffs = (h - newh) / 2;
+            // graphics.drawImage(inputImage, xoffs, yoffs, neww, newh, null);
+            
+            // This can throw an exception if the image is too big:
+            try {
+                waiter.drawWait(graphics, xoffs, yoffs, neww, newh);
+            }
+            catch (java.lang.OutOfMemoryError oome) {
+                // draw a white background overlaid with a red cross
+                graphics.setColor(Color.white);
+                graphics.fillRect(1, 1, w - 2, h - 2);
+                graphics.setColor(Color.red);
+                graphics.drawRect(0, 0, w - 1, h - 1);
+                graphics.drawLine(0, 0, w, h);
+                graphics.drawLine(0, h, w, 0);
+            }
+        }
+        graphics.dispose();
+        return rImage;
+    }
+    
+    /**
+     * A class which conveniently allows us to synchronously retrieve the
+     * width and height of an Image, and to draw the image to a graphics
+     * context.
+     * 
+     * @author Davin McCall
+     */
+    public static class ImageWaiter implements ImageObserver
+    {
+        public int width;
+        public int height;
+        public boolean done;
+        public boolean gotDimensions;
+        public Image src;
+        
+        public ImageWaiter(Image src)
+        {
+            this.src = src;
+            done = false;
+            gotDimensions = false;
+            synchronized (this) {
+                width = src.getWidth(this);
+                height = src.getHeight(this);
+                if (width != -1 && height != -1) {
+                    gotDimensions = true;
+                }
+            }
+        }
+        
+        /**
+         * Wait until we have the dimensions of the image.
+         */
+        public synchronized void waitDimensions()
+        {
+            try {
+                while (! gotDimensions) {
+                    wait();
+                }
+            }
+            catch (InterruptedException ie) {}
+        }
+        
+        /**
+         * Draw the source image to a graphics context and wait for the drawing
+         * operation to complete.
+         * 
+         * @param canvas   The graphics context to draw to
+         * @param x        The x position to draw to
+         * @param y        The y position to draw to
+         */
+        public synchronized void drawWait(Graphics canvas, int x, int y)
+        {
+            done = canvas.drawImage(src, x, y, this);
+            try {
+                while (! done) {
+                    wait();
+                }
+            }
+            catch (InterruptedException ie) {}
+        }
+        
+        /**
+         * Scale and draw the source image to a graphics context and wait for the
+         * drawing operation to complete.
+         * 
+         * @param canvas   The graphics context to draw to
+         * @param x        The x position to draw to
+         * @param y        The y position to draw to
+         * @param w        The width to scale to
+         * @param h        The height to scale to
+         */
+        public synchronized void drawWait(Graphics canvas, int x, int y, int w, int h)
+        {
+            done = canvas.drawImage(src, x, y, w, h, this);
+            try {
+                while (! done) {
+                    wait();
+                }
+            }
+            catch (InterruptedException ie) {}
+        }
+        
+        /*
+         * This is the asynchronous callback for when the dimensions of the image
+         * become available, or the draw operation finishes.
+         * 
+         *  (non-Javadoc)
+         * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+         */
+        @Override
+        public synchronized boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
+        {
+            // First stage: get image dimensions
+            if (! gotDimensions) {
+                if ((infoflags & WIDTH) != 0) {
+                    this.width = width;
+                }
+                
+                if ((infoflags & HEIGHT) != 0) {
+                    this.height = height;
+                }
+                
+                if (this.width != -1 && this.height != -1) {
+                    gotDimensions = true;
+                    notify();
+                    return false;
+                }
+                else {
+                    return true;
+                }
+            }
+            
+            // Second stage: wait for draw operation to complete
+            if ((infoflags & (FRAMEBITS | ALLBITS | ERROR | ABORT)) != 0) {
+                done = true;
+                notify();
+                return false;
+            }
+            
+            return true;
+        }
+    }
+    
+    
+    /**
+     * Copies the src-DIR recursively into dst.
+     */
+    public static void copyDir(File src, File dst)
+    {
+        if (!src.isDirectory()) {
+            return;
+        }
+        if (!dst.exists()) {
+            dst.mkdirs();
+        }
+        File[] files = src.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            File file = files[i];
+            File newDst = new File(dst, file.getName());
+            if (file.isDirectory()) {
+                copyDir(file, newDst);
+            }
+            else {
+                copyFile(file, newDst);
+            }
+        }
+    }
+
+    /**
+     * Copies the src to dst, creating parent dirs for dst. If dst exists it
+     * is overwritten.
+     * 
+     * @param src
+     *            The source. It must be a file
+     * @param dst
+     *            Must not exist as a DIR
+     */
+    public static void copyFile(File src, File dst)
+    {
+        if (!src.isFile() || dst.isDirectory()) {
+            return;
+        }
+        dst.getParentFile().mkdirs();
+        if (dst.exists()) {
+            dst.delete();
+        }
+        try {
+            BufferedInputStream is = new BufferedInputStream(new FileInputStream(src));
+            BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(dst));
+
+            byte[] buffer = new byte[8192];
+            int read = 0;
+            while (read != -1) {
+                os.write(buffer, 0, read);
+                read = is.read(buffer);
+            }
+            os.flush();
+            is.close();
+            os.close();
+        }
+        catch (FileNotFoundException ex) {
+            ex.printStackTrace();
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+        finally {
+
+        }
+    }
+    
+    /**
+     * Gets a list of the sound files in this scenario
+     * @return A list of files in the sounds subdirectory, without the path prefix (e.g. "foo.wav")
+     */
+    public static Iterable<String> getSoundFiles()
+    {
+        return delegate.getSoundFiles();
+    }
+
+    /**
+     * Tries to find the specified file using the classloader. It first searches in
+     * 'projectdir/dir/', then in the 'projectdir' and last as an absolute filename or URL.
+     * 
+     * @param filename Name of the file
+     * @param dir directory to search in first
+     * @return A URL that can be read or null if the URL could not be found.
+     * @throws FileNotFoundException If the file cannot be found.
+     */
+    public static URL getURL(final String filename, final String dir) throws FileNotFoundException
+    {
+        if (filename == null) {
+            throw new NullPointerException("Filename must not be null.");
+        }
+        
+        URL url = delegate.getResource(dir + "/" + filename);
+
+        if (url == null) {
+            url = delegate.getResource(filename);
+        }
+        if (url == null) {
+            // Third, try as an absolute file
+            File f = new File(filename);
+            
+            try {
+                if (f.canRead()) {
+                    url = f.toURI().toURL();
+                }
+            }
+            catch (MalformedURLException e) {
+                // Not a URL that Java can handle
+            }
+            catch (SecurityException se) {
+                // Can get this when running as an applet
+            }
+        }
+        if(url == null) {
+            // Fourth, try as an absolute  URL.
+            InputStream s = null;
+            try {
+                url = new URL(filename);
+                s = url.openStream();
+                s.close();
+            }
+            catch (MalformedURLException e) {
+                url = null;
+            }
+            catch (IOException e) {
+                url = null;
+            } finally {
+                if(s != null) {
+                    try {
+                        s.close();
+                    }
+                    catch (IOException e) {
+                    }
+                }
+            }
+        }
+
+        checkCase(url);
+
+        if(url == null) {
+            throw new FileNotFoundException("Could not find file: " + filename);
+        }
+        return url;
+    }
+
+    
+    /**
+     * Checks whether the case is correct for the given URL. If it is detected
+     * NOT to be the right case a IllegalArgumentException will be thrown.
+     * 
+     * @throws IllegalArgumentException If the case is wrong.
+     */
+    private static void checkCase(URL url)
+    {
+        if (url != null) {
+            String errMsg = null;
+            try {
+                File f = new File(url.toURI());
+                String givenName = f.getName();
+                String realName = f.getCanonicalFile().getName();
+                if (!realName.equals(givenName) && realName.equalsIgnoreCase(givenName)) {
+                    errMsg = "Filename \'" + givenName + "\' has the wrong case. It should be: \'" + realName + "\'";
+                }
+
+            }
+            catch (Throwable e) {
+                // things might go wrong if we are running in an applet or from
+                // a jar. Just ignore all exceptions.
+            }
+            if (errMsg != null) {
+                throw new IllegalArgumentException(errMsg);
+            }
+        }
+    }
+
+    /**
+     * Returns the path to a small version of the greenfoot logo.
+     */
+    public static String getGreenfootLogoPath()
+    {        
+        return delegate.getGreenfootLogoPath();
+    }
+    
+    /**
+     * Check whether a class can be instantiated: it is not abstract
+     * or an interface.
+     */
+    public static boolean canBeInstantiated(Class<?> cls)
+    {
+        // ACC_INTERFACE 0x0200 Is an interface, not a class.
+        // ACC_ABSTRACT 0x0400 Declared abstract; may not be
+        // instantiated.
+        if (cls == null) {
+            return false;
+        }
+        if (cls.isEnum() || cls.isInterface()) {
+            return false;
+        }
+        return ! Modifier.isAbstract(cls.getModifiers());
+    }
+    
+    /**
+     * Creates a new image which is a copy of the original with a drop shadow added.
+     */
+    public static BufferedImage createDragShadow(BufferedImage image)
+    {
+        BufferedImage dragImage = ShadowRenderer.createDropShadow(image, 3, 0.3f, Color.BLACK);
+        Graphics2D g2 = dragImage.createGraphics();
+        g2.drawImage(image, 0, 0, null);
+        g2.dispose();
+        return dragImage;
+    }
+    
+    /**
+     * Create a new button for the use in the Greenfoot UI. 
+     */
+    public static JButton createButton(Action action)
+    {
+        JButton button = new JButton(action);
+        button.setFocusable(false);
+        return button;
+    }
+    
+    /**
+     * Creates a new font derived from the one passed in, but with an added underline.
+     */
+    @SuppressWarnings("unchecked")
+    private static Font deriveUnderlinedFont(Font f)
+    {
+        Map attr =  f.getAttributes();                
+        attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
+        Font underLineFont = f.deriveFont(attr);
+        return underLineFont;
+    }
+
+    /**
+     * Makes this label into a clickable link to some website. It will modify
+     * the font to look like a classic link from HTML pages by making it blue
+     * with an underline.
+     * 
+     * @param label The label to make into a hyperlink.
+     * @param url The url to open when clicked.
+     */
+    public static void makeLink(final JLabel label, final String url)
+    {
+        label.setCursor(new Cursor(Cursor.HAND_CURSOR));
+        label.setForeground(urlColor);
+        Font f = label.getFont();
+        Font underLineFont = deriveUnderlinedFont(f);
+        label.setFont(underLineFont);
+        label.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent e)
+            {
+                Utility.openWebBrowser(url);
+            }
+        });
+    }
+    
+    /**
+     * Replaces all occurrences of BlueJ with Greenfoot in the title of the frame.
+     * <p>
+     * Should be called from event thread.
+     */
+    public static void makeGreenfootTitle(Frame frame)
+    {
+        String title = frame.getTitle();
+        String newTitle = title.replaceAll("BlueJ", "Greenfoot");
+        frame.setTitle(newTitle);
+    }    
+    
+    /**
+     * Tries to locate the top level greenfoot dir. This method takes the
+     * different platforms into account. Specifically the Mac has a different
+     * structure.
+     * 
+     * @throws IOException If it can't read the greenfoot dir.
+     * 
+     */
+    public static File getGreenfootDir()
+        throws IOException
+    {
+        File libDir = Config.getBlueJLibDir();
+        // The parent dir of the lib dir is the top level dir of greenfoot
+        File greenfootDir = libDir.getParentFile();
+        // But on the mac it is further back in the hierarchy.
+        if (Config.isMacOS() && greenfootDir != null && greenfootDir.toString().endsWith(".app/Contents/Resources")) {
+            greenfootDir = greenfootDir.getParentFile().getParentFile().getParentFile();
+        }
+        if (greenfootDir == null || !(greenfootDir.isDirectory() && greenfootDir.canRead())) {
+            throw new IOException("Could not read from greenfoot directory: " + greenfootDir);
+        }
+        return greenfootDir;
+    }
+
+    /**
+     * Opens the given page of the Greenfoot API documentation in a web browser.
+     * @param page name of the page relative to the root of the API doc.
+     * @throws IOException If the greenfoot directory can not be read
+     */
+    public static void showApiDoc(String page)
+        throws IOException
+    {
+        String customUrl = Config.getPropString("greenfoot.url.javadoc", null);
+        if(customUrl != null) {
+            Utility.openWebBrowser(customUrl);
+        }
+        else {
+            File greenfootDir = GreenfootUtil.getGreenfootDir();
+            File location = new File(greenfootDir, "/doc/API/" + page);
+            if (location.canRead()) {
+                Utility.openWebBrowser(location);
+            }
+        }
+    }
+    
+    /**
+     * Returns a set of the third party libraries used by Greenfoot.
+     * 
+     */
+    public static Set<File> get3rdPartyLibs()
+    {
+        File bluejLibDir = Config.getBlueJLibDir();      
+        String[] thirdPartyLibs = Boot.GREENFOOT_EXPORT_JARS;
+        Set<File> jars = new TreeSet<File>();
+        for (String lib : thirdPartyLibs) {
+            jars.add(new File(bluejLibDir, lib));
+        }
+        return jars;
+    }
+
+    /**
+     * Check whether MP3 support is available.
+     */
+    public static boolean isMp3LibAvailable()
+    {
+        if (! haveCheckedForMp3) {
+            URL url = delegate.getResource("javazoom/jl/decoder/BitstreamException.class");
+            mp3available = url != null;
+            haveCheckedForMp3 = true;
+        }
+        return mp3available;
+    }
+
+    /**
+     * First tries to create the file with the given name and type. If it
+     * already exists, it will try creating the file with "01" appended to the
+     * filename, if that exists it will try "02" and so on.
+     * 
+     * @param dir Directory where the file should be created.
+     * @param name Base name of the file
+     * @param type Type of the file (extension) (without the dot)
+     * @throws IOException If an IO error is generate when trying to create the
+     *             file.
+     */
+    public static File createNumberedFile(File dir, String name, String type)
+        throws IOException
+    {
+        File f = new File(dir, name + "." + type);
+        int number = 1;
+        while (!f.createNewFile()) {
+            String numberString = null;
+            if (number < 10) {
+                numberString = "0" + number;
+            }
+            else {
+                numberString = "" + number;
+            }
+            f = new File(dir, name + numberString + "." + type);
+            number++;
+        }
+        return f;
+    }
+    
+    /**
+     * Retrieves the GreenfootImage either from the cache or a new image if not previously created
+     * Adds the image to the cached image list or the null image list (if none was found)
+     * @param className name of the class
+     * @param imageName filename of the image
+     */
+    public static GreenfootImage getGreenfootImage(String className, String imageName)
+    {   
+        //try {throw new Exception();} catch (Exception e) {e.printStackTrace();}
+        GreenfootImage image=null;
+        if (imageName==null){
+            return image;
+        }
+        if (isInvalidImageFilename(imageName)){
+            return image;
+        }
+        // If it is the Actor class the image is always the same:
+        if (className.equals("Actor")) {
+            return new GreenfootImage(getGreenfootLogoPath());
+        }
+        try {
+            image = new GreenfootImage(imageName);
+        }
+        catch (IllegalArgumentException iae) {
+            // This occurs if the image file doesn't exist anymore
+        }
+        return image;
+    }
+
+    /**
+     * Remove the cached version of an image for a particular class. This should be
+     * called when the image for the class is changed. Thread-safe.
+     */
+    public static void removeCachedImage(String className)
+    {
+        imageCache.removeCachedImage(className);
+    }
+   
+    /**
+     * Adds a filename with the associated image into the cache
+     * @param name filename (should be the image filename)
+     * @param image GreenfootImage
+     */
+    public static boolean addCachedImage(String name, GreenfootImage image)
+    {
+        return imageCache.addCachedImage(name, image);
+    }
+    
+    /**
+     * Gets the cached image (if any) of the requested name. Thread-safe.
+     * 
+     * @param name   name of the image file
+     * @return The cached image (should not be modified), or null if the image
+     *         is not cached.
+     */
+    public static GreenfootImage getCachedImage(String name)
+    {
+        return imageCache.getCachedImage(name);
+    }
+    
+    /**
+     * Returns whether the cached image is null
+     */
+    public static boolean isInvalidImageFilename(String fileName)
+    {
+        return imageCache.isNullCachedImage(fileName);
+    }
+    
+    /**
+     * Display a message to the user; how the message is displayed is dependent
+     * upon the platform context. In the Greenfoot IDE, the message will be displayed
+     * in a dialog; otherwise it will be written to the terminal/console/log.
+     * 
+     * @param parent  The parent component (if a dialog is used to display the message)
+     * @param messageText   The message text itself.
+     */
+    public static void displayMessage(Component parent, String messageText)
+    {
+        delegate.displayMessage(parent, messageText);
+    }
+
+    /**
+     * Given a string that represents a filename (or long path),
+     * chops off the extension if any is present.
+     * 
+     * So Crab.java becomes Crab, and /tmp/pic.png becomes /tmp/pic
+     */
+    public static String removeExtension(String full)
+    {
+        int n = full.lastIndexOf('.');
+        if (n == -1) {
+            return full;
+        }
+        else {
+            return full.substring(0, n);
+        }
+    }
+
+    /**
+     * Find out whether storage is supported in the current setting
+     */
+    public static boolean isStorageSupported()
+    {
+        return delegate.isStorageSupported();
+    }
+
+    /**
+     * null if an error, blank values if no previous storage
+     */
+    public static UserInfo getCurrentUserInfo()
+    {
+        return delegate.getCurrentUserInfo();
+    }
+
+    /**
+     * returns whether it was successful
+     */
+    public static boolean storeCurrentUserInfo(UserInfo data)
+    {
+        if (data.getUserName().equals(getUserName()))
+            return delegate.storeCurrentUserInfo(data);
+        else
+        {
+            // This message the user should see, because
+            // it indicates a programming mistake:
+            System.err.println("Attempted to store the data for another user, \"" + data.getUserName() + "\" (i.e. a user other than the current user, \"" + getUserName() + "\")");
+            return false;
+        }
+    }
+
+    /**
+     * null if problem, empty list if simply no data
+     * 
+     * Returns highest data when sorted by integer index 0
+     */
+    public static List<UserInfo> getTopUserInfo(int limit)
+    {
+        return delegate.getTopUserInfo(limit);
+    }
+
+    /**
+     * returns null if storage not supported.
+     */
+    public static GreenfootImage getUserImage(String userName)
+    {
+        if (userName == null || userName.equals("")) {
+            userName = getUserName();
+        }
+        
+        GreenfootImage r = null;
+        
+        if (userName != null) {
+            r = delegate.getUserImage(userName);
+        }
+        
+        if (r == null)
+        {
+            // This can be because there was a problem reading from the gallery,
+            // or because we're using local storage:
+            r = new GreenfootImage(50, 50);
+            r.setColor(java.awt.Color.DARK_GRAY);
+            r.fill();
+            
+            final int CHARS_PER_LINE = 6; // Heuristic: 15 pixels high, assume 8 pixels width per char, 50 / 8 ~= 6
+            
+            StringBuilder wrappedName = new StringBuilder();
+            if (userName == null)
+                userName = "";
+            for (int i = 0 ;i < userName.length(); i += CHARS_PER_LINE)
+                wrappedName.append(userName.substring(i, Math.min(userName.length(), i + CHARS_PER_LINE))).append("\n");
+                    
+            GreenfootImage textImage = new GreenfootImage(wrappedName.toString(), 15, java.awt.Color.WHITE, java.awt.Color.DARK_GRAY);
+            r.drawImage(textImage, Math.max(0, (50 - textImage.getWidth()) / 2), Math.max(0, (50 - textImage.getHeight()) / 2));
+        }
+        // Should never return null:
+        return r;
+    }
+
+    // For local storage, this is the username set via the IDE
+    // For remote storage, this is the username got from the applet params
+    // For turned off, this is null
+    public static String getUserName()
+    {
+        return delegate.getUserName();
+    }
+
+    /**
+     * Get info for users near the current player when sorted by score
+     * 
+     * @return  null if problem, empty list if simply no data.
+     */
+    public static List<UserInfo> getNearbyUserData(int maxAmount)
+    {
+        return delegate.getNearbyUserInfo(maxAmount);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/HDTimer.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/HDTimer.java
new file mode 100644
index 0000000000000000000000000000000000000000..807d2a202cb51bb9ac2eb7c012967e9b7e89d8d1
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/HDTimer.java
@@ -0,0 +1,246 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+
+/**
+ * Timer to do high precision sleeps and waits.
+ * 
+ * @author Poul Henriksen
+ */
+public class HDTimer
+{
+    private static Long sleepPrecision;
+    private static long worstYieldTime;
+    private static boolean inited;
+    private static Long waitPrecision;
+
+    static {
+        init();
+    }
+
+    public synchronized static void init()
+    {
+        if (!inited) {
+            measureSleepPrecision();
+            measureWaitPrecision();
+            inited = true;
+        }
+    }
+
+    private static void measureSleepPrecision()
+    {
+        int testSize = 11;
+        List<Long> tests = new ArrayList<Long>();
+
+        try {
+            for (int i = 0; i < testSize; i++) {
+                long t1 = System.nanoTime();
+                Thread.sleep(0, 1);
+                long t2 = System.nanoTime();
+                tests.add((t2 - t1));
+            }
+        }
+        catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        Collections.sort(tests);
+        sleepPrecision = tests.get(testSize / 2);
+    }
+
+    private static void measureWaitPrecision()
+    {
+        int testSize = 11;
+        List<Long> tests = new ArrayList<Long>();
+        Object lock = new Object();
+        try {
+            synchronized (lock) {
+                for (int i = 0; i < testSize; i++) {
+                    long t1 = System.nanoTime();
+                    lock.wait(0, 1);
+                    long t2 = System.nanoTime();
+                    tests.add((t2 - t1));
+                }
+            }
+        }
+        catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        Collections.sort(tests);
+        waitPrecision = tests.get(testSize / 2);
+    }
+
+    /**
+     * Sleep for the specified amount of time.
+     * 
+     * @param nanos
+     *            Time to wait in nanoseconds.
+     * @throws InterruptedException
+     *             if another thread has interrupted the current thread
+     */
+    public static void sleep(long nanos)
+        throws InterruptedException
+    {
+        long tStart = System.nanoTime();
+        sleepFromTime(nanos, tStart);
+    }
+
+    /**
+     * Sleep for the specified amount of time.
+     * 
+     * @param nanos
+     *            Time to wait in nanoseconds.
+     * @param tStart The tiem from which the wainting should start.
+     * 
+     * @throws InterruptedException
+     *             if another thread has interrupted the current thread
+     */
+    private static void sleepFromTime(long nanos, long tStart)
+        throws InterruptedException
+    {
+        long sleepNanos = nanos - sleepPrecision;
+
+        // First, use Java's Thread.sleep() if it is precise enough
+        if (nanos / sleepPrecision >= 2) {
+            long actualDelayMillis = (sleepNanos) / 1000000L;
+            int nanoRest = (int) (sleepNanos % 1000000L);
+            if(Thread.interrupted()) {
+                throw new InterruptedException("HDTimer.sleepFromTime interrupted in sleep.");
+            }
+            Thread.sleep(actualDelayMillis, nanoRest);
+        }
+
+        // Second, yield in a busy loop if precise enough
+        while ((System.nanoTime() - tStart + worstYieldTime) < nanos) {
+            long t1 = System.nanoTime();
+            if(Thread.interrupted()) {
+                throw new InterruptedException("HDTimer.sleepFromTime interrupted in yield.");
+            }
+            Thread.yield();
+            long yieldTime = System.nanoTime() - t1;
+            if (yieldTime > worstYieldTime) {
+                worstYieldTime = yieldTime;
+            }
+        }
+
+        // Third, run a busy loop for the rest of the time
+        while ((System.nanoTime() - tStart) < nanos) {
+            if(Thread.interrupted()) {
+                throw new InterruptedException("HDTimer.sleepFromTime interrupted in busy loop.");
+            }
+        }
+    }
+
+    /**
+     * Wait for the specified amount of time. This method will hold and release
+     * the lock for a while. As opposed to Object.wait(), this method will not
+     * finish when the lock is receives a notify or notifyAll, but will instead
+     * continue waiting.
+     * 
+     * This method is less precise than sleep, since it always has to invoke
+     * Object.wait() to release the lock and is hence limited by the precision
+     * of wait.
+     * 
+     * @deprecated Use {@link #wait(long, WriteLock)}
+     * @param nanos
+     *            Time to wait in nanoseconds.
+     * @throws InterruptedException
+     *             if another thread has interrupted the current thread
+     */
+    public static void wait(long nanos, Object lock)
+        throws InterruptedException
+    {
+        long tStart = System.nanoTime();
+
+        // First, use Java's Object.wait()
+        long waits = 0;
+        while ((System.nanoTime() - tStart ) < (nanos  - waitPrecision) || waits == 0) {
+            long waitNanos = tStart - System.nanoTime() - waitPrecision;
+            
+            long actualDelayMillis = (waitNanos) / 1000000L;
+            int nanoRest = (int) (waitNanos % 1000000L);
+            if (actualDelayMillis <= 0 && nanoRest <= 0) {
+                // NEVER wait a length of 0 or less, because that is the same as
+                // infinite wait.
+                actualDelayMillis = 0;
+                nanoRest = 1;
+            }
+            synchronized (lock) {
+                lock.wait(actualDelayMillis, nanoRest);
+                waits++;
+            }
+        }
+        //long waited = System.nanoTime() - tStart;
+        
+        // Second, yield in a busy loop if precise enough
+        while ((System.nanoTime() - tStart + worstYieldTime) < nanos) {
+            long t1 = System.nanoTime();
+            Thread.yield();
+            long yieldTime = System.nanoTime() - t1;
+            if (yieldTime > worstYieldTime) {
+                worstYieldTime = yieldTime;
+            }
+        }
+
+        // Third, run a busy loop for the rest of the time
+        while ((System.nanoTime() - tStart) < nanos) ;
+    }
+    
+    /**
+     * Wait for the specified amount of time. This method will release the lock
+     * (if it is currently held) for some time while waiting. As opposed to
+     * Object.wait(), this method will not finish when the lock receives a
+     * notify or notifyAll, but will instead continue waiting.
+     * 
+     * 
+     * @param nanos Time to wait in nanoseconds.
+     * @param lock The lock to release while waiting.
+     * @throws InterruptedException if another thread has interrupted the
+     *             current thread
+     */
+    public static void wait(long nanos, ReentrantReadWriteLock lock)
+        throws InterruptedException
+    {
+        long tStart = System.nanoTime();
+        if(!lock.isWriteLockedByCurrentThread()) {
+            // We do not hold the lock, so just sleep
+            sleepFromTime(nanos, tStart);
+            return;
+        }
+            
+        // We can release the lock until we are finished sleeping
+        lock.writeLock().unlock();
+        try {
+            sleepFromTime(nanos, tStart);
+        }
+        finally {
+            // Note we must NOT lock interruptibly - we must ensure the
+            // lock is regained before returning.
+            lock.writeLock().lock();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Location.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Location.java
new file mode 100644
index 0000000000000000000000000000000000000000..00787695daa76d491f474b4a02fe70bc1d584aba
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Location.java
@@ -0,0 +1,109 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+/**
+ * A location in integers
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: Location.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class Location
+    implements Cloneable
+{
+    private int x;
+    private int y;
+
+    public Location()
+    {
+        x = 0;
+        y = 0;
+    }
+
+    public Location(int x, int y)
+    {
+        this.x = x;
+        this.y = y;
+    }
+
+    public int getX()
+    {
+        return x;
+    }
+
+    public int getY()
+    {
+        return y;
+    }
+
+    public void setX(int x)
+    {
+        this.x = x;
+    }
+
+    public void setY(int y)
+    {
+        this.y = y;
+    }
+
+    /**
+     * Multiplies the location with the parameters.
+     * 
+     * @param xMappingScale
+     * @param yMappingScale
+     */
+    public void scale(int xMappingScale, int yMappingScale)
+    {
+        x *= xMappingScale;
+        y *= yMappingScale;
+    }
+
+    public Object clone()
+    {
+        Object o = null;
+        try {
+            o = super.clone();
+        }
+        catch (CloneNotSupportedException e) {}
+        return o;
+    }
+
+    /**
+     * Adds the parameters to the location.
+     * 
+     * @param dx
+     * @param dy
+     */
+    public void add(int dx, int dy)
+    {
+        x += dx;
+        y += dy;
+    }
+
+    public String toString()
+    {
+        String s = super.toString();
+        s = s + " (" + getX() + ", " + getY() + ")";
+        return s;
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Selectable.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Selectable.java
new file mode 100644
index 0000000000000000000000000000000000000000..c35717b788e984c6c9db9f6300a45395b50fd18c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Selectable.java
@@ -0,0 +1,33 @@
+/*
+ This file is part of the Greenfoot program.
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ This file is subject to the Classpath exception as provided in the
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+/**
+ * Interface for classes in which items can be selected.
+ */
+public interface Selectable<T>
+{
+    /**
+     * Should select the given argument.
+     */ 
+    public void select(T o);
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/ShadowRenderer.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/ShadowRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..71b18620e8a58b53e6992b2888ca5bf97b33f269
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/ShadowRenderer.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2007, Romain Guy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of the TimingFramework project nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package greenfoot.util;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+
+/**
+ * Class to create drop shadows for images.
+ * <p>
+ * 
+ * The implementation in this class is taken from the DropShadowDemo in the StaticEffects project by Romain Guy.
+ * 
+ * @author Poul Henriksen
+ */
+public class ShadowRenderer
+{
+
+    /**
+     * <p>A shadow renderer needs three properties to generate shadows.
+     * These properties are:</p> 
+     * <ul>
+     *   <li><i>size</i>: The size, in pixels, of the shadow. This property also
+     *   defines the fuzzyness.</li>
+     *   <li><i>opacity</i>: The opacity, between 0.0 and 1.0, of the shadow.</li>
+     *   <li><i>color</i>: The color of the shadow. Shadows are not meant to be
+     *   black only.</li>
+     * </ul>
+     * @param image the image to create a drop shadow for.
+     * @param size the size of the shadow in pixels. Defines the fuzziness.
+     * @param opacity the opacity of the shadow.
+     * @param color the color of the shadow.
+     */
+    public static BufferedImage createDropShadow(BufferedImage image, int size, float opacity, Color color)
+    {
+        BufferedImage shadow = new BufferedImage(image.getWidth() + 4 * size, image.getHeight() + 4 * size,
+                BufferedImage.TYPE_INT_ARGB);
+
+        Graphics2D g2 = shadow.createGraphics();
+        g2.drawImage(image, size * 2, size * 2, null);
+
+        g2.setComposite(AlphaComposite.SrcIn);
+        g2.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), (int) (255f * opacity) ));
+        g2.fillRect(0, 0, shadow.getWidth(), shadow.getHeight());
+
+        g2.dispose();
+
+        shadow = getGaussianBlurFilter(size, true).filter(shadow, null);
+        shadow = getGaussianBlurFilter(size, false).filter(shadow, null);
+
+        return shadow;
+    }
+
+    public static ConvolveOp getGaussianBlurFilter(int radius, boolean horizontal)
+    {
+        if (radius < 1) {
+            throw new IllegalArgumentException("Radius must be >= 1");
+        }
+
+        int size = radius * 2 + 1;
+        float[] data = new float[size];
+
+        float sigma = radius / 3.0f;
+        float twoSigmaSquare = 2.0f * sigma * sigma;
+        float sigmaRoot = (float) Math.sqrt(twoSigmaSquare * Math.PI);
+        float total = 0.0f;
+
+        for (int i = -radius; i <= radius; i++) {
+            float distance = i * i;
+            int index = i + radius;
+            data[index] = (float) Math.exp(-distance / twoSigmaSquare) / sigmaRoot;
+            total += data[index];
+        }
+
+        for (int i = 0; i < data.length; i++) {
+            data[i] /= total;
+        }
+
+        Kernel kernel = null;
+        if (horizontal) {
+            kernel = new Kernel(size, 1, data);
+        }
+        else {
+            kernel = new Kernel(1, size, data);
+        }
+        return new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/StandalonePropStringManager.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/StandalonePropStringManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..e647246dfe5222e3397fdb4c282c0194c1394659
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/StandalonePropStringManager.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+import bluej.BlueJPropStringSource;
+import java.util.Properties;
+
+
+/**
+ * A standalone reader of property strings for use in exported scenarios
+ * as standalone jar files
+ * 
+ * @author Bruce Quig
+ */
+public class StandalonePropStringManager implements BlueJPropStringSource
+{
+    private Properties values;
+    
+    public StandalonePropStringManager(Properties props)
+    {
+        values = props;
+    }
+
+    public String getBlueJPropertyString(String property, String def)
+    {
+       return values.getProperty(property, def);
+    }
+
+    public String getLabel(String key)
+    {
+        return values.getProperty(key, key);
+    }
+
+    public void setUserProperty(String property, String value)
+    {
+        values.setProperty(property, value);
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Version.java b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Version.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a74cf99bd427821b312e9d04439799ce1f16c8c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/greenfoot/util/Version.java
@@ -0,0 +1,222 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package greenfoot.util;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import bluej.Config;
+
+/**
+ * Represents a version number. A version is a sequence of numbers separated by
+ * full stops and an optional string at the end.
+ * 
+ * @author Poul Henriksen
+ * 
+ */
+public class Version
+{
+    /**
+     * A change in this number indicates a breaking change that will be likely
+     * to break some scenarios.
+     */
+    private int breakingNumber;
+
+    /**
+     * A change in this number indicates a visible (to the user) change that
+     * should not break anything in most cases.
+     */
+    private int nonBreakingNumber;
+
+    /** A change in this number indicates an internal change only. */
+    private int internalNumber;
+
+    /** The version number was bad or non-existent */
+    private boolean badVersion = false;
+
+    /**
+     * Create a new Version from the string.
+     * 
+     * @param versionString A string in the format X.Y.Z. If the string is null
+     *            or invalid, it will be flagged and can be determined by
+     *            calling {@link #isBad()}.
+     */
+    public Version(String versionString)
+    {
+        if (versionString == null) {
+            badVersion = true;
+            return;
+        }
+
+        String[] split = versionString.split("\\.");
+        List<Integer> numbers = new ArrayList<Integer>();
+
+        String lastString = null;
+        for (String s : split) {
+            try {
+                numbers.add(Integer.valueOf(Integer.parseInt(s)));
+            }
+            catch (NumberFormatException nfe) {
+                lastString = s;
+                break;
+            };
+        }
+
+        // Make sure to handle the last number - even if there is something
+        // after it, like an extra string.
+        if (numbers.size() < 3 && lastString != null) {
+            // split around any sequence of non-digits.
+            String[] endSplit = lastString.split("[^0-9]+");
+            // The first element of the array now contains a number
+            if (endSplit.length > 0) {
+                String candidate = endSplit[0];
+                // if the candidate number is matching the beginning, we have
+                // found a part of the version number.
+                if (lastString.startsWith(candidate)) {
+                    numbers.add(Integer.valueOf(Integer.parseInt(candidate)));
+                }
+            }
+        }
+
+        if (numbers.size() == 3) {
+            breakingNumber = numbers.get(0);
+            nonBreakingNumber = numbers.get(1);
+            internalNumber = numbers.get(2);
+        }
+        else {
+            badVersion = true;
+        }
+    }
+
+    /**
+     * True if this version number is older than the other version number in a
+     * way that will be likely to break some scenarios. Or if any of the
+     * versions is a bad version number.
+     * 
+     */
+    public boolean isOlderAndBreaking(Version other)
+    {
+        return this.breakingNumber < other.breakingNumber || this.badVersion || other.badVersion;
+    }
+
+    /**
+     * True if this version number is different than the other version number in
+     * a way that will be unlikely to break scenarios. Or if any of the versions
+     * is a bad version number.
+     */
+    public boolean isNonBreaking(Version other)
+    {
+        return this.nonBreakingNumber != other.nonBreakingNumber || this.badVersion || other.badVersion;
+    }
+
+    /**
+     * True if this version number is different than the other version number
+     * but will only contain in internal changes and will not break scenarios.
+     * Or if any of the versions is a bad version number.
+     * 
+     */
+    public boolean isInternal(Version other)
+    {
+        return this.internalNumber != other.internalNumber || this.badVersion || other.badVersion;
+    }
+
+    /**
+     * True if the version number was not correctly formated.
+     * 
+     */
+    public boolean isBad()
+    {
+        return badVersion;
+    }
+
+    /**
+     * Returns the version in the format X.Y.Z.
+     */
+    public String toString()
+    {
+        return breakingNumber + "." + nonBreakingNumber + "." + internalNumber;
+    }
+
+    /**
+     * Return a message that shows the changes introduced in apiVersion compared to this version.
+     * 
+     * @param apiVersion The API version that for which the changes should be shown.
+     * @return
+     */
+    public String getChangesMessage(Version apiVersion)
+    {
+        StringBuffer message = new StringBuffer(Config.getString("project.version.older.part1") + this
+                + Config.getString("project.version.older.part2") + apiVersion
+                + Config.getString("project.version.older.part3") + "\n");
+        
+        int changeNumber = 1;
+        String changesString = Config.getString("project.version.changes." + changeNumber, "EMPTY").trim();
+        
+        while(!changesString.equals("EMPTY")) {
+            int spaceIndex = changesString.indexOf(' ');
+            if(spaceIndex < 5) {
+                // Incorrect version number format
+                return "";
+            }
+            String versionString = changesString.substring(0,spaceIndex);
+            Version changeVersion = new Version(versionString);
+            if(this.isOlderAndBreaking(changeVersion)) {
+                String text = changesString.substring(spaceIndex + 1);  
+                message.append("\n \n  " + text);
+            }
+            changeNumber++;
+            changesString = Config.getString("project.version.changes." + changeNumber, "EMPTY");
+        }
+        
+
+        return message.toString();
+    }
+
+    /**
+     * This will return a message about the version being VERY old (before we
+     * introduced version numbers). This is very unlikely to ever be used.
+     * 
+     */
+    public String getBadMessage()
+    {
+        return Config.getString("project.version.none");
+    }
+
+    /**
+     * Return a message that says that this project is a newer version.
+     */
+    public String getNewerMessage()
+    {
+        return Config.getString("project.version.newer.part1") + this
+        + Config.getString("project.version.newer.part2");
+    }
+
+    /**
+     * Get message if this is not a Greenfoot version number.
+     */
+    public String getNotGreenfootMessage(File projectDir)
+    {
+        return Config.getString("project.version.notGreenfoot") + projectDir;
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/BlueJRMIClient.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/BlueJRMIClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..e945c3a5a91ea606bd6ce4b0e9505b176d2533b9
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/BlueJRMIClient.java
@@ -0,0 +1,157 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+
+import rmiextension.wrappers.RBlueJ;
+import rmiextension.wrappers.RPackage;
+import rmiextension.wrappers.RProject;
+import bluej.BlueJPropStringSource;
+import bluej.Config;
+import bluej.extensions.ProjectNotOpenException;
+
+/**
+ * The RMI client that establishes the initial connection to the BlueJ RMI server
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class BlueJRMIClient implements BlueJPropStringSource
+{
+    RBlueJ blueJ = null;
+    private static BlueJRMIClient instance;
+
+    private RPackage pkg;
+    private String prjDir;
+    
+    public BlueJRMIClient(String prjDir, String rmiServiceName)
+    {
+        BlueJRMIServer.forceHostForServer();
+        instance = this;
+        this.prjDir = prjDir;
+
+        try {
+            URI uri = new URI(rmiServiceName);
+            String path = uri.getPath().substring(1); // strip leading '/'
+            String host = uri.getHost();
+            int port = uri.getPort();
+            Registry reg = LocateRegistry.getRegistry(host, port, new LocalSocketFactory());
+            blueJ = (RBlueJ) reg.lookup(path);
+        }
+        catch (URISyntaxException use) {
+            use.printStackTrace();
+        }
+        catch (RemoteException e) {
+            e.printStackTrace();
+        }
+        catch (NotBoundException e) {
+            e.printStackTrace();
+        }
+
+    }
+    
+    /**
+     * Perform initialisation (which involves calling back into the other VM).
+     */
+    public void initialise()
+    {
+        if (blueJ != null) {
+            try {
+                RProject[] openProjects = blueJ.getOpenProjects();
+                RProject prj = null;
+                for (int i = 0; i < openProjects.length; i++) {
+                    prj = openProjects[i];
+                    File passedDir = new File(prjDir);
+                    if (prj.getDir().equals(passedDir)) {
+                        break;
+                    }
+                }
+                pkg = prj.getPackage("");
+
+            }
+            catch (RemoteException e1) {
+                e1.printStackTrace();
+            }
+            catch (ProjectNotOpenException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public static BlueJRMIClient instance()
+    {
+        return instance;
+    }
+
+    /**
+     * Returns the remote BlueJ instance.
+     */
+    public RBlueJ getBlueJ()
+    {
+        return blueJ;
+    }
+    
+    /**
+     * Returns the remote BlueJ package.
+     */
+    public RPackage getPackage()
+    {
+        return pkg;
+    }
+    
+    // Implementation for "BlueJPropStringSource" interface
+    
+    @Override
+    public String getBlueJPropertyString(String property, String def)
+    {
+        try {
+            String val = blueJ.getExtensionPropertyString(property, null);
+            if (val == null)
+                val = blueJ.getBlueJPropertyString(property, def);
+            return val;
+        }
+        catch (RemoteException re) {
+            return def;
+        }
+    }
+
+    @Override
+    public String getLabel(String key)
+    {
+        return Config.getString(key, key);
+    }
+    
+    @Override
+    public void setUserProperty(String property, String val)
+    {
+        try {
+            blueJ.setExtensionPropertyString(property, val);
+        }
+        catch (RemoteException re) {}
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/BlueJRMIServer.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/BlueJRMIServer.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c357eb3f0289bd10408955ffd2c0de388a54e4b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/BlueJRMIServer.java
@@ -0,0 +1,172 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.rmi.Naming;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.security.Permission;
+
+import rmiextension.wrappers.RBlueJ;
+import rmiextension.wrappers.RBlueJImpl;
+import bluej.extensions.BlueJ;
+import bluej.utility.Debug;
+
+/**
+ * Starts the registry and BlueJ-service.
+ * <p>
+ * To support multiple instances of greenfoot running at the same time the
+ * registry will be started on a random free port.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class BlueJRMIServer
+{
+    private final static String HOST = "127.0.0.1";
+    private final static String BLUEJ_SERVICE = "BlueJService";
+    private static int port;
+
+    /** How many unsuccessful attempts that have been made to start the registry */
+    private int registryStartAttempts = 0;
+    /** How many time to we retry before giving up */
+    private static final int MAX_REGISTRY_START_ATTEMPTS = 10;
+    
+    private static final LocalSocketFactory socketFactory = new LocalSocketFactory();
+
+    /**
+     * Returns the BlueJ service.
+     * <p>
+     * Can only be called after the registry has been started.
+     * 
+     * @return URL containing host, port and service name.
+     */
+    public static String getBlueJService()
+    {
+        if (port == 0) {
+            throw new IllegalStateException("Registry not started.");
+        }
+        return "//" + HOST + ":" + port + "/" + BLUEJ_SERVICE;
+    }
+    
+    /**
+     * Make sure that the localhost is used for the server. If this is not done,
+     * RMI will use the outgoing IP address if there is one, and losing this IP
+     * address will make RMI calls impossible and hence lock up Greenfoot.
+     */
+    public static void forceHostForServer()
+    {
+        System.setProperty("java.rmi.server.hostname", HOST);
+    }
+
+    /**
+     * Creates a new RMI server and exports the argument as a BlueJService. The
+     * registry will be started on a free port, NOT the default RMI port.
+     * 
+     * @throws IOException If for some reason the server could not be created.
+     */
+    public BlueJRMIServer(BlueJ blueJ)
+        throws IOException
+    {
+        if (System.getSecurityManager() == null) {
+            // If there's no security manager, the registry will
+            // (stupidly) refuse to load classes from the class path
+            // that aren't visible to the system class loader.
+            System.setSecurityManager(new SecurityManager() {
+                public void checkPermission(Permission perm) {
+                    // super.checkPermission(perm);
+                    return;
+                }
+
+                public void checkPermission(Permission perm, Object context) {
+                    // super.checkPermission(perm, context);
+                    return;
+                }
+            });
+        }
+        
+        startRegistry();
+        blueJ.addPackageListener(ProjectManager.instance());
+        RBlueJ rBlueJ = new RBlueJImpl(blueJ);
+        Naming.rebind(getBlueJService(), rBlueJ);
+    }
+
+    /**
+     * Starts the registry.
+     * 
+     * @throws IOException If the registry could not be started - even after
+     *             several retries.
+     */
+    private void startRegistry()
+        throws IOException
+    {
+        forceHostForServer();
+        boolean success = false;
+        while (!success && registryStartAttempts < MAX_REGISTRY_START_ATTEMPTS) {
+            try {
+                port = getFreePort();
+            }
+            catch (IOException e1) {
+                //
+                Debug.reportError("Could not obtain a free port number. Attempt number: " + registryStartAttempts);
+                e1.printStackTrace();
+                registryStartAttempts++;
+                continue;
+            }
+
+            try {
+                LocateRegistry.createRegistry(port, socketFactory, socketFactory);
+                success = true;
+            }
+            catch (RemoteException re) {
+                // One reason could be that the port that was reported as free
+                // is no longer free.
+                Debug.reportError("Could not start registry. Attempt number: " + registryStartAttempts);
+                re.printStackTrace();
+                registryStartAttempts++;
+                continue;
+            }
+        }
+        if (!success) {
+            throw new IOException("Could not start the registry.");
+        }
+    }
+
+    /**
+     * Gets a port that is currently unused. When using the returned port, it
+     * might no longer be free so appropiate exception handling should be in
+     * place.
+     * 
+     * @return A free port number.
+     * @throws IOException If something goes wrong when trying to obtain a free
+     *             port number.
+     */
+    private int getFreePort()
+        throws IOException
+    {
+        ServerSocket s = new ServerSocket(0);
+        int freePort = s.getLocalPort();
+        s.close();
+        return freePort;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/ConstructorInvoker.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/ConstructorInvoker.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b8e99c2b9a6d1ded8c74ca5a8d01c0c10a66167
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/ConstructorInvoker.java
@@ -0,0 +1,132 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension;
+
+import java.awt.EventQueue;
+
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.DebuggerResult;
+import bluej.debugmgr.ResultWatcher;
+import bluej.debugmgr.objectbench.ObjectBench;
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.extensions.BPackage;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+
+/**
+ * 
+ * This is an Invoker that can instantiate objects of classes that are NOT a part
+ * of a project.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class ConstructorInvoker
+{
+    private PkgMgrFrame pkgFrame;
+    private String className;
+    private DebuggerResult result;
+
+    public ConstructorInvoker(BPackage bPackage, String className)
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        pkgFrame = (PkgMgrFrame) bPackage.getFrame();
+        this.className = className;
+    }
+   
+    
+    /**
+     * Invoke a constructor which takes String arguments only.
+     * 
+     * @param instanceNameOnObjectBench  Name of the created object as it
+     *                                   should appear on the bench
+     * @param args           Arguments to supply to the constructor; the constructor can
+     *                       only take String parameters
+     * @param resultNotify   A watcher to be notified when the constructor completes
+     *                       (or when execution fails). Notification will occur on the AWT
+     *                       event thread. 
+     */
+    public void invokeConstructor(final String instanceNameOnObjectBench, final String[] args,
+            final ResultWatcher resultWatcher)
+    {
+        final ObjectBench objBench = pkgFrame.getObjectBench();
+        final Package pkg = pkgFrame.getPackage(); 
+        final Debugger debugger = pkgFrame.getProject().getDebugger();
+        
+        Thread t = new Thread() {
+            public void run() {
+                String [] argTypes = new String[args.length];
+                DebuggerObject [] argObjects = new DebuggerObject[args.length];
+                for (int i = 0; i < args.length; i++) {
+                    argTypes[i] = "java.lang.String";
+                    argObjects[i] = debugger.getMirror(args[i]);
+                }
+                
+                result = debugger.instantiateClass(className, argTypes, argObjects);
+                final DebuggerObject debugObject = result.getResultObject();
+                
+                EventQueue.invokeLater(new Runnable() {
+                    @Override
+                    public void run()
+                    {
+                        if (debugObject != null) {
+                            ObjectWrapper wrapper = ObjectWrapper.getWrapper(
+                                    pkgFrame, objBench,
+                                    debugObject,
+                                    debugObject.getGenType(),
+                                    instanceNameOnObjectBench);       
+
+                            objBench.addObject(wrapper);
+                            pkg.getDebugger().addObject(pkg.getQualifiedName(), wrapper.getName(), debugObject);  
+                        }
+                        
+                        if (resultWatcher != null) {
+                            int status = result.getExitStatus();
+                            if (status == Debugger.NORMAL_EXIT) {
+                                resultWatcher.putResult(result.getResultObject(),
+                                        instanceNameOnObjectBench, null);
+                            }
+                            else if (status == Debugger.EXCEPTION) {
+                                resultWatcher.putException(result.getException(), null);
+                            }
+                            else if (status == Debugger.TERMINATED) {
+                                resultWatcher.putVMTerminated(null);
+                            }
+                        }
+                    }
+                });
+            }
+        };
+        
+        t.start();
+    }
+    
+    /**
+     * Get the result from constructor invocation.
+     */
+    public DebuggerResult getResult()
+    {
+        return result;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/GreenfootDebugHandler.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/GreenfootDebugHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..67879d5c1c562f64ee2f6f7daab0e2c10c7c91d7
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/GreenfootDebugHandler.java
@@ -0,0 +1,503 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010,2011,2012 Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension;
+
+import greenfoot.actions.ResetWorldAction;
+import greenfoot.core.Simulation;
+import greenfoot.core.SimulationDebugMonitor;
+
+import java.awt.EventQueue;
+import java.rmi.RemoteException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import rmiextension.wrappers.RProjectImpl;
+import rmiextension.wrappers.WrapperPool;
+import bluej.debugger.Debugger;
+import bluej.debugger.DebuggerClass;
+import bluej.debugger.DebuggerEvent;
+import bluej.debugger.DebuggerEvent.BreakpointProperties;
+import bluej.debugger.DebuggerField;
+import bluej.debugger.DebuggerListener;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.DebuggerThread;
+import bluej.debugger.SourceLocation;
+import bluej.debugmgr.Invoker;
+import bluej.extensions.BProject;
+import bluej.extensions.ExtensionBridge;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.pkgmgr.Project;
+import bluej.utility.Debug;
+import bluej.utility.JavaNames;
+
+/**
+ * A class that does several things:
+ * 
+ * <p>Firstly, it listens for the debugger terminating the Greenfoot VM, and relaunches Greenfoot.
+ * 
+ * <p>Secondly, it tries to make sure that the debugger never stops the code
+ * entirely outside the user's code (i.e. there should always be some user code
+ * somewhere in the call stack) 
+ * 
+ * @author Neil Brown
+ */
+public class GreenfootDebugHandler implements DebuggerListener
+{  
+    private static final String SIMULATION_CLASS = Simulation.class.getName();   
+    private static final String[] INVOKE_METHODS = {Simulation.ACT_WORLD, Simulation.ACT_ACTOR,
+            Simulation.NEW_INSTANCE, Simulation.RUN_QUEUED_TASKS};
+    private static final String SIMULATION_INVOKE_KEY = SIMULATION_CLASS + "INTERNAL";
+    
+    private static final String PAUSED_METHOD = Simulation.PAUSED;
+    private static final String SIMULATION_THREAD_PAUSED_KEY = "SIMULATION_THREAD_PAUSED"; 
+        
+    private static final String SIMULATION_THREAD_RUN_KEY = "SIMULATION_THREAD_RUN";
+    
+    private static final String RESET_CLASS = ResetWorldAction.class.getName();
+    private static final String RESET_METHOD = ResetWorldAction.RESET_WORLD;
+    private static final String RESET_KEY = "RESET_WORLD";
+    
+    private BProject project;
+    private DebuggerThread simulationThread;
+    private DebuggerClass simulationClass;
+    
+    private boolean currentlyResetting;
+    
+    private GreenfootDebugHandler(BProject project)
+    {
+        this.project = project;
+    }
+        
+    /**
+     * This is the publicly-visible way to add a debugger listener for a particular project.    
+     */
+    static void addDebuggerListener(BProject project)
+    {
+        try {
+            Project proj = Project.getProject(project.getDir());
+
+            // Technically I could collapse the two listeners into one, but they
+            // perform orthogonal tasks so it's nicer to keep the code separate:
+            GreenfootDebugHandler handler = new GreenfootDebugHandler(project);
+            int mstate = proj.getDebugger().addDebuggerListener(handler);
+            proj.getDebugger().addDebuggerListener(handler.new GreenfootDebugControlsLink());
+            if (mstate == Debugger.IDLE) {
+                // The VM may have already started by the time the listener was added. If so,
+                // we need to kick off Greenfoot on the other VM here:
+                handler.addRunResetBreakpoints(proj.getDebugger());
+                ProjectManager.instance().openGreenfoot(project);
+            }
+        } catch (ProjectNotOpenException ex) {
+            Debug.reportError("Project not open when adding debugger listener in Greenfoot", ex);
+        }
+    }
+
+    private void addRunResetBreakpoints(Debugger debugger)
+    {
+        try {
+            // We have to initialise the class; the IBM JDK otherwise throws an ObjectCollectedException
+            // exception, seemingly in error.
+            simulationClass = debugger.getClass(SIMULATION_CLASS, true);
+
+            Map<String, String> simulationRunBreakpointProperties = new HashMap<String, String>();
+            simulationRunBreakpointProperties.put(SIMULATION_THREAD_RUN_KEY, "TRUE");
+            simulationRunBreakpointProperties.put(Debugger.PERSIST_BREAKPOINT_PROPERTY, "TRUE");
+            debugger.toggleBreakpoint(simulationClass, "run", true, simulationRunBreakpointProperties);
+
+            Map<String, String> resetBreakpointProperties = new HashMap<String, String>();
+            resetBreakpointProperties.put(RESET_KEY, "yes");
+            resetBreakpointProperties.put(Debugger.PERSIST_BREAKPOINT_PROPERTY, "TRUE");
+            debugger.toggleBreakpoint(RESET_CLASS, RESET_METHOD, true, resetBreakpointProperties);
+        }
+        catch (ClassNotFoundException cnfe) {
+            Debug.reportError("Simulation class could not be located. Possible installation problem.", cnfe);
+        }
+    }
+    
+    private boolean isSimulationThread(DebuggerThread dt)
+    {
+        return dt != null && simulationThread != null && simulationThread.sameThread(dt);
+    }
+    
+    /**
+     * An early examination of the debugger event (gets called before processDebuggerEvent)
+     * 
+     * This method is responsible for checking where the debugger has stopped (if it has),
+     * and deciding whether it should be run on for a bit until it reaches user code.
+     * 
+     * This method does not actually run it on; see the comments on the scheduledTasks field
+     * at the top of the class for how it works.
+     */
+    @Override
+    public boolean examineDebuggerEvent(final DebuggerEvent e)
+    {
+        final Debugger debugger = (Debugger)e.getSource();
+        List<SourceLocation> stack = e.getThread().getStack();
+        
+        if (e.getID() == DebuggerEvent.THREAD_BREAKPOINT
+            && e.getThread() != null &&
+            e.getBreakpointProperties().get(SIMULATION_THREAD_RUN_KEY) != null) {
+            // This is the breakpoint at the very beginning of the simulation thread;
+            // record this thread as being the simulation thread and set it running again:
+            simulationThread = e.getThread();
+            try {
+                RProjectImpl rproj = WrapperPool.instance().getWrapper(project);
+                rproj.setSimulationThread(simulationThread);
+            }
+            catch (RemoteException re) {
+                Debug.reportError("Unexpected exception getting project wrapper: ", re);
+            }
+            e.getThread().cont();
+            return true;
+            
+        } else if (e.getID() == DebuggerEvent.THREAD_BREAKPOINT
+                && atResetBreakpoint(e.getBreakpointProperties())) {
+            // The user has clicked reset:
+            currentlyResetting = true;
+            
+            setSpecialBreakpoints(debugger);
+            // Set the simulation thread going if it's suspended:
+            if (simulationThread.isSuspended()) {
+                simulationThread.cont();
+            }
+
+            EventQueue.invokeLater(new Runnable() {
+                public void run()
+                {
+                    try {
+                        ExtensionBridge.clearObjectBench(project);
+                    }
+                    catch (ProjectNotOpenException e) { }
+
+                    // Run the GUI thread on:
+                    e.getThread().cont();
+                };
+            });
+            
+            return true;
+        } else if (e.isHalt() && isSimulationThread(e.getThread())) {
+            if (atPauseBreakpoint(e.getBreakpointProperties())) {
+                // They are going to pause; remove all special breakpoints and set them going
+                // (so that they actually hit the pause):
+                debugger.removeBreakpointsForClass(SIMULATION_CLASS);
+                e.getThread().cont();
+                // We also hit pause when a reset has completed:
+                currentlyResetting = false;
+                return true;
+            } else if (currentlyResetting) {
+                // Run through all breakpoints:
+                e.getThread().cont();
+                return true;
+            } else if (insideUserCode(stack)) {
+                // They are in an act method, make sure the breakpoints are cleared:
+                
+                // This method can be safely invoked without needing to talk to the worker thread:
+                debugger.removeBreakpointsForClass(SIMULATION_CLASS);
+                        
+                // If they have just hit the breakpoint and are in InvokeAct itself,
+                // step-into the World/Actor:
+                if (atInvokeBreakpoint(e.getBreakpointProperties())) {
+                    e.getThread().stepInto();
+                    return true;
+                } else if (inInvokeMethods(stack, 0)) {
+                    // Finished calling act() and have stepped out; run to next one:
+                    runToInternalBreakpoint(debugger, e.getThread());
+                    return true;                    
+                } //otherwise they are in their own code
+            } else  {
+                if (inPauseMethod(stack)) {
+                    // They are paused, just set them running again and forget it:
+                    e.getThread().cont();
+                } else {
+                    // They are not in an act() method and not paused; run until they get to an act() method:
+                    runToInternalBreakpoint(debugger, e.getThread());
+                }
+                return true;
+            }
+        }
+
+        return false;
+    }
+    
+    /**
+     * Processes a debugger event.  This is called after examineDebuggerEvent, with a second
+     * parameter that effectively corresponds to the return result of examineDebuggerEvent.
+     * 
+     * <p>Thus, if the parameter is true, we look for a scheduled task to run.
+     * 
+     * <p>We call threadHalted if necessary.
+     */
+    @Override
+    public void processDebuggerEvent(final DebuggerEvent e, boolean skipUpdate)
+    {
+        if (e.getNewState() == Debugger.IDLE && e.getOldState() == Debugger.NOTREADY) {
+            if (! ProjectManager.checkLaunchFailed()) {
+                //It is important to have this code run at a later time.
+                //If it runs from this thread, it tries to notify the VM event handler,
+                //which is currently calling us and we get a deadlock between the two VMs.
+                EventQueue.invokeLater(new Runnable() {
+                    public void run()
+                    {
+                        addRunResetBreakpoints((Debugger) e.getSource());
+                        ProjectManager.instance().openGreenfoot(project);
+                    }
+                });
+            }
+        }
+    }
+
+    /**
+     * Runs the debugger on until it hits the special invoke-act breakpoints that occur
+     * just before user code might be encountered.  This method doesn't actually check if you're
+     * thereabouts already, so it should be only called once you've checked that you actually
+     * want to run onwards.
+     * 
+     * Returns a task that will run them onwards, which can be scheduled as you like
+     */
+    private void runToInternalBreakpoint(final Debugger debugger, final DebuggerThread thread)
+    {
+        // Set a break point where we want them to be:
+        setSpecialBreakpoints(debugger);
+
+        // Then set them running again:
+        thread.cont();
+    }
+    
+    /**
+     * Works out if we are currently in a call to the World or Actor act() methods
+     * by looking in the call stack for them. Strictly speaking, we might not be
+     * truly inside the user code: it might be we are about to enter or have just
+     * left the act() method. It is only valid to call this for the simulation
+     * thread.
+     */
+    private static boolean insideUserCode(List<SourceLocation> stack)
+    {
+        for (int i = 0; i < stack.size();i++) {
+            if (inInvokeMethods(stack, i)) {
+                return true;
+            }
+        }
+        return false;
+    }
+   
+    /**
+     * Works out if the specified frame in the call-stack is in one of the special invoke-act
+     * methods that call the World and Actor's act() methods or the method that runs
+     * other user code on the simulation thread 
+     */
+    private static boolean inInvokeMethods(List<SourceLocation> stack, int frame)
+    {
+        if (frame < stack.size()) {
+            String className = stack.get(frame).getClassName();
+            if (className.equals(SIMULATION_CLASS)) {
+                String methodName = stack.get(frame).getMethodName();
+                for (String actMethod : INVOKE_METHODS) {
+                    if (actMethod.equals(methodName)) {
+                        return true;
+                    }
+                }
+            }
+            else if (JavaNames.getBase(className).startsWith(Invoker.SHELLNAME)) {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Works out if they are at the breakpoint triggered by the user clicking
+     * the Reset button.
+     */
+    private static boolean atResetBreakpoint(BreakpointProperties props)
+    {
+        return props != null && props.get(RESET_KEY) != null;
+    }
+    
+    /**
+     * Works out if they are currently in the Simulation.PAUSED method by looking 
+     * for the special breakpoint property
+     */
+    private static boolean atPauseBreakpoint(BreakpointProperties props)
+    {
+        return props != null && props.get(SIMULATION_THREAD_PAUSED_KEY) != null;
+    }
+    
+    /**
+     * Works out if they are currently paused by looking at the call stack
+     * while they are suspended.
+     */
+    private static boolean inPauseMethod(List<SourceLocation> stack)
+    {
+        for (SourceLocation loc : stack) {
+            if (loc.getClassName().equals(SIMULATION_CLASS) && loc.getMethodName().equals(PAUSED_METHOD)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Checks if the given breakpoint is an invoke breakpoint set by 
+     * the setSpecialBreakpoints call, below  
+     */
+    private static boolean atInvokeBreakpoint(BreakpointProperties props)
+    {
+        return props != null && props.get(SIMULATION_INVOKE_KEY) != null;
+    }
+    
+    /**
+     * Sets breakpoints in the special invoke-act methods that call the World and Actor's
+     * act() methods, and the method that constructs new objects, and the method called when
+     * the simulation will pause.  These breakpoints will thus be encountered immediately before control
+     * would descend into the World and Actor's act() methods or other tasks (i.e. potential user code),
+     * or if the simulation is going to wait for the user to click the controls (e.g. end of an
+     * Act, or because the simulation is now going to be Paused).
+     */
+    private void setSpecialBreakpoints(final Debugger debugger)
+    {
+        for (String method : INVOKE_METHODS) {
+            String err = debugger.toggleBreakpoint(simulationClass, method, true, Collections.singletonMap(SIMULATION_INVOKE_KEY, "yes"));
+            if (err != null) {
+                Debug.reportError("Problem setting special breakpoint: " + err);
+            }
+        }
+        
+        String err = debugger.toggleBreakpoint(simulationClass, PAUSED_METHOD, true, Collections.singletonMap(SIMULATION_THREAD_PAUSED_KEY, "yes"));
+        if (err != null) {
+            Debug.reportError("Problem setting special breakpoint: " + err);
+        }
+    }
+    
+    /**
+     * A second debug listener that only worries about enabling and disabling the
+     * Act/Run/Pause buttons according to whether the Simulation thread is currently at
+     * a breakpoint.
+     */
+    private class GreenfootDebugControlsLink implements DebuggerListener
+    {
+        private LinkedList<String> queuedStateVars = new LinkedList<String>();
+        private Object SEND_EVENT = new Object();
+        private String CLASS_NAME = SimulationDebugMonitor.class.getName();
+        
+        private void simplifyEvents()
+        {
+            // If there is more than one event, it must be made redundant by the latest
+            // event:
+            while (queuedStateVars.size() > 1) {
+                queuedStateVars.removeFirst();
+            }
+        }
+        
+        private class SendNextEvent implements Runnable
+        {
+            private Debugger debugger;
+            
+            public SendNextEvent(Debugger debugger)
+            {
+                this.debugger = debugger;
+            }
+
+            @Override
+            public void run()
+            {
+                // We hold the monitor until the object has been instantiated, to prevent race hazards:
+                synchronized (SEND_EVENT) {
+                    String stateVar;
+                    synchronized (queuedStateVars) {
+                        simplifyEvents();
+                        if (queuedStateVars.isEmpty()) {
+                            return;
+                        }
+                        stateVar = queuedStateVars.removeFirst();
+                    }
+                    try {
+                        DebuggerClass simMonClass = debugger.getClass(CLASS_NAME, true);
+                        DebuggerObject stateObject = null;
+                        for (int i = 0; ; i++) {
+                            DebuggerField simMonField = simMonClass.getStaticField(i);
+                            if (simMonField.getName().equals(stateVar)) {
+                                stateObject = simMonField.getValueObject(null);
+                                break;
+                            }
+                        }
+                        debugger.instantiateClass(CLASS_NAME, new String[] {"java.lang.Object"},
+                                new DebuggerObject[] {stateObject});
+                    } catch (ClassNotFoundException ex) {
+                        Debug.reportError("Could not find internal class " + CLASS_NAME, ex);
+                    }
+                }
+            }
+        }
+        
+        @Override
+        public boolean examineDebuggerEvent(DebuggerEvent e)
+        {
+            return false;
+        }
+
+        @Override
+        public synchronized void processDebuggerEvent(DebuggerEvent e, boolean skipUpdate)
+        {
+            final String stateVar;
+            if (e.isHalt()) {
+                if (isSimulationThread(e.getThread())) {
+                    stateVar = "NOT_RUNNING";
+                }
+                else {
+                    return;
+                }
+            }
+            else if (e.getID() == DebuggerEvent.THREAD_CONTINUE) {
+                if (isSimulationThread(e.getThread())) {
+                    stateVar = "RUNNING";
+                }
+                else {
+                    return;
+                }
+            } else {
+                return;
+            }
+            
+            final Debugger debugger = (Debugger) e.getSource();
+            
+            /* We are on the BlueJ VM, but we need to adjust the state of the buttons
+             * on the Greenfoot VM (aka Debug VM).  We use this slight hack of constructing
+             * an object on the Greenfoot VM that will do the work for us there.
+             * 
+             * For a parameter, we pass one of the static objects that the class holds
+             * (this was more obviously do-able than passing a boolean constant, fix it if you know how)
+             * 
+             * We must do this in a new thread because we'll deadlock if we try to directly
+             * create the object from a debug handler as we are. 
+             */
+
+            synchronized (queuedStateVars) {
+                queuedStateVars.addLast(stateVar);
+                new Thread (new SendNextEvent(debugger)).start();
+            }                
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/LocalSocketFactory.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/LocalSocketFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..1bb55c9e744129c39dbb59a1810b182be08cdac7
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/LocalSocketFactory.java
@@ -0,0 +1,71 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+
+/**
+ * A socket factory to prevent the use of the system socks server, and force connection
+ * only through the loopback interface (127.0.0.1 address).
+ */
+public class LocalSocketFactory implements RMIClientSocketFactory, RMIServerSocketFactory
+{
+    @Override
+    public Socket createSocket(String host, int port) throws IOException
+    {
+        Socket s = new Socket(Proxy.NO_PROXY);
+        // Note we ignore the provided host and use 127.0.0.1 instead
+        SocketAddress sa = new InetSocketAddress("127.0.0.1", port);
+        s.connect(sa, 5000); // 5 second timeout
+        return s;
+    }
+    
+    @Override
+    public ServerSocket createServerSocket(int port) throws IOException
+    {
+        InetAddress ia = InetAddress.getByAddress(new byte[] {127,0,0,1});
+        return new ServerSocket(port, 50, ia); // 50 is the documented default
+    }
+    
+    // Surprisingly, we need to override these;
+    // see http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/faq.html#customsocketreuse 
+    
+    @Override
+    public int hashCode()
+    {
+        return 0xDEED0000;
+    }
+    
+    @Override
+    public boolean equals(Object obj)
+    {
+        return obj != null && getClass() == obj.getClass();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/ObjectBench.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/ObjectBench.java
new file mode 100644
index 0000000000000000000000000000000000000000..227ebb5d75d63cf1962592fab51d7cace270b405
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/ObjectBench.java
@@ -0,0 +1,55 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension;
+
+import bluej.debugmgr.ResultWatcher;
+import bluej.extensions.BPackage;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+
+/**
+ * Creates and removes objects on the object bench.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class ObjectBench
+{
+    /**
+     * Creates a new object, and puts it on the object bench. The given ResultWatcher
+     * will be notified of the result (on the AWT event thread).
+     */
+    public static void createObject(BPackage pkg, String className,
+            String instanceName, String[] constructorParams,
+            ResultWatcher watcher)
+    {
+        try {
+            ConstructorInvoker launcher = new ConstructorInvoker(pkg, className);
+            launcher.invokeConstructor(instanceName, constructorParams, watcher);
+        }
+        catch (ProjectNotOpenException e) {
+            throw new RuntimeException("Project not open (any longer)");
+        }
+        catch (PackageNotFoundException e) {
+            throw new RuntimeException("Package not found");
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/ProjectManager.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/ProjectManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..156e7d4fc747fbcef1fa8da519e42c043fe0256f
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/ProjectManager.java
@@ -0,0 +1,377 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension;
+
+import greenfoot.core.GreenfootLauncherDebugVM;
+import greenfoot.core.GreenfootMain;
+import greenfoot.core.ProjectProperties;
+
+import java.io.File;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import rmiextension.wrappers.RProjectImpl;
+import rmiextension.wrappers.WrapperPool;
+import bluej.Boot;
+import bluej.Config;
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugmgr.ResultWatcher;
+import bluej.extensions.BObject;
+import bluej.extensions.BPackage;
+import bluej.extensions.BProject;
+import bluej.extensions.BlueJ;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.extensions.event.PackageEvent;
+import bluej.extensions.event.PackageListener;
+import bluej.pkgmgr.DocPathEntry;
+import bluej.pkgmgr.Project;
+import bluej.testmgr.record.InvokerRecord;
+import bluej.utility.Debug;
+import bluej.utility.DialogManager;
+
+/**
+ * The ProjectManager is on the BlueJ-VM. It monitors pacakage events from BlueJ
+ * and launches the greenfoot project in the greenfoot-VM.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class ProjectManager
+    implements PackageListener
+{
+    /** Singleton instance */
+    private static ProjectManager instance;
+
+    /** List to keep track of which projects has been opened */
+    private List<BPackage> openedPackages = new ArrayList<BPackage>();
+
+    /** List to keep track of which projects are int the process of being created */
+    private List<File> projectsInCreation = new ArrayList<File>();
+    
+    /** Map of open projects (by directory) to the corresponding RProjectImpl instance */
+    private Map<File,RProjectImpl> openedProjects = new HashMap<File,RProjectImpl>();
+
+    /** The class that will be instantiated in the greenfoot VM to launch the project */
+    private String launchClass = GreenfootLauncherDebugVM.class.getName();
+    private static final String launcherName = "greenfootLauncher";
+
+    private static BlueJ bluej;
+    
+    private static volatile boolean launchFailed = false;
+
+    private ProjectManager()
+    {}
+
+    /**
+     * Get the singleton instance. Make sure it is initialised first.
+     * 
+     * @see #init(BlueJ)
+     */
+    public static ProjectManager instance()
+    {
+        if (bluej == null) {
+            throw new IllegalStateException("Projectmanager has not been initialised.");
+        }
+        return instance;
+    }
+
+    /**
+     * Initialise. Must be called before the instance is accessed.
+     */
+    public static void init(BlueJ bluej)
+    {
+        ProjectManager.bluej = bluej;
+        instance = new ProjectManager();
+    }
+
+    /**
+     * Launch the project in the Greenfoot VM if it is a proper Greenfoot
+     * project. This is called when a package is opened; because there is
+     * no listener interface for project open/close events, we have to keep
+     * track of projects manually.
+     */
+    private void launchProject(final BProject project)
+    {
+        File projectDir;
+        try {
+            projectDir = project.getDir();
+        } catch (ProjectNotOpenException pnoe) {
+            // The project must have closed in the meantime
+            return;
+        }
+        int versionOK = checkVersion(projectDir);
+        if (versionOK != GreenfootMain.VERSION_BAD) {
+            try {
+                if (versionOK == GreenfootMain.VERSION_UPDATED) {
+                    project.getPackage("").reload();
+                }
+
+                // Add debugger listener. The listener will launch Greenfoot once the
+                // VM is ready.
+                GreenfootDebugHandler.addDebuggerListener(project);
+                
+                // Add Greenfoot API sources to project source path
+                Project bjProject = Project.getProject(project.getDir());
+                List<DocPathEntry> sourcePath = bjProject.getSourcePath();
+
+                String language = Config.getPropString("bluej.language");
+
+                if (! language.equals("english")) {
+                    // Add the native language sources first
+                    File langlib = new File(Config.getBlueJLibDir(), language);
+                    File apiDir = new File(new File(langlib, "greenfoot"), "api");
+                    sourcePath.add(new DocPathEntry(apiDir, ""));
+                }
+
+                File langlib = new File(Config.getBlueJLibDir(), "english");
+                File apiDir = new File(new File(langlib, "greenfoot"), "api");
+                sourcePath.add(new DocPathEntry(apiDir, ""));
+                
+            } catch (Exception e) {
+                Debug.reportError("Could not create greenfoot launcher.", e);
+                // This is bad, lets exit.
+                greenfootLaunchFailed(project);
+            }
+        }
+        else {
+            try {
+                project.close();
+            }
+            catch (ProjectNotOpenException pnoe) {}
+            
+            // If this was the only open project, open the startup project
+            // instead.
+            if (bluej.getOpenProjects().length == 0) {
+                File startupProject = new File(bluej.getSystemLibDir(), "startupProject");
+                bluej.openProject(startupProject);
+            }
+        }
+    }
+
+    /**
+     * Check whether failure to launch has been recorded.
+     */
+    public static boolean checkLaunchFailed()
+    {
+        return launchFailed;
+    }
+    
+    /**
+     * Launch the Greenfoot debug VM code (and tell it where to connect to for RMI purposes).
+     * 
+     * @param project  A just-opened project
+     */
+    public void openGreenfoot(final BProject project)
+    {
+        try {
+            final BPackage pkg = project.getPackage("");
+            ResultWatcher watcher = new ResultWatcher() {
+                @Override
+                public void beginCompile()
+                {
+                    // Nothing needs doing
+                }
+                @Override
+                public void beginExecution(InvokerRecord ir)
+                {
+                    // Nothing needs doing
+                }
+                @Override
+                public void putError(String message, InvokerRecord ir)
+                {
+                    Debug.message("Greenfoot launch failed with error: " + message);
+                    greenfootLaunchFailed(project);
+                }
+                @Override
+                public void putException(ExceptionDescription exception, InvokerRecord ir)
+                {
+                    Debug.message("Greenfoot launch failed due to exception in debug VM: " + exception.getText());
+                    greenfootLaunchFailed(project);
+                }
+                @Override
+                public void putResult(DebuggerObject result, String name,
+                        InvokerRecord ir)
+                {
+                    // This is ok
+                    try {
+                        BObject bObject = pkg.getObject(name);
+                        RProjectImpl rProject = WrapperPool.instance().getWrapper(project);
+                        rProject.setTransportObject(bObject);
+                    }
+                    catch (ProjectNotOpenException e) {
+                        // I guess we can ignore this.
+                    }
+                    catch (PackageNotFoundException e) {
+                        // And this.
+                    }
+                    catch (RemoteException re) {
+                        Debug.reportError("Unexpected exception getting remote project wrapper", re);
+                    }
+                }
+                @Override
+                public void putVMTerminated(InvokerRecord ir)
+                {
+                    Debug.message("Greenfoot launch failed due to debug VM terminating.");
+                    greenfootLaunchFailed(project);
+                }
+            };
+            ObjectBench.createObject(pkg, launchClass, launcherName,
+                    new String[] {project.getDir().getPath(),
+                    BlueJRMIServer.getBlueJService()}, watcher);
+        } catch (ProjectNotOpenException e) {
+            // Not important; project has been closed, so no need to launch
+        }
+    }
+    
+    /**
+     * Launching Greenfoot failed. Display a dialog, and exit.
+     */
+    public static void greenfootLaunchFailed(BProject project)
+    {
+        launchFailed = true;
+        String text = Config.getString("greenfoot.launchFailed");
+        DialogManager.showErrorText(null, text);
+        System.exit(1);
+    }
+
+    /**
+     * Handles the check of the project version. It will notify the user if the
+     * project has to be updated.
+     * 
+     * @param projectDir Directory of the project.
+     * @return one of GreenfootMain.VERSION_OK, VERSION_UPDATED or VERSION_BAD
+     */
+    private int checkVersion(File projectDir)
+    {
+        if(isNewProject(projectDir)) {
+            ProjectProperties newProperties = new ProjectProperties(projectDir);
+            newProperties.setApiVersion(Boot.GREENFOOT_API_VERSION);
+            newProperties.save();
+        }        
+        return GreenfootMain.updateApi(projectDir, null, Boot.GREENFOOT_API_VERSION); 
+    }
+
+    /**
+     * Checks if this is a project that is being created for the first time
+     */
+    private boolean isNewProject(File projectDir)
+    {
+        return projectsInCreation.contains(projectDir);        
+    }
+    
+    /**
+     * Flags that this project is in the process of being created.
+     */
+    public void addNewProject(File projectDir)
+    {
+        projectsInCreation.add(projectDir);
+    }
+
+    /**
+     * Flags that this project is no longer in the process of being created.
+     */
+    public void removeNewProject(File projectDir)
+    {
+        projectsInCreation.remove(projectDir);
+    }
+
+    /**
+     * Whether this project is currently open or not, according to our records.
+     * 
+     */
+    private boolean isProjectOpen(BProject prj)
+    {
+        File prjFile = null;
+        try {
+            prjFile = prj.getDir();
+        }
+        catch (ProjectNotOpenException pnoe) {
+            // If we get a ProjectNotOpenException... then surely the project isn't open?
+            // (shouldn't be possible).
+            return false;
+        }
+        
+        return (openedProjects.get(prjFile) != null);
+    }
+
+    //=================================================================
+    //bluej.extensions.event.PackageListener implementation
+    //=================================================================
+
+    /*
+     * @see bluej.extensions.event.PackageListener#packageOpened(bluej.extensions.event.PackageEvent)
+     */
+    public void packageOpened(PackageEvent event)
+    {
+        try {
+            BPackage pkg = event.getPackage();
+            BProject project = pkg.getProject();
+            if (! isProjectOpen(project)) {
+                openedProjects.put(project.getDir(), WrapperPool.instance().getWrapper(project));
+                launchProject(project);
+            }
+
+            openedPackages.add(event.getPackage());
+        }
+        catch (ProjectNotOpenException pnoe) {
+            // Going out on a bit of a limb, but this won't happen.
+            // (if a package is being opened, then the project *must* be open).
+        }
+        catch (RemoteException re) {
+            // Not really much reason for this to happen either.
+            Debug.reportError("Remote exception when package opened", re);
+        }
+    }
+
+    /*
+     * @see bluej.extensions.event.PackageListener#packageClosing(bluej.extensions.event.PackageEvent)
+     */
+    public void packageClosing(PackageEvent event)
+    {
+        try {
+            BProject project = event.getPackage().getProject();
+            openedPackages.remove(event.getPackage());
+            for (BPackage pkg : openedPackages) {
+                try {
+                    if (pkg.getProject() == project) {
+                        return; // Project still open
+                    }
+                }
+                catch (ProjectNotOpenException pnoe) {
+                    // If this happens, it's open because the package close event
+                    // has yet to be reported. We'll clean up then.
+                }
+            }
+            // If we finished the loop without finding any packages in the project still
+            // open, then the project itself has closed.
+            openedProjects.remove(project.getDir());
+        }
+        catch (ProjectNotOpenException pnoe) {
+            // Currently this shouldn't happen; the package is reported closed while
+            // the project is still considered open.
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/RMIExtension.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/RMIExtension.java
new file mode 100644
index 0000000000000000000000000000000000000000..d2d206a5813f534081ef71edaef154cf560dca65
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/RMIExtension.java
@@ -0,0 +1,170 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension;
+
+import greenfoot.core.GreenfootLauncherBlueJVM;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import bluej.Config;
+import bluej.Main;
+import bluej.debugger.jdi.NetworkTest;
+import bluej.extensions.BProject;
+import bluej.extensions.BlueJ;
+import bluej.extensions.Extension;
+import bluej.extensions.event.ApplicationEvent;
+import bluej.extensions.event.ApplicationListener;
+import bluej.utility.Debug;
+
+/**
+ * This is the starting point of Greenfoot as a BlueJ Extension.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class RMIExtension extends Extension implements ApplicationListener
+{
+    private BlueJ theBlueJ;
+
+    /**
+     * When this method is called, the extension may start its work.
+     */
+    @SuppressWarnings("ResultOfObjectAllocationIgnored")
+    public void startup(BlueJ bluej)
+    {
+        theBlueJ = bluej;
+        ProjectManager.init(bluej);
+
+        try {
+            new BlueJRMIServer(theBlueJ);
+        }
+        catch (IOException e) {
+            Debug.reportError("Could not launch RMI server", e);
+            NetworkTest.doTest();
+            ProjectManager.greenfootLaunchFailed(null);
+        }
+
+        theBlueJ.addApplicationListener(this);
+    }
+
+    /**
+     * Opens a project in BlueJ if no other projects are open.
+     * 
+     * @param projectPath path of the project to open.
+     */
+    public void maybeOpenProject(File projectPath)
+    {
+        // Now we need to find out if a greenfoot project is automatically
+        // opening. If not we must open the dummy project.
+        boolean openOrphans = "true".equals(Config.getPropString("bluej.autoOpenLastProject"));
+        if (!openOrphans || !Main.hadOrphanPackages()) {
+            if (theBlueJ.getOpenProjects().length == 0) {
+                openProject(projectPath);
+            }
+        }
+    }
+
+    /**
+     * Opens a project in BlueJ
+     * 
+     * @param projectPath path of the project to open.
+     */
+    public void openProject(File projectPath)
+    {
+        BProject project = theBlueJ.openProject(projectPath);
+        if (project == null) {
+            Debug.reportError("Could not open scenario: " + projectPath);
+        }
+    }
+
+    /**
+     * Creates a new project in BlueJ
+     * 
+     * @param projectPath path of the project to open.
+     */
+    public void newProject(File projectPath)
+    {
+        ProjectManager.instance().addNewProject(projectPath);
+        BProject project = theBlueJ.newProject(projectPath);
+        if (project == null) {
+            Debug.reportError("Could not open scenario: " + projectPath);
+        }
+        ProjectManager.instance().removeNewProject(projectPath);
+
+    }
+
+    /**
+     * This method must decide if this Extension is compatible with the current
+     * release of the BlueJ Extensions API
+     */
+    public boolean isCompatible()
+    {
+        return Config.isGreenfoot();
+    }
+
+    /**
+     * Returns the version number of this extension
+     */
+    public String getVersion()
+    {
+        return ("2003.03");
+    }
+
+    /**
+     * Returns the user-visible name of this extension
+     */
+    public String getName()
+    {
+        return ("greenfoot Extension");
+    }
+
+    @Override
+    public String getDescription()
+    {
+        return ("greenfoot extension");
+    }
+
+    /**
+     * Returns a URL where you can find info on this extension. The real problem
+     * is making sure that the link will still be alive in three years...
+     */
+    @Override
+    public URL getURL()
+    {
+        try {
+            return new URL("http://www.greenfoot.org");
+        }
+        catch (MalformedURLException e) {
+            return null;
+        }
+    }
+    
+    // ------------- ApplicationListener interface ------------
+    
+    public void blueJReady(ApplicationEvent event)
+    {
+        GreenfootLauncherBlueJVM.getInstance().launch(this);
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/InvocationResultWatcher.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/InvocationResultWatcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..4aa27a36b8c8a1b00fffdc404deb13d210c9ce00
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/InvocationResultWatcher.java
@@ -0,0 +1,81 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import bluej.debugger.DebuggerObject;
+import bluej.debugger.ExceptionDescription;
+import bluej.debugmgr.ExpressionInformation;
+import bluej.debugmgr.ResultWatcher;
+import bluej.testmgr.record.InvokerRecord;
+
+/**
+ * A result watcher used by the RObjectImpl class.
+ * 
+ * @author Davin McCall
+ */
+class InvocationResultWatcher implements ResultWatcher
+{
+    public String errorMsg = null;
+    public DebuggerObject resultObj = null;
+    
+    public void putError(String error, InvokerRecord ir)
+    {
+        errorMsg = error;
+        synchronized (this) {
+            notify();
+        }
+    }
+    
+    @Override
+    public void beginCompile() { }
+    
+    @Override
+    public void beginExecution(InvokerRecord ir) { }
+    
+    public void putResult(DebuggerObject dObj, String name, InvokerRecord ir)
+    {
+        resultObj = dObj;
+        synchronized (this) {
+            notify();
+        }
+    }
+    
+    public ExpressionInformation getExpressionInformation()
+    {
+        return null;
+    }
+
+    public void putException(ExceptionDescription exception, InvokerRecord ir)
+    {
+        errorMsg = exception.getText();
+        synchronized (this) {
+            notify();
+        }
+    }
+    
+    public void putVMTerminated(InvokerRecord ir)
+    {
+        synchronized (this) {
+            notify();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RBlueJ.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RBlueJ.java
new file mode 100644
index 0000000000000000000000000000000000000000..aeeb418941d06de27e706431aa5c8485b5f023d2
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RBlueJ.java
@@ -0,0 +1,158 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.io.File;
+import java.rmi.RemoteException;
+import java.util.Properties;
+
+import rmiextension.wrappers.event.RClassListener;
+import rmiextension.wrappers.event.RCompileListener;
+import rmiextension.wrappers.event.RInvocationListener;
+
+/**
+ * 
+ * Interface for accessing BlueJ-functionality
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public interface RBlueJ
+    extends java.rmi.Remote
+{
+    /**
+     * Get a stream object that can be used to output to the debug log.
+     */
+    public RPrintStream getDebugPrinter()
+        throws RemoteException;
+    
+    /**
+     * Register a Compile event listener for the project identified by the given path.
+     */
+    public void addCompileListener(RCompileListener listener, File projectPath)
+        throws RemoteException;
+
+    /**
+     * Register an invocation event listener
+     */
+    public void addInvocationListener(RInvocationListener listener)
+        throws RemoteException;
+
+    /**
+     * Register a remote class event listener
+     */
+    public void addClassListener(RClassListener listener)
+        throws RemoteException;
+    
+    
+    /**
+     * Get a BlueJ property value
+     */
+    public String getBlueJPropertyString(String property, String def)
+        throws RemoteException;
+
+    /**
+     * Get a BlueJ extensions property value
+     * 
+     * @param property  The property whose value to retrieve
+     * @param def       The default value to return
+     * @return   The property value
+     */
+    public String getExtensionPropertyString(String property, String def)
+        throws RemoteException;
+
+
+    /**
+     * Get a list of all open projects.
+     */
+    public RProject[] getOpenProjects()
+        throws RemoteException;
+
+    /**
+     * Get the Bluej "lib" dir.
+     */
+    public File getSystemLibDir()
+        throws RemoteException;
+
+    /**
+     * Create and open a new Project
+     * 
+     * @param directory  The directory to create the project in
+     * @return   A reference to the newly created project, or null
+     *           if the project could not be created.
+     */
+    public RProject newProject(File directory)
+        throws RemoteException;
+
+    /**
+     * Open an existing project
+     * @param projectDirFile  The directory containing the project to open
+     * @return  A reference to the project
+     */
+    public RProject openProject(File projectDirFile)
+        throws RemoteException;
+
+    /**
+     * Remove a compile listener.
+     * @param listener  The listener to remove
+     */
+    public void removeCompileListener(RCompileListener listener)
+        throws RemoteException;
+
+    /**
+     * Remove an invocation listener.
+     * @param listener  The listener to remove
+     */
+    public void removeInvocationListener(RInvocationListener listener)
+        throws RemoteException;
+
+    /**
+     * De-register a remote class event listener.
+     */
+    public void removeClassListener(RClassListener listener)
+        throws RemoteException;
+
+    /**
+     * Set an extension property value.
+     * @param property  The property key
+     * @param value     The value to set
+     */
+    public void setExtensionPropertyString(String property, String value)
+        throws RemoteException;
+
+    /**
+     * Exits the entire application.
+     * 
+     * @throws RemoteException
+     */
+    public void exit()
+        throws RemoteException;
+
+    /**
+     * Get the properties that were given on the command line and used 
+     * to initialise bluej.Config.
+     */
+    public Properties getInitialCommandLineProperties()
+        throws RemoteException;
+
+    public void showPreferences()
+        throws RemoteException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RBlueJImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RBlueJImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..7ebfe94918aabc97b234259206948524c064406c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RBlueJImpl.java
@@ -0,0 +1,397 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.awt.EventQueue;
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+
+import rmiextension.ProjectManager;
+import rmiextension.wrappers.event.RClassListener;
+import rmiextension.wrappers.event.RClassListenerWrapper;
+import rmiextension.wrappers.event.RCompileListener;
+import rmiextension.wrappers.event.RCompileListenerWrapper;
+import rmiextension.wrappers.event.RInvocationListener;
+import rmiextension.wrappers.event.RInvocationListenerWrapper;
+import bluej.Config;
+import bluej.extensions.BProject;
+import bluej.extensions.BlueJ;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.extensions.event.ClassListener;
+import bluej.extensions.event.CompileEvent;
+import bluej.extensions.event.CompileListener;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.prefmgr.PrefMgrDialog;
+import bluej.utility.Debug;
+import bluej.utility.Utility;
+
+/**
+ * Implements the RBlueJ RMI interface.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class RBlueJImpl extends java.rmi.server.UnicastRemoteObject
+    implements RBlueJ
+{
+    BlueJ blueJ;
+
+    // These maps are implemented as instances Hashtable rather than HashMap, so they
+    // do not require external synchronization.
+    private Map<RCompileListener,RCompileListenerWrapper> compileListeners =
+        new Hashtable<RCompileListener,RCompileListenerWrapper>();
+    private Map<RInvocationListener,RInvocationListenerWrapper> invocationListeners =
+        new Hashtable<RInvocationListener,RInvocationListenerWrapper>();
+    private Map<RClassListener,RClassListenerWrapper> classListeners =
+        new Hashtable<RClassListener,RClassListenerWrapper>();
+    
+    public RBlueJImpl(BlueJ blueJ)
+        throws RemoteException
+    {
+        super();
+        this.blueJ = blueJ;
+        blueJ.addCompileListener(new CompileListener() {
+            
+            @Override
+            public void compileWarning(CompileEvent event) { }
+            
+            @Override
+            public void compileSucceeded(CompileEvent event)
+            {
+                // Do a Garbage Collection to finalize any garbage JdiObjects, thereby
+                // allowing objects on the remote VM to be garbage collected.
+                System.gc();
+            }
+            
+            @Override
+            public void compileStarted(CompileEvent event) { }
+            
+            @Override
+            public void compileFailed(CompileEvent event) { }
+            
+            @Override
+            public void compileError(CompileEvent event) { }
+        });
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#getDebugPrinter()
+     */
+    public RPrintStream getDebugPrinter() throws RemoteException
+    {
+        return new RPrintStreamImpl();
+    }
+    
+    /*
+     * @see rmiextension.wrappers.RBlueJ#addCompileListener(rmiextension.wrappers.event.RCompileListener, java.lang.String)
+     */
+    public void addCompileListener(RCompileListener listener, final File projectPath)
+    {
+        final BProjectRef bProjectRef = new BProjectRef();
+        
+        try {
+            EventQueue.invokeAndWait(new Runnable() {
+                @Override
+                public void run()
+                {
+                    BProject[] projects = blueJ.getOpenProjects();
+                    BProject project = null;
+                    for (int i = 0; i < projects.length; i++) {
+                        BProject prj = projects[i];
+                        try {
+                            if(prj.getDir().equals(projectPath)) {
+                                project = prj;
+                            }
+                        }
+                        catch (ProjectNotOpenException e) {
+                            e.printStackTrace();
+                        }
+                    }
+                    bProjectRef.bProject = project;
+                }
+            });
+        }
+        catch (InterruptedException e1) { }
+        catch (InvocationTargetException e1) {
+            throw new Error(e1);
+        }
+        
+        RCompileListenerWrapper wrapper = new RCompileListenerWrapper(listener, bProjectRef.bProject, this);
+        compileListeners.put(listener, wrapper);
+        blueJ.addCompileListener(wrapper);
+    }
+    
+    private class BProjectRef
+    {
+        public BProject bProject;
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#addInvocationListener(rmiextension.wrappers.event.RInvocationListener)
+     */
+    public void addInvocationListener(RInvocationListener listener)
+    {
+        RInvocationListenerWrapper wrapper = new RInvocationListenerWrapper(listener);
+        invocationListeners.put(listener, wrapper);
+        blueJ.addInvocationListener(wrapper);
+    }
+    
+    /*
+     * @see rmiextension.wrappers.RBlueJ#addClassListener(rmiextension.wrappers.event.RClassListener)
+     */
+    public void addClassListener(RClassListener listener) throws RemoteException
+    {
+        RClassListenerWrapper wrapper = new RClassListenerWrapper(this, listener);
+        classListeners.put(listener, wrapper);
+        blueJ.addClassListener(wrapper);
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#getBlueJPropertyString(java.lang.String, java.lang.String)
+     */
+    public String getBlueJPropertyString(String property, String def)
+    {
+        return blueJ.getBlueJPropertyString(property, def);
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#getExtensionPropertyString(java.lang.String, java.lang.String)
+     */
+    public String getExtensionPropertyString(String property, String def)
+    {
+        return blueJ.getExtensionPropertyString(property, def);
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#getOpenProjects()
+     */
+    public RProject[] getOpenProjects()
+        throws RemoteException
+    {
+        final ArrayList<RProject> rProjects = new ArrayList<RProject>();
+        
+        try {
+            EventQueue.invokeAndWait(new Runnable() {
+                @Override
+                public void run()
+                {
+                    BProject[] bProjects = blueJ.getOpenProjects();
+                    for (BProject bProject : bProjects) {
+                        try {
+                            rProjects.add(WrapperPool.instance().getWrapper(bProject));
+                        }
+                        catch (RemoteException e) {
+                            // Shouldn't happen?
+                        }
+                    }
+                }
+            });
+        }
+        catch (InterruptedException e) { }
+        catch (InvocationTargetException e) {
+            Debug.reportError("Problem getting open projects", e.getCause());
+        }
+
+        return rProjects.toArray(new RProject[rProjects.size()]);
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#getSystemLibDir()
+     */
+    public File getSystemLibDir()
+    {
+        File f = blueJ.getSystemLibDir();
+        //The getAbsoluteFile() fixes a weird bug on win using jdk1.4.2_06
+        return f.getAbsoluteFile();
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#newProject(java.io.File)
+     */
+    public RProject newProject(final File directory)
+        throws RemoteException
+    {
+        final RProjectRef wrapper = new RProjectRef();
+        
+        try {
+            EventQueue.invokeAndWait(new Runnable() {
+                @Override
+                public void run()
+                {
+                    ProjectManager.instance().addNewProject(directory);
+                    BProject wrapped = blueJ.newProject(directory);
+                    if (wrapped != null) {
+                        try {
+                            wrapper.rProject = WrapperPool.instance().getWrapper(wrapped);
+                        }
+                        catch (RemoteException e) {
+                            Debug.reportError("Error creating RMI project wrapper", e);
+                        }
+                    }
+                    ProjectManager.instance().removeNewProject(directory);
+                }
+            });
+        }
+        catch (InterruptedException e) { }
+        catch (InvocationTargetException e) {
+            Debug.reportError("Error creating project via RMI", e.getCause());
+        }
+        
+        return wrapper.rProject;
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#openProject(java.lang.String)
+     */
+    public RProject openProject(final File directory)
+        throws RemoteException
+    {
+        final RProjectRef projectRef = new RProjectRef();
+        
+        try {
+            EventQueue.invokeAndWait(new Runnable() {
+                @Override
+                public void run()
+                {
+                    BProject bProject = blueJ.openProject(directory);
+                    if (bProject != null) {
+                        try {
+                            projectRef.rProject = WrapperPool.instance().getWrapper(bProject);
+                        }
+                        catch (RemoteException re) {
+                            Debug.reportError("Error when opening project via RMI", re);
+                        }
+                    }
+                }
+            });
+        }
+        catch (InterruptedException e) { }
+        catch (InvocationTargetException e) {
+            Debug.reportError("Error opening project", e);
+            Debug.reportError("Error cause:", e.getCause());
+        }
+        
+        return projectRef.rProject;
+    }
+    
+    private class RProjectRef
+    {
+        public RProject rProject;
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#removeCompileListener(rmiextension.wrappers.event.RCompileListener)
+     */
+    public void removeCompileListener(RCompileListener listener)
+    {
+        RCompileListenerWrapper wrapper = compileListeners.remove(listener);
+        blueJ.removeCompileListener(wrapper);
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#removeInvocationListener(rmiextension.wrappers.event.RInvocationListener)
+     */
+    public void removeInvocationListener(RInvocationListener listener)
+    {
+        RInvocationListenerWrapper wrapper = invocationListeners.remove(listener);
+        blueJ.removeInvocationListener(wrapper);
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#removeClassListener(rmiextension.wrappers.event.RClassListener)
+     */
+    public void removeClassListener(RClassListener listener)
+    {
+        ClassListener wrapper = classListeners.remove(listener);
+        blueJ.removeClassListener(wrapper);
+    }
+    
+    /*
+     * @see rmiextension.wrappers.RBlueJ#setExtensionPropertyString(java.lang.String, java.lang.String)
+     */
+    public void setExtensionPropertyString(String property, String value)
+    {
+        blueJ.setExtensionPropertyString(property, value);
+    }
+
+    /*
+     * @see dk.sdu.mip.dit.remote.RBlueJ#exit()
+     */
+    public void exit()
+        throws RemoteException
+    {
+        try {
+            EventQueue.invokeAndWait(new Runnable() {
+               public void run()
+                {
+                   BProject[] bProjects = blueJ.getOpenProjects();
+                   int length = bProjects.length;
+                   for (int i = 0; i < length; i++) {
+                       try {
+                           RProjectImpl rpImpl = WrapperPool.instance().getWrapper(bProjects[i]);
+                           rpImpl.notifyClosing();
+                       }
+                       catch (RemoteException re) {}
+                   }
+                   
+                   PkgMgrFrame [] frames = PkgMgrFrame.getAllFrames();
+                   for (int i = 0; i < frames.length; i++) {
+                       frames[i].doClose(false, true);
+                   }
+                } 
+            });
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#getInitialCommandLineProperties()
+     */
+    public Properties getInitialCommandLineProperties()
+        throws RemoteException
+    {
+        return Config.getInitialCommandLineProperties();
+    }
+
+    /*
+     * @see rmiextension.wrappers.RBlueJ#showPreferences()
+     */
+    @Override
+    public void showPreferences() throws RemoteException
+    {
+        EventQueue.invokeLater(new Runnable() {
+           @Override
+           public void run()
+           {
+               PrefMgrDialog.showDialog();
+               Utility.bringToFront(PrefMgrDialog.getInstance());
+           }
+        });
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RClass.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..463383b346d66c8374b05738b41983628b49c080
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RClass.java
@@ -0,0 +1,132 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.io.File;
+import java.rmi.RemoteException;
+
+import bluej.extensions.BField;
+import bluej.extensions.BMethod;
+import bluej.extensions.ClassNotFoundException;
+import bluej.extensions.CompilationNotStartedException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.extensions.editor.Editor;
+
+/**
+ * Remote BlueJ class interface.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public interface RClass
+    extends java.rmi.Remote
+{
+    public abstract void compile(boolean waitCompileEnd, boolean forceQuiet)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException, CompilationNotStartedException;
+
+    public abstract void edit()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+    
+    /**
+     * Closes the editor (sets the editor to not visible)
+     * @throws ProjectNotOpenException   if the project has been closed
+     * @throws PackageNotFoundException  if the package has been removed
+     * @throws RemoteException           if a remote exception occurs
+     */
+    public abstract void closeEditor()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+    
+    public abstract void insertAppendMethod(String comment, String access, String methodName, String methodBody, boolean showEditorOnCreate, boolean showEditorOnAppend)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    public abstract void insertMethodCallInConstructor(String methodName, boolean showEditor)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+    
+    public abstract RConstructor getConstructor(Class<?>[] signature)
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException;
+
+    public abstract RConstructor[] getConstructors()
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException;
+
+    public abstract BMethod getDeclaredMethod(String methodName, Class<?>[] params)
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException;
+
+    public abstract BMethod[] getDeclaredMethods()
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException;
+
+    public abstract RField getField(String fieldName)
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException;
+
+    public abstract BField[] getFields()
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException;
+
+    public abstract RPackage getPackage()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    /**
+     * Gets the superclass of this class (if it has one).
+     * 
+     * @param inRemoteCallback  whether this method is being called from a method which was itself invoked
+     *                          by a callback from this virtual machine, which blocks the dispatch thread.
+     */
+    public abstract RClass getSuperclass(boolean inRemoteCallback)
+        throws ProjectNotOpenException, PackageNotFoundException, ClassNotFoundException, RemoteException;
+
+    public abstract boolean isCompiled(boolean inRemoteCallback)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    public abstract String getQualifiedName()
+        throws RemoteException;
+
+  
+    public File getJavaFile()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    public abstract void remove()
+        throws ProjectNotOpenException, PackageNotFoundException, ClassNotFoundException, RemoteException;
+
+    /**
+     * Put the editor for this class in or out of read-only mode.
+     * 
+     * @see Editor#setReadOnly(boolean)
+     */
+    public abstract void setReadOnly(boolean b)
+        throws RemoteException, ProjectNotOpenException, PackageNotFoundException ;
+
+    /**
+     * Show a message in the editor status area for this class.
+     */
+    public abstract void showMessage(String message)
+        throws RemoteException, ProjectNotOpenException, PackageNotFoundException;
+
+    /**
+     * Check whether this class has a source file.
+     */
+    public abstract boolean hasSourceCode()
+        throws RemoteException, ProjectNotOpenException, PackageNotFoundException;
+
+    /**
+     * Auto-indents the code for this class.
+     */
+    public abstract void autoIndent()
+        throws RemoteException, ProjectNotOpenException, PackageNotFoundException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RClassImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RClassImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..261ba2e9d2d2e4eedcbce5d456e1c6b14c83fde0
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RClassImpl.java
@@ -0,0 +1,529 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.awt.EventQueue;
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.rmi.RemoteException;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+
+import javax.swing.text.BadLocationException;
+
+import bluej.editor.moe.MoeEditor;
+import bluej.editor.moe.MoeIndent;
+import bluej.editor.moe.MoeSyntaxDocument;
+import bluej.extensions.BClass;
+import bluej.extensions.BConstructor;
+import bluej.extensions.BField;
+import bluej.extensions.BMethod;
+import bluej.extensions.BPackage;
+import bluej.extensions.ClassNotFoundException;
+import bluej.extensions.CompilationNotStartedException;
+import bluej.extensions.ExtensionBridge;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.extensions.editor.Editor;
+import bluej.parser.nodes.ParsedNode;
+import bluej.parser.nodes.NodeTree.NodeAndPosition;
+import bluej.utility.Debug;
+
+/**
+ * Implementation of the remote class interface.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class RClassImpl extends java.rmi.server.UnicastRemoteObject
+    implements RClass
+{
+    private BClass bClass;
+    
+    private static ProjectNotOpenException pnoe;
+    private static PackageNotFoundException pnfe;
+    
+    /**
+     * Package-private constructor. Use WrapperPool to instantiate.
+     */
+    RClassImpl(BClass bClass)
+        throws RemoteException
+    {
+        this.bClass = bClass;
+        if (bClass == null) {
+            throw new NullPointerException("Argument can't be null");
+        }
+    }
+
+    @Override
+    public void compile(boolean waitCompileEnd, boolean forceQuiet)
+        throws ProjectNotOpenException, PackageNotFoundException, CompilationNotStartedException
+    {
+        bClass.compile(waitCompileEnd, forceQuiet);
+    }
+    
+    @Override
+    public boolean hasSourceCode() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        return ExtensionBridge.hasSourceCode(bClass);
+    }
+
+    @Override
+    public void edit()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        synchronized (RClassImpl.class) {
+            pnoe = null;
+            pnfe = null;
+            
+            EventQueue.invokeLater(new Runnable() {
+                public void run()
+                {
+                    try {
+                        Editor editor = bClass.getEditor();
+                        if (editor != null) {
+                            editor.setVisible(true);
+                        }
+                    }
+                    catch (ProjectNotOpenException e) {
+                        pnoe = e;
+                    }
+                    catch (PackageNotFoundException e) {
+                        pnfe = e;
+                    }
+                }
+            });
+            
+            if (pnoe != null) throw pnoe;
+            if (pnfe != null) throw pnfe;
+        }
+    }
+    
+    @Override
+    public void closeEditor() throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        synchronized (RClassImpl.class) {
+            pnoe = null;
+            pnfe = null;
+
+            EventQueue.invokeLater(new Runnable() {
+                public void run()
+                {
+                    try {
+                        Editor editor = bClass.getEditor();
+                        if (editor != null) {
+                            editor.setVisible(false);
+                        }
+                    }
+                    catch (ProjectNotOpenException e) {
+                        pnoe = e;
+                    }
+                    catch (PackageNotFoundException e) {
+                        pnfe = e;
+                    }
+                }
+            });
+
+            if (pnoe != null) throw pnoe;
+            if (pnfe != null) throw pnfe;
+        }
+    }
+    
+    @Override
+    public void showMessage(final String message) throws RemoteException,
+            ProjectNotOpenException, PackageNotFoundException
+    {
+        final Editor e = bClass.getEditor();
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                e.showMessage(message);
+            }
+        });
+    }
+
+    @Override
+    public void insertAppendMethod(final String comment, final String access, final String methodName, final String methodBody, final boolean showEditorOnCreate, final boolean showEditorOnAppend) throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        final Editor e = bClass.getEditor();
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                MoeEditor bje = (MoeEditor)bluej.extensions.editor.EditorBridge.getEditor(e);
+                MoeSyntaxDocument doc = bje.getSourceDocument();
+                
+                
+                NodeAndPosition<ParsedNode> classNode = findClassNode(doc);
+                if (classNode == null)
+                    return;
+                NodeAndPosition<ParsedNode> existingMethodNode = findMethodNode(methodName, classNode);
+        
+                if (existingMethodNode != null) {
+                    //Append to existing method:
+                    appendTextToNode(e, bje, existingMethodNode, methodBody);
+                    if (showEditorOnAppend)
+                        e.setVisible(true);
+                } else {
+                    //Make a new method:
+                    String fullMethod = comment + "    " + access + " void " + methodName + "()\n    {\n" + methodBody + "    }\n";
+                    appendTextToNode(e, bje, classNode, fullMethod);
+                    if (showEditorOnCreate)
+                        e.setVisible(true);
+                }
+            }
+        });
+    }
+    
+    private NodeAndPosition<ParsedNode> findClassNode(MoeSyntaxDocument doc)
+    {
+        NodeAndPosition<ParsedNode> root = new NodeAndPosition<ParsedNode>(doc.getParser(), 0, doc.getParser().getSize());
+        for (NodeAndPosition<ParsedNode> nap : iterable(root)) {
+            if (nap.getNode().getNodeType() == ParsedNode.NODETYPE_TYPEDEF)
+                return nap;
+        }
+        return null;
+    }
+
+    @Override
+    public void insertMethodCallInConstructor(final String methodName, final boolean showEditor)
+            throws ProjectNotOpenException, PackageNotFoundException,
+            RemoteException
+    {
+        final Editor e = bClass.getEditor();
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                MoeEditor bje = (MoeEditor)bluej.extensions.editor.EditorBridge.getEditor(e);
+                MoeSyntaxDocument doc = bje.getSourceDocument();
+                
+                NodeAndPosition<ParsedNode> classNode = findClassNode(doc);
+                if (classNode == null)
+                    return;
+                NodeAndPosition<ParsedNode> constructor = findMethodNode(bClass.getName(), classNode);
+                if (constructor != null && false == hasMethodCall(doc, methodName, constructor, true)) {
+                    //Add at the end of the constructor:
+                    appendTextToNode(e, bje, constructor, "\n        " + methodName + "();\n    ");
+                }
+                
+                if (showEditor)
+                    e.setVisible(true);
+            }
+        });
+    }
+    
+    /**
+     * Appends text to a node that ends in a curly bracket
+     */
+    private void appendTextToNode(Editor e, MoeEditor bjEditor, NodeAndPosition<ParsedNode> node, String text)
+    {
+        //The node may have whitespace at the end, so we look for the last closing brace and
+        //insert before that:
+        for (int pos = node.getEnd() - 1; pos >= 0; pos--) {
+            if ("}".equals(e.getText(e.getTextLocationFromOffset(pos), e.getTextLocationFromOffset(pos+1)))) {
+                bjEditor.undoManager.beginCompoundEdit();
+                int originalLength = node.getSize();
+                // First insert the text:
+                e.setText(e.getTextLocationFromOffset(pos), e.getTextLocationFromOffset(pos), text);
+                // Then auto-indent the method to make sure our indents were correct:
+                int oldPos = bjEditor.getSourcePane().getCaretPosition();
+                MoeIndent.calculateIndentsAndApply(bjEditor.getSourceDocument(), node.getPosition(), node.getPosition() + originalLength + text.length(), oldPos);
+                bjEditor.undoManager.endCompoundEdit();
+                e.setCaretLocation(e.getTextLocationFromOffset(pos));
+                return;
+            }
+        }
+        Debug.message("Could not find end of node to append to: \"" + e.getText(e.getTextLocationFromOffset(node.getPosition()), e.getTextLocationFromOffset(node.getEnd())) + "\"");
+    }
+    
+    // This really returns an iterator, but wrapping it into an iterable means that
+    // we can use Java's nice for-each loops:
+    private Iterable<NodeAndPosition<ParsedNode>> iterable(final NodeAndPosition<ParsedNode> parent)
+    {
+        return new Iterable<NodeAndPosition<ParsedNode>>()
+        {
+            @Override
+          public void forEach(
+              Consumer<? super NodeAndPosition<ParsedNode>> action) {
+            // TODO Auto-generated method stub
+            
+          }
+
+          @Override
+          public Spliterator<NodeAndPosition<ParsedNode>> spliterator() {
+            // TODO Auto-generated method stub
+            return null;
+          }
+
+            public Iterator<NodeAndPosition<ParsedNode>> iterator()
+            {
+                return parent.getNode().getChildren(parent.getPosition());
+            };
+        };
+    }
+    
+    private boolean hasMethodCall(MoeSyntaxDocument doc, String methodName, NodeAndPosition<ParsedNode> methodNode, boolean root)
+    {
+        for (NodeAndPosition<ParsedNode> nap : iterable(methodNode)) {
+            // Method nodes have comments as children, and the body:
+            if (nap.getNode().getNodeType() == ParsedNode.NODETYPE_NONE && root) {
+                return hasMethodCall(doc, methodName, nap, false);
+            }
+            
+            try {
+                if (nap.getNode().getNodeType() == ParsedNode.NODETYPE_EXPRESSION && doc.getText(nap.getPosition(), nap.getSize()).startsWith(methodName)) {
+                    return true;
+                }
+            }
+            catch (BadLocationException e) {
+            }            
+        }
+        
+        return false;
+    }
+    
+    private NodeAndPosition<ParsedNode> findMethodNode(String methodName, NodeAndPosition<ParsedNode> start)
+    {
+        for (NodeAndPosition<ParsedNode> nap : iterable(start)) {
+            if (nap.getNode().getNodeType() == ParsedNode.NODETYPE_NONE) {
+                NodeAndPosition<ParsedNode> r = findMethodNode(methodName, nap);
+                if (r != null)
+                    return r;
+            }
+            if (nap.getNode().getNodeType() == ParsedNode.NODETYPE_METHODDEF && nap.getNode().getName().equals(methodName)) {
+                return nap;
+            }
+        }
+        
+        return null;
+    }
+
+    @Override
+    public RConstructor getConstructor(Class<?>[] signature)
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException
+    {
+
+        BConstructor bConstructor = bClass.getConstructor(signature);
+
+        RConstructor rConstructor = WrapperPool.instance().getWrapper(bConstructor);
+        return rConstructor;
+    }
+
+    @Override
+    public RConstructor[] getConstructors()
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException
+    {
+
+        BConstructor[] bConstructors = bClass.getConstructors();
+        int length = bConstructors.length;
+        RConstructor[] rConstructors = new RConstructor[length];
+        for (int i = 0; i < length; i++) {
+            rConstructors[i] = WrapperPool.instance().getWrapper(bConstructors[i]);
+        }
+
+        return rConstructors;
+    }
+
+    @Override
+    public BMethod getDeclaredMethod(String methodName, Class<?>[] params)
+        throws ProjectNotOpenException, ClassNotFoundException
+    {
+        return null;
+    }
+
+    @Override
+    public BMethod[] getDeclaredMethods()
+        throws ProjectNotOpenException, ClassNotFoundException
+    {
+        return bClass.getDeclaredMethods();
+
+    }
+
+    @Override
+    public RField getField(String fieldName)
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException
+    {
+
+        BField wrapped = bClass.getField(fieldName);
+        RField wrapper = WrapperPool.instance().getWrapper(wrapped);
+        return wrapper;
+    }
+
+    @Override
+    public BField[] getFields()
+        throws ProjectNotOpenException, ClassNotFoundException
+    {
+        return bClass.getFields();
+    }
+
+    @Override
+    public RPackage getPackage()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        BPackage wrapped = bClass.getPackage();
+        RPackage wrapper = WrapperPool.instance().getWrapper(wrapped);
+        return wrapper;
+    }
+
+    @Override
+    public RClass getSuperclass(boolean inRemoteCallback)
+        throws ProjectNotOpenException, PackageNotFoundException, ClassNotFoundException, RemoteException
+    {
+        if (! inRemoteCallback) {
+            synchronized (RClassImpl.class) {
+                final BClass[] wrapped = new BClass[1];
+                final ClassNotFoundException[] cnfe = new ClassNotFoundException[1];
+                pnoe = null;
+                pnfe = null;
+
+                try {
+                    EventQueue.invokeAndWait(new Runnable() {
+                        @Override
+                        public void run()
+                        {
+                            try {
+                                wrapped[0] = bClass.getSuperclass();
+                            }
+                            catch (ProjectNotOpenException e) {
+                                pnoe = e;
+                            }
+                            catch (PackageNotFoundException e) {
+                                pnfe = e;
+                            }
+                            catch (ClassNotFoundException e) {
+                                cnfe[0] = e;
+                            }
+                        }
+                    });
+                }
+                catch (InterruptedException ie) {
+                    throw new RuntimeException(ie);
+                }
+                catch (InvocationTargetException ite) {
+                    throw new RuntimeException(ite.getCause());
+                }
+
+                if (pnoe != null) {
+                    throw pnoe;
+                }
+                if (pnfe != null) {
+                    throw pnfe;
+                }
+                if (cnfe[0] != null) {
+                    throw cnfe[0];
+                }
+
+                return WrapperPool.instance().getWrapper(wrapped[0]);
+            }
+        }
+        else {
+            BClass sc = bClass.getSuperclass();
+            return WrapperPool.instance().getWrapper(sc);
+        }
+    }
+
+    @Override
+    public boolean isCompiled(boolean inRemoteCallback)
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        synchronized (RClassImpl.class) {
+            pnoe = null;
+            pnfe = null;
+            final boolean[] result = new boolean[1];
+            try {
+                Runnable r = new Runnable() {
+                    public void run()
+                    {
+                        try {
+                            result[0] = bClass.isCompiled();
+                        } catch (ProjectNotOpenException e) {
+                            pnoe = e;
+                        } catch (PackageNotFoundException e) {
+                            pnfe = e;
+                        }
+                    }                                    
+                };
+                if (inRemoteCallback) {
+                    r.run();
+                }
+                else {
+                    EventQueue.invokeAndWait(r);
+                }
+            }
+            catch (InterruptedException ie) {
+                ie.printStackTrace();
+            }
+            catch (InvocationTargetException ite) {
+                ite.printStackTrace();
+            }
+            
+            if (pnoe != null) throw pnoe;
+            if (pnfe != null) throw pnfe;
+            
+            return result[0];
+        }
+    }
+
+    public String getToString()
+    {
+        return bClass.getName();
+    }
+
+    public String getQualifiedName()
+        throws RemoteException
+    {
+        return bClass.getName();
+    }
+
+    public File getJavaFile()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        return bClass.getJavaFile();
+    }
+
+    public void remove() throws ProjectNotOpenException, PackageNotFoundException, ClassNotFoundException, RemoteException
+    {
+        bClass.remove();
+    }
+
+
+    public void setReadOnly(boolean b) throws RemoteException, ProjectNotOpenException, PackageNotFoundException 
+    {
+        if(bClass != null && bClass.getEditor() != null) {
+            bClass.getEditor().setReadOnly(b);
+        }
+    }
+
+    @Override
+    public void autoIndent() throws ProjectNotOpenException, PackageNotFoundException
+    {
+        final Editor e = bClass.getEditor();
+        EventQueue.invokeLater(new Runnable() {
+            public void run()
+            {
+                MoeEditor bje = (MoeEditor)bluej.extensions.editor.EditorBridge.getEditor(e);
+                MoeSyntaxDocument doc = bje.getSourceDocument();
+                
+                MoeIndent.calculateIndentsAndApply(doc,0);
+            }
+        });        
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RCompileObserver.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RCompileObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..7139956a45ac267c48ff339cad8ac45e5f544035
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RCompileObserver.java
@@ -0,0 +1,50 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.io.File;
+import java.rmi.RemoteException;
+
+import bluej.compiler.Diagnostic;
+
+/**
+ * A remote version of the CompileObserver interface.
+ * 
+ * @author Davin McCall
+ */
+public interface RCompileObserver extends java.rmi.Remote
+{
+    /**
+     * A compilation job has started.
+     */
+    void startCompile(File[] sources) throws RemoteException;
+    
+    /**
+     * An error or warning message occurred during compilation
+     */
+    void compilerMessage(Diagnostic diagnostic) throws RemoteException;
+    
+    /**
+     * A Compilation job finished.
+     */
+    void endCompile(File[] sources, boolean succesful) throws RemoteException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RConstructor.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RConstructor.java
new file mode 100644
index 0000000000000000000000000000000000000000..a95a47f7d9c0cf52ee639b9c499878f2daf91458
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RConstructor.java
@@ -0,0 +1,58 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import bluej.extensions.InvocationArgumentException;
+import bluej.extensions.InvocationErrorException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+
+/**
+ * @author Poul Henriksen
+ * @version $Id: RConstructor.java 8234 2010-09-02 10:17:24Z nccb $
+ */
+public interface RConstructor
+    extends Remote
+{
+    public Class<?>[] getParameterTypes()
+        throws RemoteException;
+
+    public boolean matches(Class<?>[] parameter)
+        throws RemoteException;
+
+    public RObject newInstance(Object[] initargs)
+        throws RemoteException, ProjectNotOpenException, PackageNotFoundException, InvocationArgumentException,
+        InvocationErrorException;
+
+    /**
+     * This should actually have been the toString() method, but we cannot add
+     * an exception to an inherited method. And to get RMI to work, it must
+     * throw RemoteException.
+     * 
+     * @return
+     */
+    public String getToString()
+        throws RemoteException;
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RConstructorImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RConstructorImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..306489b5a5d4e697e1a87eacb87805e251f68c25
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RConstructorImpl.java
@@ -0,0 +1,101 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.rmi.RemoteException;
+
+import bluej.extensions.BConstructor;
+import bluej.extensions.BObject;
+import bluej.extensions.InvocationArgumentException;
+import bluej.extensions.InvocationErrorException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+
+/**
+ * @author Poul Henriksen
+ * @version $Id: RConstructorImpl.java 8234 2010-09-02 10:17:24Z nccb $
+ */
+public class RConstructorImpl extends java.rmi.server.UnicastRemoteObject
+    implements RConstructor
+{
+    private BConstructor bConstructor;
+
+    /**
+     * @return
+     */
+    public Class<?>[] getParameterTypes()
+        throws RemoteException
+    {
+        return bConstructor.getParameterTypes();
+    }
+
+    /**
+     * @param parameter
+     * @return
+     */
+    public boolean matches(Class<?>[] parameter)
+        throws RemoteException
+    {
+        return bConstructor.matches(parameter);
+    }
+
+    /**
+     * @param initargs
+     * @return
+     * @throws ProjectNotOpenException
+     * @throws PackageNotFoundException
+     * @throws InvocationArgumentException
+     * @throws InvocationErrorException
+     */
+    public RObject newInstance(Object[] initargs)
+        throws RemoteException, ProjectNotOpenException, PackageNotFoundException, InvocationArgumentException,
+        InvocationErrorException
+    {
+        BObject bObject = bConstructor.newInstance(initargs);
+        RObject rObject = WrapperPool.instance().getWrapper(bObject);
+        return rObject;
+    }
+
+    /**
+     * @throws RemoteException
+     */
+    public RConstructorImpl()
+        throws RemoteException
+    {
+        super();
+    }
+
+    public RConstructorImpl(BConstructor bConstructor)
+        throws RemoteException
+    {
+        this.bConstructor = bConstructor;
+        if (bConstructor == null) {
+            throw new NullPointerException("Argument can't be null");
+        }
+    }
+
+    public String getToString()
+        throws RemoteException
+    {
+        return bConstructor.toString();
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RField.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RField.java
new file mode 100644
index 0000000000000000000000000000000000000000..319ae479f522963adb2b3c002196c447f362aa8a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RField.java
@@ -0,0 +1,61 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.rmi.RemoteException;
+
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public interface RField
+    extends java.rmi.Remote
+{
+    /**
+     * @return
+     */
+    public abstract int getModifiers()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public abstract String getName()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public abstract Class<?> getType()
+        throws RemoteException;
+
+    /**
+     * @param onThis
+     * @return
+     * @throws ProjectNotOpenException
+     * @throws PackageNotFoundException
+     */
+    public abstract RObject getValue(RObject onThis)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RFieldImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RFieldImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f072e7d67ee4312ed6fdac3e41b9dbc46d31230
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RFieldImpl.java
@@ -0,0 +1,135 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import greenfoot.util.GreenfootUtil;
+
+import java.rmi.RemoteException;
+
+import bluej.extensions.BField;
+import bluej.extensions.BObject;
+import bluej.extensions.ClassNotFoundException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+
+/**
+ * Implementation of the remote field interface.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class RFieldImpl extends java.rmi.server.UnicastRemoteObject
+    implements RField
+{
+    private BField bField;
+
+    /**
+     * Construct a remote field wrapper for a BField object.
+     */
+    public RFieldImpl(BField bField)
+        throws RemoteException
+    {
+        this.bField = bField;
+        if (bField == null) {
+            throw new NullPointerException("Argument can't be null");
+        }
+    }
+
+    /*
+     * @see rmiextension.wrappers.RField#getModifiers()
+     */
+    @Override
+    public int getModifiers()
+    {
+        return bField.getModifiers();
+    }
+
+    /*
+     * @see rmiextension.wrappers.RField#getName()
+     */
+    @Override
+    public String getName()
+    {
+        return bField.getName();
+    }
+
+    /*
+     * @see rmiextension.wrappers.RField#getType()
+     */
+    @Override
+    public Class<?> getType()
+    {
+        return bField.getType();
+    }
+
+    /*
+     * @see rmiextension.wrappers.RField#getValue(rmiextension.wrappers.RObject)
+     */
+    @Override
+    public RObject getValue(RObject onThis)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        try {
+            Object fieldValue = bField.getValue(null);
+
+            if (fieldValue instanceof BObject) {
+
+                BObject bFieldValue = (BObject) fieldValue;
+
+                String newInstanceName = "noName";
+                
+                try {
+                    String className = bFieldValue.getBClass().getName();
+                    className = GreenfootUtil.extractClassName(className);
+                    newInstanceName = className.substring(0, 1).toLowerCase() + className.substring(1);
+                }
+                catch (ClassNotFoundException e) {
+                    e.printStackTrace();
+                }
+                    
+                //must add to object bench in order to get the menu later
+                bFieldValue.addToBench(newInstanceName);
+
+                RObject wrapper = WrapperPool.instance().getWrapper(bFieldValue);
+                return wrapper;
+            }
+            else {
+                return null;
+            }
+        }
+        catch (ProjectNotOpenException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        catch (PackageNotFoundException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        catch (RemoteException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+        //Object obj =bField.getValue(onThis.getBObject());
+        // onThis.getField(RField)
+        return null;
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RJobQueue.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RJobQueue.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3a66f8009fe9b3b82d2cd217fda52a7fe41eb31
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RJobQueue.java
@@ -0,0 +1,37 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.io.File;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Interface for a remote compiler job queue.
+ * 
+ * @author Davin McCall
+ */
+public interface RJobQueue extends Remote
+{
+    public void compile(File [] files, RCompileObserver observer)
+            throws RemoteException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RJobQueueImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RJobQueueImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..6dd8dda682ea62ada440671b142028c8f4be18f1
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RJobQueueImpl.java
@@ -0,0 +1,111 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2010,2011,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.io.File;
+import java.rmi.RemoteException;
+import java.rmi.ServerError;
+import java.rmi.ServerException;
+
+import bluej.compiler.CompileObserver;
+import bluej.compiler.Diagnostic;
+import bluej.compiler.JobQueue;
+import bluej.pkgmgr.Package;
+import bluej.utility.Debug;
+
+/**
+ * Implementation of a remote compiler queue.
+ * 
+ * @author Davin McCall
+ */
+public class RJobQueueImpl extends java.rmi.server.UnicastRemoteObject
+    implements RJobQueue
+{
+    private JobQueue queue;
+    private Package pkg;
+    
+    public RJobQueueImpl(Package pkg) throws RemoteException
+    {
+        super();
+        queue = JobQueue.getJobQueue();
+        this.pkg = pkg;
+    }
+    
+    @Override
+    public void compile(File[] files, final RCompileObserver observer)
+            throws RemoteException
+    {
+        CompileObserver cobserver = new CompileObserver() {
+            @Override
+            public void startCompile(File[] sources)
+            {
+                try {
+                    observer.startCompile(sources);
+                }
+                catch (ServerError se) {
+                    Debug.reportError("Server error in RMI call: " + se.getCause());
+                }
+                catch (ServerException se) {
+                    Debug.reportError("Server error in RMI call: " + se.getCause());
+                }
+                catch (RemoteException re) {
+                    // probably, connection broken
+                }
+            }
+            @Override
+            public void endCompile(File[] sources, boolean successful)
+            {
+                try {
+                    observer.endCompile(sources, successful);
+                }
+                catch (ServerError se) {
+                    Debug.reportError("Server error in RMI call: " + se.getCause());
+                }
+                catch (ServerException se) {
+                    Debug.reportError("Server error in RMI call: " + se.getCause());
+                }
+                catch (RemoteException re) {
+                    // probably, connection broken
+                }
+            }
+            @Override
+            public boolean compilerMessage(Diagnostic diagnostic)
+            {
+                try {
+                    observer.compilerMessage(diagnostic);
+                }
+                catch (ServerError se) {
+                    Debug.reportError("Server error in RMI call: " + se.getCause());
+                }
+                catch (ServerException se) {
+                    Debug.reportError("Server error in RMI call: " + se.getCause());
+                }
+                catch (RemoteException re) {
+                    // probably, connection broken
+                }
+                return true;
+            }
+        };
+        queue.addJob(files, cobserver, pkg.getProject().getClassLoader(), pkg.getPath(), true,
+                pkg.getProject().getProjectCharset());
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RObject.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..28d6c191183c33ecd3f134371b5074ca91236414
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RObject.java
@@ -0,0 +1,99 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.rmi.RemoteException;
+
+import bluej.extensions.ClassNotFoundException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+
+/**
+ * @author Poul Henriksen
+ * @version $Id: RObject.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public interface RObject
+    extends java.rmi.Remote
+{
+    /**
+     * @param instanceName
+     * @throws ProjectNotOpenException
+     * @throws PackageNotFoundException
+     */
+    public abstract void addToBench(String instanceName)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    /**
+     * @return
+     * @throws ProjectNotOpenException
+     * @throws ClassNotFoundException
+     * @throws PackageNotFoundException 
+     */
+    public abstract RClass getRClass()
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException, PackageNotFoundException;
+
+    /**
+     * @return
+     */
+    public abstract String getInstanceName()
+        throws RemoteException;
+
+    /**
+     * @return
+     * @throws ProjectNotOpenException
+     * @throws PackageNotFoundException
+     */
+    public abstract RPackage getPackage()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    /**
+     * @throws ProjectNotOpenException
+     * @throws PackageNotFoundException
+     */
+    public abstract void removeFromBench()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    
+    // no longer needed
+//    public MenuSerializer getMenu()
+//        throws RemoteException;
+    
+    /**
+     * Allow an arbitrary method to be invoked with arbitrary parameters.
+     * 
+     * If a compilation error occurs, returns the generated error message
+     * preceded by an exclamation mark (!).<p>
+     * 
+     * If successful and a return value exists, put the return value on the
+     * bench and return its name.<p>
+     * 
+     * Otherwise (no error, no return value) return null. 
+     * 
+     * @param method    The name of the method to invoke
+     * @param argTypes  The classnames of the argument types of the method
+     * @param argVals   The argument "values" as they should appear in the shell code
+     * @throws RemoteException
+     */
+    public String invokeMethod(String method, String [] argTypes, String [] argVals)
+        throws RemoteException;
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RObjectImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RObjectImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..21ea610d19f6aefecc33310ebd7f85ed8bd712aa
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RObjectImpl.java
@@ -0,0 +1,205 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.extensions.BClass;
+import bluej.extensions.BObject;
+import bluej.extensions.BPackage;
+import bluej.extensions.ClassNotFoundException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.views.MethodView;
+import bluej.views.View;
+
+/**
+ * @author Poul Henriksen
+ * @version $Id: RObjectImpl.java 7934 2010-07-27 05:55:36Z davmac $
+ */
+public class RObjectImpl extends UnicastRemoteObject
+    implements RObject
+{
+    /**
+     * @throws RemoteException
+     */
+    protected RObjectImpl()
+        throws RemoteException
+    {
+        super();
+    }
+
+    public RObjectImpl(BObject bObject)
+        throws RemoteException
+    {
+        this.bObject = bObject;
+        if (bObject == null) {
+            throw new NullPointerException("Argument can't be null");
+        }
+    }
+
+    BObject bObject;
+
+    /**
+     * @param instanceName
+     * @throws ProjectNotOpenException
+     * @throws PackageNotFoundException
+     */
+    public void addToBench(String instanceName)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        bObject.addToBench(instanceName);
+    }
+
+    /**
+     * @return
+     * @throws ProjectNotOpenException
+     * @throws ClassNotFoundException
+     * @throws PackageNotFoundException 
+     */
+    public RClass getRClass()
+        throws ProjectNotOpenException, ClassNotFoundException, RemoteException, PackageNotFoundException
+    {
+        BClass wrapped = bObject.getBClass();
+        RClass wrapper = WrapperPool.instance().getWrapper(wrapped);
+        return wrapper;
+
+    }
+
+    /**
+     * @return
+     */
+    public String getInstanceName()
+        throws RemoteException
+    {
+        return bObject.getInstanceName();
+    }
+
+    /**
+     * @return
+     * @throws ProjectNotOpenException
+     * @throws PackageNotFoundException
+     */
+    public RPackage getPackage()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        BPackage wrapped = bObject.getPackage();
+        RPackage wrapper = WrapperPool.instance().getWrapper(wrapped);
+        return wrapper;
+
+    }
+
+    /**
+     * @throws ProjectNotOpenException
+     * @throws PackageNotFoundException
+     */
+    public void removeFromBench()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        bObject.removeFromBench();
+    }
+
+    /**
+     * Invoke a static method.
+     * 
+     * Return is the compiler error message preceded by '!' in the case of
+     * a compile time error, or the name of the constructed object, or null
+     * if a run-time error occurred.
+     * 
+     * @param className  The class for which to invoke the method
+     * @param methodName The name of the method
+     * @param argTypes   The argument types of the method (class names)
+     * @param args       The argument strings to use
+     * @return   The name of the returned object (see notes above).
+     */
+    public String invokeMethod(String method, String [] argTypes, String [] argVals)
+        throws RemoteException
+    {
+        try {
+            // First find the method. The existing extension mechanism makes
+            // this pretty much impossible; BClass only allows searching for
+            // Declared methods - we want a method that may have been declared
+            // in a super class.
+            
+            // TODO: add to extension mechanism(?).
+            // For the moment, cheat and use reflection.
+            
+            Class<?> BObjectClass = BObject.class;
+            Field oWrapperField = BObjectClass.getDeclaredField("objectWrapper");
+            oWrapperField.setAccessible(true);
+            ObjectWrapper ow = (ObjectWrapper) oWrapperField.get(bObject);
+
+            // Debug.message("Calling method: " + method + " on object: " + ow.getName());
+            String className = ow.getObject().getClassName();
+            PkgMgrFrame pmf = ow.getFrame();
+            Class<?> oClass = ow.getPackage().loadClass(className);
+            
+            // can't just use getMethods() as that doesn't give us package-private
+            // methods, sigh...
+            View mClassView = View.getView(oClass);
+            
+            while (mClassView != null) {
+                MethodView [] methods = mClassView.getDeclaredMethods();
+                findMethod:
+                for (int i = 0; i < methods.length; i++) {
+                    // This method is not the one we're looking for if it's
+                    // private, has a different name, or a different number
+                    // of parameters
+                    if ((methods[i].getModifiers() & Modifier.PRIVATE) != 0)
+                        continue;
+                    if (! methods[i].getName().equals(method))
+                        continue;
+                    if (methods[i].getParameterCount() != argTypes.length)
+                        continue;
+                    
+                    // ... or if any of the parameters are different
+                    Class<?> [] params = methods[i].getParameters();
+                    for (int j = 0; j < params.length; j++) {
+                        if (! params[j].getName().equals(argTypes[j]))
+                            continue findMethod;
+                    }
+                    
+                    // we've found the right method
+                    // theMethod = methods[i];
+                    return RPackageImpl.invokeCallable(pmf, methods[i], ow, argVals);
+                }
+                
+                // try the super class
+                mClassView = mClassView.getSuper();
+            }
+        }
+        catch (NoSuchFieldException nsfe) {
+            nsfe.printStackTrace();
+        }
+        catch (IllegalAccessException iae) {
+            iae.printStackTrace();
+        }
+        
+        throw new IllegalArgumentException("method not found.");
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPackage.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPackage.java
new file mode 100644
index 0000000000000000000000000000000000000000..e64386e82b11f16441c7d10ffc240d480eb7c5f8
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPackage.java
@@ -0,0 +1,163 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.io.File;
+import java.rmi.RemoteException;
+
+import bluej.extensions.BObject;
+import bluej.extensions.CompilationNotStartedException;
+import bluej.extensions.MissingJavaFileException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+/**
+ * The remote interface for a package.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public interface RPackage
+    extends java.rmi.Remote
+{
+    /**
+     * Compile files in the package which need compilation, optionally waiting until the
+     * compilation finishes.
+     */
+    public abstract void compile(boolean waitCompileEnd)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException, CompilationNotStartedException;
+
+    /**
+     * Rebuild the package, i.e. compile all classes regardless of their current state.
+     */
+    public abstract void compileAll()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException, CompilationNotStartedException;
+
+    /**
+     * Get access to the compiler queue.
+     */
+    public abstract RJobQueue getCompiler()
+        throws RemoteException;
+    
+    /**
+     * Get a remote reference to a class within the package.
+     */
+    public abstract RClass getRClass(String name)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    /**
+     * Get all classes within the package
+     */
+    public abstract RClass[] getRClasses()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    /**
+     * Get the qualified name of this package.
+     */
+    public abstract String getName()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    /**
+     * Get the object with the given instance name from the object bench of this package.
+     */
+    public abstract RObject getObject(String instanceName)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    /**
+     * Get all objects from the object bench of this package.
+     */
+    public abstract BObject[] getObjects()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    /**
+     * Get the project to which this package belongs.
+     */
+    public abstract RProject getProject()
+        throws ProjectNotOpenException, RemoteException;
+
+    /**
+     * Reload the entire package.
+     */
+    public abstract void reload()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    /**
+     * Returns the directory where this package is stored.
+     * 
+     * @throws ProjectNotOpenException
+     *             if the project this package is part of has been closed by the
+     *             user.
+     * @throws PackageNotFoundException
+     *             if the package has been deleted by the user.
+     */
+    public abstract File getDir()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException;
+
+    /**
+     * Creates a new Class with the given name. The class name must not be a
+     * fully qualified name, and the .java file must already exist.
+     * 
+     * @throws ProjectNotOpenException
+     *             if the project this package is part of has been closed by the
+     *             user.
+     * @throws PackageNotFoundException
+     *             if the package has been deleted by the user.
+     * @throws MissingJavaFileException
+     *             if the .java file for the new class does not exist.
+     */
+    public abstract RClass newClass(String className)
+        throws RemoteException, ProjectNotOpenException, PackageNotFoundException, MissingJavaFileException;
+
+    /**
+     * Invoke a constructor. Put the resulting object on the bench.<p>
+     * 
+     * Return is the compiler error message preceded by '!' in the case of
+     * a compile time error, or the name of the constructed object, or null
+     * if a run-time error occurred.
+     * 
+     * @param className   The fully qualified name of the class to instantiate
+     * @param argTypes    The (raw) argument types of the constructor
+     * @param args        The argument strings to use
+     * @return   The name of the constructed object (see notes).
+     */
+    public String invokeConstructor(String className, String [] argTypes, String [] args)
+        throws RemoteException;
+    
+    /**
+     * Invoke a static method.
+     * 
+     * Return is the compiler error message preceded by '!' in the case of
+     * a compile time error, or the name of the constructed object, or null
+     * if a run-time error occurred.
+     * 
+     * @param className  The class for which to invoke the method
+     * @param methodName The name of the method
+     * @param argTypes   The argument types of the method (class names)
+     * @param args       The argument strings to use (as Java expressions)
+     * @return   The name of the returned object (see notes above).
+     */
+    public String invokeMethod(String className, String methodName, String [] argTypes, String [] args)
+        throws RemoteException;
+
+    /**
+     * Close the package.
+     */
+    public void close() throws RemoteException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPackageImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPackageImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..a268399fd15decd1e0fbe99d382b57b99571f125
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPackageImpl.java
@@ -0,0 +1,558 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.awt.EventQueue;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.rmi.RemoteException;
+
+import javax.swing.SwingUtilities;
+
+import bluej.debugmgr.Invoker;
+import bluej.debugmgr.objectbench.ObjectWrapper;
+import bluej.extensions.BClass;
+import bluej.extensions.BObject;
+import bluej.extensions.BPackage;
+import bluej.extensions.CompilationNotStartedException;
+import bluej.extensions.MissingJavaFileException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.pkgmgr.Package;
+import bluej.pkgmgr.PkgMgrFrame;
+import bluej.views.CallableView;
+import bluej.views.ConstructorView;
+import bluej.views.MethodView;
+import bluej.views.View;
+
+/**
+ * This class is a wrapper for a BlueJ package
+ * 
+ * @see bluej.extensions.BPackage
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class RPackageImpl extends java.rmi.server.UnicastRemoteObject
+    implements RPackage
+{
+
+    //The BlueJ-package (from extensions) that is wrapped
+    BPackage bPackage;
+    
+    // Used to hold exceptions thrown when we try to compile
+    private static CompilationNotStartedException cnse;
+    private static PackageNotFoundException pnfe;
+    private static ProjectNotOpenException pnoe;
+    // Returns from various methods
+    private static RClass rclassResult;
+    private static RClass[] rclassArrayResult;
+
+    public RPackageImpl(BPackage bPackage)
+        throws java.rmi.RemoteException
+    {
+        super();
+        this.bPackage = bPackage;
+    }
+
+    /////////////////////
+    // Wrapper Methods
+    /////////////////////
+
+    /*
+     * @see rmiextension.wrappers.RPackage#compile(boolean)
+     */
+    public void compile(boolean waitCompileEnd)
+        throws ProjectNotOpenException, PackageNotFoundException, CompilationNotStartedException
+    {
+        bPackage.compile(waitCompileEnd);
+    }
+    
+    /*
+     * @see rmiextension.wrappers.RPackage#compileAll()
+     */
+    public void compileAll()
+        throws ProjectNotOpenException, PackageNotFoundException, CompilationNotStartedException
+    {
+        synchronized (RPackageImpl.class) {
+            try {
+                cnse = null;
+                pnfe = null;
+                pnoe = null;
+                
+                SwingUtilities.invokeAndWait(new Runnable() {
+                    public void run()
+                    {
+                        try {
+                            bPackage.compileAll(false);
+                        }
+                        catch (CompilationNotStartedException ce) {
+                            cnse = ce;
+                        }
+                        catch (PackageNotFoundException pe) {
+                            pnfe = pe;
+                        }
+                        catch (ProjectNotOpenException pe) {
+                            pnoe = pe;
+                        }
+                    } 
+                });
+            }
+            catch (InvocationTargetException ite) {
+                ite.printStackTrace();
+            }
+            catch (InterruptedException ie) {
+                ie.printStackTrace();
+            }
+            
+            if (cnse != null) {
+                throw cnse;
+            }
+            if (pnfe != null) {
+                throw pnfe;
+            }
+            if (pnoe != null) {
+                throw pnoe;
+            }
+        }
+    }
+
+    /*
+     * @see rmiextension.wrappers.RPackage#getCompiler()
+     */
+    @Override
+    public RJobQueue getCompiler() throws RemoteException
+    {
+        return new RJobQueueImpl(getPackage());
+    }
+    
+    /*
+     * @see rmiextension.wrappers.RPackage#getRClass(java.lang.String)
+     */
+    public RClass getRClass(final String name)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        synchronized (RPackageImpl.class) {
+            pnoe = null;
+            pnfe = null;
+            
+            try {
+                EventQueue.invokeAndWait(new Runnable() {
+                   public void run()
+                    {
+                       try {
+                           rclassResult = WrapperPool.instance().getWrapper(bPackage.getBClass(name));
+                       } catch (RemoteException e) {
+                           e.printStackTrace();
+                       } catch (ProjectNotOpenException e) {
+                           pnoe = e;
+                       } catch (PackageNotFoundException e) {
+                           pnfe = e;
+                       }
+                    } 
+                });
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            } catch (InvocationTargetException e) {
+                e.printStackTrace();
+            }
+            
+            if (pnoe != null) throw pnoe;
+            if (pnfe != null) throw pnfe;
+            
+            return rclassResult;
+        }
+    }
+
+    /*
+     * @see rmiextension.wrappers.RPackage#getRClasses()
+     */
+    public RClass[] getRClasses()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        synchronized (RPackageImpl.this) {
+            pnoe = null;
+            pnfe = null;
+
+            try {
+                EventQueue.invokeAndWait(new Runnable() {
+                    public void run()
+                    {
+                        try {
+                            BClass[] bClasses = bPackage.getClasses();
+                            int length = bClasses.length;
+                            RClass[] rClasses = new RClass[length];
+                            for (int i = 0; i < length; i++) {
+                                rClasses[i] = WrapperPool.instance().getWrapper(bClasses[i]);
+                            }
+
+                            rclassArrayResult = rClasses;
+                        }
+                        catch (ProjectNotOpenException e) {
+                            pnoe = e;
+                        }
+                        catch (PackageNotFoundException e) {
+                            pnfe = e;
+                        }
+                        catch (RemoteException re) {}
+                    }
+                });
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            } catch (InvocationTargetException e) {
+                e.printStackTrace();
+            }
+
+            if (pnoe != null) throw pnoe;
+            if (pnfe != null) throw pnfe;
+
+            return rclassArrayResult;
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.RPackage#getName()
+     */
+    public String getName()
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        return bPackage.getName();
+    }
+
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.RPackage#getObject(java.lang.String)
+     */
+    public RObject getObject(String instanceName)
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        BObject wrapped = bPackage.getObject(instanceName);
+        RObject wrapper = WrapperPool.instance().getWrapper(wrapped);
+        return wrapper;
+    }
+
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.RPackage#getObjects()
+     */
+    public BObject[] getObjects()
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        return bPackage.getObjects();
+    }
+
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.RPackage#getProject()
+     */
+    public RProject getProject()
+        throws RemoteException, ProjectNotOpenException
+    {
+        return WrapperPool.instance().getWrapper(bPackage.getProject());
+    }
+
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.RPackage#reload()
+     */
+    public void reload()
+        throws ProjectNotOpenException, PackageNotFoundException
+    {
+        final Exception[] exception = new Exception[1];
+        
+        try {
+            EventQueue.invokeAndWait(new Runnable() {
+                @Override
+                public void run()
+                {
+                    try {
+                        bPackage.reload();
+                    } catch (ProjectNotOpenException e) {
+                        exception[0] = e;
+                    } catch (PackageNotFoundException e) {
+                        exception[0] = e;
+                    }
+                }
+            });
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } catch (InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+        
+        if (exception[0] != null) {
+            if (exception[0] instanceof ProjectNotOpenException) {
+                throw (ProjectNotOpenException) exception[0];
+            }
+            else {
+                throw (PackageNotFoundException) exception[0];
+            }
+        }
+    }
+
+    /*
+     * @see greenfoot.remote.RPackage#getDir()
+     */
+    public File getDir()
+        throws ProjectNotOpenException, PackageNotFoundException, RemoteException
+    {
+        return bPackage.getDir();
+    }
+
+    /*
+     * @see greenfoot.remote.RPackage#newClass(java.lang.String)
+     */
+    public RClass newClass(final String className)
+        throws RemoteException, ProjectNotOpenException, PackageNotFoundException, MissingJavaFileException
+    {
+        final RClass[] wrapper = new RClass[1];
+        final Exception[] exception = new Exception[1];
+        
+        try {
+            EventQueue.invokeAndWait(new Runnable() {
+                @Override
+                public void run()
+                {
+                    try {
+                        BClass wrapped = bPackage.newClass(className);
+                        wrapper[0] = WrapperPool.instance().getWrapper(wrapped);
+                        bPackage.reload();
+                    }
+                    catch (ProjectNotOpenException pnoe) {
+                        exception[0] = pnoe;
+                    }
+                    catch (PackageNotFoundException pnfe) {
+                        exception[0] = pnfe;
+                    }
+                    catch (MissingJavaFileException mjfe) {
+                        exception[0] = mjfe;
+                    }
+                    catch (RemoteException re) {
+                        exception[0] = re;
+                    }
+                }
+            });
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } catch (InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+        
+        if (exception[0] != null) {
+            if (exception[0] instanceof ProjectNotOpenException) {
+                throw (ProjectNotOpenException) exception[0];
+            }
+            else if (exception[0] instanceof PackageNotFoundException) {
+                throw (PackageNotFoundException) exception[0];
+            }
+            else if (exception[0] instanceof MissingJavaFileException) {
+                throw (MissingJavaFileException) exception[0];
+            }
+            else {
+                throw (RemoteException) exception[0];
+            }
+        }
+        
+        return wrapper[0];
+    }
+    
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.RPackage#invokeMethod(java.lang.String, java.lang.String, java.lang.String[], java.lang.String[])
+     */
+    public String invokeMethod(String className, String methodName, String [] argTypes, String [] args)
+    {
+        Package pkg = getPackage();
+        Class<?> cl = pkg.loadClass(className);
+        View mClassView = View.getView(cl);
+        
+        // do we really need to search super classes?
+        while (mClassView != null) {
+            MethodView [] methods = mClassView.getDeclaredMethods();
+            findMethod:
+            for (int i = 0; i < methods.length; i++) {
+                // This method is not the one we're looking for if it's
+                // private, has a different name, or a different number
+                // of parameters
+                if ((methods[i].getModifiers() & Modifier.PRIVATE) != 0)
+                    continue;
+                if ((methods[i].getModifiers() & Modifier.STATIC) == 0)
+                    continue;
+                if (! methods[i].getName().equals(methodName))
+                    continue;
+                if (methods[i].getParameterCount() != argTypes.length)
+                    continue;
+                
+                // ... or if any of the parameters are different
+                Class<?> [] params = methods[i].getParameters();
+                for (int j = 0; j < params.length; j++) {
+                    if (! params[j].getName().equals(argTypes[j]))
+                        continue findMethod;
+                }
+                
+                // we've found the right method
+                return invokeCallable(PkgMgrFrame.findFrame(pkg), methods[i], null, args);
+            }
+            
+            // try the super class
+            mClassView = mClassView.getSuper();
+        }
+
+        throw new IllegalArgumentException("method not found");
+    }
+    
+    /**
+     * Invoke a constructor. Put the resulting object on the bench.<p>
+     * 
+     * Return is the compiler error message preceded by '!' in the case of
+     * a compile time error, or the name of the constructed object, or null
+     * if a run-time error occurred.
+     * 
+     * @param className   The fully qualified name of the class to instantiate
+     * @param argTypes    The (raw) argument types of the constructor
+     * @param args        The argument strings to use
+     * @return   The name of the constructed object (see notes).
+     */
+    public String invokeConstructor(String className, String [] argTypes, String [] args)
+    {
+        // TODO support generics
+        
+        Package pkg = getPackage();
+        Class<?> cl = pkg.loadClass(className);
+        View mClassView = View.getView(cl);
+
+        // Search through the constructors for the one we want.
+        ConstructorView [] constructors = mClassView.getConstructors();
+        consLoop:
+        for (int i = 0; i < constructors.length; i++) {
+            // check the parameter count and types match
+            if (constructors[i].getParameterCount() != argTypes.length)
+                continue;
+            Class<?> [] params = constructors[i].getParameters();
+            for (int j = 0; j < params.length; j++) {
+                if (! params[j].getName().equals(argTypes[j]))
+                    continue consLoop;
+            }
+            
+            // we have a match
+            return invokeCallable(PkgMgrFrame.findFrame(pkg), constructors[i], null, args);
+        }
+        
+        // Couldn't find the requested constructor
+        throw new IllegalArgumentException("constructor not found");
+    }
+    
+    /**
+     * Invoke a callable (a constructor, static method or instance method).<p>
+     * 
+     * Return is the compiler error message preceded by '!' in the case of
+     * a compile time error, or the name of the constructed object, or null
+     * if a run-time error occurred.
+     * 
+     * @param pkg     The package from which to perform the invocation
+     * @param cv      The constructor or method to invoke
+     * @param ow      The object to invoke against (null for static method
+     *                or constructor)
+     * @param argVals The arguments to apply to the call
+     */
+    public static String invokeCallable(PkgMgrFrame pmf, CallableView cv, ObjectWrapper ow, String [] argVals)
+    {
+        // also used by RPackage
+        InvocationResultWatcher watcher = new InvocationResultWatcher();
+        Invoker invoker;
+        if (ow == null)
+            invoker = new Invoker(pmf, cv, watcher);
+        else
+            invoker = new Invoker(pmf, (MethodView) cv, ow, watcher);
+
+        synchronized (watcher) {
+            invoker.invokeDirect(argVals);
+            try {
+                watcher.wait();
+            }
+            catch (InterruptedException ie) {}
+        }
+        
+        if (watcher.errorMsg != null) {
+            // some error occurred
+            return "!" + watcher.errorMsg;
+        }
+        else {
+            if (watcher.resultObj == null)
+                return null;
+            
+            ObjectWrapper newOw = ObjectWrapper.getWrapper(pmf, pmf.getObjectBench(), watcher.resultObj, watcher.resultObj.getGenType(), "result");
+            pmf.getObjectBench().addObject(newOw);
+            Package pkg = pmf.getPackage();
+            pkg.getDebugger().addObject(pkg.getId(), newOw.getName(), newOw.getObject());
+            //BObject newBObject = bObject.getPackage().getObject(newOw.getName());
+            //WrapperPool.instance().getWrapper(newBObject);
+            //new RObjectImpl(newBObject);
+            return newOw.getName();
+        }
+    }
+    
+    /**
+     * Helper routine. Extract the actual Bluej package (bluej.pkgmgr.Package)
+     * from the extension interface (BPackage) using reflection.
+     */
+    private Package getPackage()
+    {
+        try {
+            Class<?> bPackageClass = bPackage.getClass();
+            Field packageId = bPackageClass.getDeclaredField("packageId");
+            packageId.setAccessible(true);
+            Object identifier = packageId.get(bPackage);
+            
+            Class<?> identifierClass = identifier.getClass();
+            Method getBluejPackage = identifierClass.getDeclaredMethod("getBluejPackage", new Class[0]);
+            getBluejPackage.setAccessible(true);
+            Package pkg = (bluej.pkgmgr.Package) getBluejPackage.invoke(identifier, (Object[]) null);
+            
+            return pkg;
+        }
+        catch (NoSuchFieldException nsfe) { nsfe.printStackTrace(); }
+        catch (IllegalAccessException iae) { iae.printStackTrace(); }
+        catch (NoSuchMethodException nsme) { nsme.printStackTrace(); }
+        catch (InvocationTargetException ite) { ite.printStackTrace(); }
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.RPackage#close()
+     */
+    public void close()
+        throws RemoteException
+    {
+
+        //Make sure that we first close "greenfoot" package becuase we don't want that to auto open the next time.
+        try {
+            PkgMgrFrame pkgMgrFrame = (PkgMgrFrame) bPackage.getFrame();
+            pkgMgrFrame.doClose(false, true);
+        }
+        catch (ProjectNotOpenException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        catch (PackageNotFoundException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPrintStream.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPrintStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..42a05d640d3378516ba48adf8f16debcc47be808
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPrintStream.java
@@ -0,0 +1,34 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.rmi.RemoteException;
+
+/**
+ * Interface for printing to a remote stream.
+ *
+ * @author Davin
+ */
+public interface RPrintStream extends java.rmi.Remote
+{
+    void print(String text) throws RemoteException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPrintStreamImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPrintStreamImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..4849489ef65ac20439312f4d0968adfc28df3a0d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RPrintStreamImpl.java
@@ -0,0 +1,57 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.rmi.RemoteException;
+
+import bluej.utility.Debug;
+
+/**
+ * Remote print stream implementation, forwards printed text to the debug log.
+ * 
+ * @author Davin McCall
+ */
+public class RPrintStreamImpl extends java.rmi.server.UnicastRemoteObject
+    implements RPrintStream
+{
+    public RPrintStreamImpl() throws RemoteException
+    {
+        super();
+    }
+    
+    @Override
+    public void print(String text) throws RemoteException
+    {
+        try {
+            Writer writer = Debug.getDebugStream();
+            synchronized (writer) {
+                writer.write(text);
+                writer.flush();
+            }
+        }
+        catch (IOException ioe) {
+            System.err.println("IOException writing to debug log.");
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RProject.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RProject.java
new file mode 100644
index 0000000000000000000000000000000000000000..e71f45e751cb75a648cdaf58c461e5dd933f44a8
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RProject.java
@@ -0,0 +1,149 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.io.File;
+import java.rmi.RemoteException;
+
+import rmiextension.wrappers.event.RProjectListener;
+import bluej.extensions.PackageAlreadyExistsException;
+import bluej.extensions.ProjectNotOpenException;
+
+/**
+ * Interface for a remote project.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public interface RProject
+    extends java.rmi.Remote
+{
+    /**
+     * Close this project. This will cause the local VM to
+     * terminate.
+     */
+    public abstract void close()
+        throws RemoteException;
+
+    /**
+     * Get the project directory.
+     * @throws ProjectNotOpenException
+     */
+    public abstract File getDir()
+        throws ProjectNotOpenException, RemoteException;
+
+    /**
+     * Get the project's name.
+     * 
+     * @throws ProjectNotOpenException
+     */
+    public abstract String getName()
+        throws ProjectNotOpenException, RemoteException;
+
+    /**
+     * Get a remote reference to a package within the project, by name.
+     * 
+     * @throws ProjectNotOpenException
+     */
+    public abstract RPackage getPackage(String name)
+        throws ProjectNotOpenException, RemoteException;
+
+    /**
+     * Create a new package within the project.
+     * 
+     * @throws ProjectNotOpenException     if the project is no longer open
+     * @throws PackageAlreadyExistsException  if the package already exists
+     * @throws RemoteException  if a remote exception occurred
+     */
+    public abstract RPackage newPackage(String fullyQualifiedName)
+        throws ProjectNotOpenException, PackageAlreadyExistsException, RemoteException;
+
+    /**
+     * Get all packages within this project.
+     * 
+     * @throws ProjectNotOpenException
+     */
+    public abstract RPackage[] getPackages()
+        throws ProjectNotOpenException, RemoteException;
+
+    /**
+     * Request a save of all open files in the project.
+     * 
+     * @throws ProjectNotOpenException
+     */
+    public abstract void save()
+        throws ProjectNotOpenException, RemoteException;
+    
+    /**
+     * Open the "readme" editor for this project.
+     * 
+     * @throws ProjectNotOpenException
+     * @throws RemoteException
+     */
+    public abstract void openReadmeEditor()
+        throws ProjectNotOpenException, RemoteException;
+    
+    /**
+     * Add a listener to this project
+     * @param listener  The listener to add
+     * @throws RemoteException
+     */
+    public abstract void addListener(RProjectListener listener)
+        throws RemoteException;
+    
+    /**
+     * Remove a listener from this project
+     * @param listener  The listener to remove
+     * @throws RemoteException
+     */
+    public abstract void removeListener(RProjectListener listener)
+        throws RemoteException;
+    
+    /**
+     * Get a remote reference to the object in the launcher "transport" field. The purpose
+     * of this is to allow obtaining a remote reference to a local object, by means of:
+     * 
+     * <ol>
+     * <li>(in the user VM) Storing a reference to the object into the transport field
+     * <li>Calling this method.
+     * </ul>
+     * 
+     * @return  A remote reference to the transport field object.
+     * @throws RemoteException  If an RMI exception occurs.
+     */
+    public abstract RObject getRemoteObject()
+        throws RemoteException;
+
+    /**
+     * Toggles the BlueJ debugger (Shows/Hides)
+     * @throws RemoteException  if an RMI error occurs
+     */
+    public abstract void toggleExecControls()
+        throws RemoteException;
+
+    /**
+     * @return	Whether or not the debugger window is currently visible
+     * @throws RemoteException   if an RMI error occurs
+     * @throws ProjectNotOpenException   if the project is no longer open
+     */
+    public abstract boolean isExecControlVisible()
+        throws RemoteException, ProjectNotOpenException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RProjectImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RProjectImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..3f839a57cbe27ad3177724d436d32a3504d6a6de
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/RProjectImpl.java
@@ -0,0 +1,393 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import greenfoot.util.DebugUtil;
+
+import java.awt.EventQueue;
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.rmi.ConnectException;
+import java.rmi.ConnectIOException;
+import java.rmi.RemoteException;
+import java.rmi.ServerError;
+import java.rmi.ServerException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import rmiextension.wrappers.event.RProjectListener;
+import bluej.debugger.DebuggerThread;
+import bluej.debugmgr.ExecControls;
+import bluej.extensions.BClass;
+import bluej.extensions.BField;
+import bluej.extensions.BObject;
+import bluej.extensions.BPackage;
+import bluej.extensions.BProject;
+import bluej.extensions.PackageAlreadyExistsException;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.pkgmgr.Project;
+import bluej.pkgmgr.target.ReadmeTarget;
+import bluej.utility.Debug;
+
+/**
+ * Implementation of the remote project interface.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class RProjectImpl extends java.rmi.server.UnicastRemoteObject
+    implements RProject
+{
+    /** The BlueJ-package (from extensions) that is wrapped */
+    private BProject bProject;
+    
+    /** The Greenfoot simulation thread */
+    private DebuggerThread simulationThread;
+    
+    /**
+     * A launcher object with a field called "transportField", used to
+     * allow obtaining a remote reference to a debug VM object.
+     */
+    private BObject transportObject;
+    
+    private List<RProjectListener> listeners = new ArrayList<RProjectListener>();
+
+    /**
+     * Construct an RProjectImpl - generally only should be called from
+     * WrapperPool (use WrapperPool.instance().getWrapper(...)).
+     * 
+     * @param bProject  The project to wrap
+     * @throws java.rmi.RemoteException
+     */
+    public RProjectImpl(BProject bProject)
+        throws java.rmi.RemoteException
+    {
+        super();
+        this.bProject = bProject;
+        
+        try {
+            Project thisProject = Project.getProject(bProject.getDir());
+            thisProject.getExecControls().setRestrictedClasses(DebugUtil.restrictedClassesAsNames());
+        } catch (ProjectNotOpenException e) {
+            Debug.message("Project not open while setting up debugger");
+        }
+    }
+
+    /**
+     * Set the object used for passing objects from the remote (debug VM) to the local VM.
+     * The object should have a field of type Object called "transportField".
+     */
+    public synchronized void setTransportObject(BObject transportObject)
+    {
+        this.transportObject = transportObject;
+        notifyAll();
+    }
+    
+    /*
+     * @see rmiextension.wrappers.RProject#close()
+     */
+    public void close()
+    {
+        notifyClosing();
+        
+        try {
+            bProject.close();
+        }
+        catch (ProjectNotOpenException pnoe) {
+            // this isn't a big deal; after all, we were trying to close
+            // the project...
+        }
+    }
+    
+    /**
+     * Inform listeners that this project will close. This should be called if the
+     * project will be closed other than by calling RProjectImpl.close().
+     */
+    public void notifyClosing()
+    {
+        List<RProjectListener> listeners;
+        synchronized (this.listeners) {
+            listeners = new ArrayList<RProjectListener>(this.listeners);
+        }
+        
+        Iterator<RProjectListener> i = listeners.iterator();
+        while (i.hasNext()) {
+            RProjectListener listener = i.next();
+            try {
+                listener.projectClosing();
+            }
+            catch (ServerError se) {
+                Debug.reportError("Error when scenario closing: ", se);
+            }
+            catch (ServerException se) {
+                Debug.reportError("Error when scenario closing: ", se);
+            }
+            catch (ConnectException ce) {
+                // Almost certainly due to the other VM having already terminated:
+                // So we'll ignore it.
+                removeListener(listener);
+            }
+            catch (ConnectIOException cioe) {
+                // Almost certainly due to the other VM having already terminated:
+                // So we'll ignore it.
+                removeListener(listener);
+            }
+            catch (RemoteException re) {
+                Debug.reportError("Error when scenario closing: ", re);
+                removeListener(listener);
+            }
+        }
+    }
+
+    /*
+     * @see rmiextension.wrappers.RProject#getDir()
+     */
+    public File getDir()
+        throws ProjectNotOpenException
+    {
+        return bProject.getDir();
+    }
+
+    /*
+     * @see rmiextension.wrappers.RProject#getName()
+     */
+    public String getName()
+        throws ProjectNotOpenException
+    {
+        return bProject.getName();
+    }
+
+    /*
+     * @see rmiextension.wrappers.RProject#getPackage(java.lang.String)
+     */
+    public RPackage getPackage(String name)
+        throws ProjectNotOpenException, RemoteException
+    {
+        BPackage bPackage = bProject.getPackage(name);
+        RPackage wrapper = null;
+        if (bPackage != null) {
+            wrapper = WrapperPool.instance().getWrapper(bPackage);
+        }
+
+        return wrapper;
+    }
+
+    /*
+     * @see rmiextension.wrappers.RProject#newPackage(java.lang.String)
+     */
+    public RPackage newPackage(String fullyQualifiedName)
+        throws ProjectNotOpenException, PackageAlreadyExistsException, RemoteException
+    {
+        BPackage bPackage = bProject.newPackage(fullyQualifiedName);
+        RPackage wrapper = null;
+        wrapper = WrapperPool.instance().getWrapper(bPackage);
+
+        return wrapper;
+    }
+
+    /*
+     * @see rmiextension.wrappers.RProject#getPackages()
+     */
+    public RPackage[] getPackages()
+        throws ProjectNotOpenException, RemoteException
+    {
+        BPackage[] packages = bProject.getPackages();
+        int length = packages.length;
+        RPackage[] wrapper = new RPackage[length];
+
+        for (int i = 0; i < length; i++) {
+            wrapper[i] = WrapperPool.instance().getWrapper(packages[i]);
+        }
+
+        return wrapper;
+    }
+
+    /*
+     * @see rmiextension.wrappers.RProject#save()
+     */
+    public void save()
+        throws ProjectNotOpenException
+    {
+        bProject.save();
+    }
+    
+    /*
+     * @see rmiextension.wrappers.RProject#openReadmeEditor()
+     */
+    public void openReadmeEditor()
+        throws ProjectNotOpenException
+    {
+        Project thisProject = Project.getProject(bProject.getDir());
+        bluej.pkgmgr.Package defaultPackage = thisProject.getPackage("");
+        ReadmeTarget readmeTarget = defaultPackage.getReadmeTarget();
+        readmeTarget.open();
+    }
+    
+    /*
+     * @see rmiextension.wrappers.RProject#addListener(rmiextension.wrappers.event.RProjectListener)
+     */
+    public void addListener(RProjectListener listener)
+        throws RemoteException
+    {
+        synchronized (listeners) {
+            listeners.add(listener);
+        }
+    }
+    
+    /*
+     * @see rmiextension.wrappers.RProject#removeListener(rmiextension.wrappers.event.RProjectListener)
+     */
+    public void removeListener(RProjectListener listener)
+    {
+        synchronized (listeners) {
+            listeners.remove(listener);
+        }
+    }
+    
+    /*
+     * @see rmiextension.wrappers.RProject#getRemoteObject()
+     */
+    @Override
+    public synchronized RObject getRemoteObject() throws RemoteException
+    {
+        try {
+            while (transportObject == null) {
+                wait();
+            }
+            BClass bClass = transportObject.getBClass();
+            BField field = bClass.getField("transportField");
+            final BObject value = (BObject) field.getValue(transportObject);
+            
+            if (value != null) {
+                EventQueue.invokeAndWait(new Runnable() {
+                    @Override
+                    public void run()
+                    {
+                        try {
+                            String cName = value.getBClass().getName();
+                            cName = cName.toLowerCase();
+                            value.addToBench(cName);
+                        }
+                        catch (bluej.extensions.ClassNotFoundException cnfe) { }
+                        catch (PackageNotFoundException pnfe) { }
+                        catch (ProjectNotOpenException pnoe) { }
+                    }
+                });
+                
+                value.getInstanceName();
+                return WrapperPool.instance().getWrapper(value);
+            }
+        }
+        catch (InterruptedException ie) { }
+        catch (bluej.extensions.ClassNotFoundException cnfe) { }
+        catch (PackageNotFoundException pnfe) { }
+        catch (ProjectNotOpenException pnoe) { }
+        catch (InvocationTargetException ite) {
+            Debug.reportError("Error adding object to bench", ite);
+        }
+        return null;
+    }
+
+    /*
+     * @see rmiextension.wrappers.RProject#isExecControlVisible()
+     */
+    @Override
+    public boolean isExecControlVisible() throws RemoteException
+    {
+        class ExecControlsChecker implements Runnable
+        {
+            public boolean visible;
+            
+            @Override
+            public void run()
+            {
+                try {
+                    Project thisProject = Project.getProject(bProject.getDir());
+                    ExecControls execControls = thisProject.getExecControls();
+                    execControls.setRestrictedClasses(DebugUtil.restrictedClassesAsNames());
+                    visible = execControls.isVisible();
+                }
+                catch (ProjectNotOpenException pnoe) {
+                    // This is ignorable.
+                }
+            }
+        }
+        
+        ExecControlsChecker checker = new ExecControlsChecker();
+        try {
+            EventQueue.invokeAndWait(checker);
+        }
+        catch (InvocationTargetException ite) {
+            Debug.reportError("Error checking exec controls visibility", ite);
+        }
+        catch (InterruptedException ie) { }
+        
+        return checker.visible;
+    }
+
+    /*
+     * @see rmiextension.wrappers.RProject#toggleExecControls()
+     */
+    @Override
+    public void toggleExecControls() throws RemoteException 
+    {
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run()
+            {
+                try {
+                    Project thisProject = Project.getProject(bProject.getDir());
+                    ExecControls execControls = thisProject.getExecControls();
+                    execControls.makeSureThreadIsSelected(simulationThread);
+                    execControls.showHide(!execControls.isVisible());
+                    execControls.setRestrictedClasses(DebugUtil.restrictedClassesAsNames());
+                }
+                catch (ProjectNotOpenException pnoe) {
+                    // This is ignorable.
+                }
+            } 
+        });
+    }
+    
+    /**
+     * Set the Greenfoot simulation thread.
+     */
+    public void setSimulationThread(DebuggerThread simulationThread)
+    {
+        this.simulationThread = simulationThread;
+        try {
+            final Project thisProject = Project.getProject(bProject.getDir());
+            EventQueue.invokeLater(new Runnable() {
+                @Override
+                public void run()
+                {
+                    if (thisProject.hasExecControls()) {
+                        ExecControls execControls = thisProject.getExecControls();
+                        execControls.makeSureThreadIsSelected(RProjectImpl.this.simulationThread);
+                    }
+                }
+            });
+        }
+        catch (ProjectNotOpenException pnoe) { }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/WrapperPool.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/WrapperPool.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa680ef18ba6b232454c4e4b75ac99995067c839
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/WrapperPool.java
@@ -0,0 +1,200 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010,2012  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers;
+
+import java.lang.ref.WeakReference;
+import java.rmi.RemoteException;
+import java.util.WeakHashMap;
+
+import bluej.extensions.BClass;
+import bluej.extensions.BConstructor;
+import bluej.extensions.BField;
+import bluej.extensions.BObject;
+import bluej.extensions.BPackage;
+import bluej.extensions.BProject;
+
+/**
+ * This class has a pool of RMI-wrappers that have been created. This is used to
+ * avoid getting more than one RMI-wrapper for each object. Doing this, makes it
+ * possible to use reference equality ('==' operator) to test if two objects are the same.
+ * 
+ * <p>Remember to "release" objects when they are no longer needed.
+ * 
+ * <p>This class is thread-safe.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class WrapperPool
+{    
+    static private WrapperPool instance = new WrapperPool();
+
+    // Note, the value must generally be a weak reference to the wrapper, because
+    // the wrapper maintains a hard reference back to the key.
+    private WeakHashMap<Object,Object> pool = new WeakHashMap<Object,Object>();
+
+    private WrapperPool()
+    {
+
+    }
+
+    public static WrapperPool instance()
+    {
+        return instance;
+    }
+
+    public synchronized RProjectImpl getWrapper(BProject wrapped)
+        throws RemoteException
+    {
+        RProjectImpl wrapper = null;
+        WeakReference<?> wrProj = (WeakReference<?>) pool.get(wrapped);
+        
+        if (wrProj != null) {
+            wrapper = (RProjectImpl) wrProj.get();
+        }
+        
+        if (wrapper == null) {
+            wrapper = new RProjectImpl(wrapped);
+            pool.put(wrapped, new WeakReference<RProjectImpl>(wrapper));
+        }
+        
+        return wrapper;
+    }
+
+    public synchronized RPackage getWrapper(BPackage wrapped)
+        throws RemoteException
+    {
+        if (wrapped == null) {
+            return null;
+        }
+        
+        RPackage wrapper = null;
+        WeakReference<?> wrPkg = (WeakReference<?>) pool.get(wrapped);
+        if (wrPkg != null) {
+            wrapper = (RPackage) wrPkg.get();
+        }
+        
+        if (wrapper == null) {
+            wrapper = new RPackageImpl(wrapped);
+            pool.put(wrapped, new WeakReference<RPackage>(wrapper));
+        }
+        return wrapper;
+    }
+
+    public synchronized RClass getWrapper(BClass wrapped)
+        throws RemoteException
+    {
+        if (wrapped == null) {
+            return null;
+        }
+        
+        RClass wrapper = null;
+        WeakReference<?> wrClass = (WeakReference<?>) pool.get(wrapped);
+        if (wrClass != null) {
+            wrapper = (RClass) wrClass.get();
+        }
+        
+        if (wrapper == null) {
+            wrapper = new RClassImpl(wrapped);
+            pool.put(wrapped, new WeakReference<RClass>(wrapper));
+        }
+        return wrapper;
+    }
+
+    /**
+     * Get a remote wrapper for a BConstructor.
+     */
+    public synchronized RConstructor getWrapper(BConstructor wrapped)
+        throws RemoteException
+    {
+        if (wrapped == null) {
+            return null;
+        }
+        
+        RConstructor wrapper = null;
+        WeakReference<?> wrCons = (WeakReference<?>) pool.get(wrapped);
+        if (wrCons != null) {
+            wrapper = (RConstructor) wrCons.get();
+        }
+        
+        if (wrapper == null) {
+            wrapper = new RConstructorImpl(wrapped);
+            pool.put(wrapped, new WeakReference<RConstructor>(wrapper));
+        }
+        
+        return wrapper;
+    }
+
+    /**
+     * Get a remote wrapper for a BObject.
+     */
+    public synchronized RObject getWrapper(BObject wrapped)
+        throws RemoteException
+    {
+        if (wrapped == null) {
+            return null;
+        }
+        
+        RObject wrapper = null;
+        WeakReference<?> wrObj = (WeakReference<?>) pool.get(wrapped);
+        if (wrObj != null) {
+            wrapper = (RObject) wrObj.get();
+        }
+
+        if (wrapper == null) {
+            wrapper = new RObjectImpl(wrapped);
+            pool.put(wrapped, new WeakReference<RObject>(wrapper));
+        }
+        
+        return wrapper;
+    }
+
+    /**
+     * Get a remote wrapper for a BField.
+     */
+    public synchronized RField getWrapper(BField wrapped)
+        throws RemoteException
+    {
+        if (wrapped == null) {
+            return null;
+        }
+        
+        RField wrapper = null;
+        WeakReference<?> wrField = (WeakReference<?>) pool.get(wrapped);
+        if (wrField != null) {
+            wrapper = (RField) wrField.get();
+        }
+        
+        if (wrapper == null) {
+            wrapper = new RFieldImpl(wrapped);
+            pool.put(wrapped, new WeakReference<RField>(wrapper));
+        }
+        return wrapper;
+    }
+
+    /**
+     * Removes a wrapper for a particular object (key) from the pool
+     */
+    public synchronized void remove(Object wrapped)
+    {
+        pool.remove(wrapped);        
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassEvent.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b7692bc266be424325859f0850fdae2964d4d3c
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassEvent.java
@@ -0,0 +1,64 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import rmiextension.wrappers.RClass;
+
+/**
+ * Interface for remote class events.
+ * 
+ * @author Davin McCall
+ * @version $Id: RClassEvent.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public interface RClassEvent extends Remote
+{
+    /**
+     * Get the event ID.
+     * 
+     * @throws RemoteException
+     */
+    public int getEventId() throws RemoteException;
+    
+    /**
+     * Get the class on which the event occurred.
+     * 
+     * @throws RemoteException
+     */
+    public RClass getRClass() throws RemoteException;
+    
+    /**
+     * Check whether the class in the event is compiled.
+     * 
+     * @throws RemoteException
+     */
+    public boolean isClassCompiled() throws RemoteException;
+    
+    /**
+     * Get the new class name (valid for a CHANGING_NAME event).
+     * 
+     * @throws RemoteException
+     */
+    public String getOldName() throws RemoteException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassEventImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassEventImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..ced65fcee3d62d25fa91f48893ed057dddc9da3b
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassEventImpl.java
@@ -0,0 +1,86 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.RemoteException;
+
+import rmiextension.wrappers.RClass;
+import rmiextension.wrappers.WrapperPool;
+import bluej.extensions.event.ClassEvent;
+
+/**
+ * Implementation of a remote class event. Wraps a local ClassEvent.
+ * 
+ * @author Davin McCall
+ * @version $Id: RClassEventImpl.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class RClassEventImpl extends java.rmi.server.UnicastRemoteObject
+    implements RClassEvent
+{
+    private ClassEvent event;
+    
+    /**
+     * Construct a remote event wrapper for the supplied ClassEvent.
+     * 
+     * @throws RemoteException
+     */
+    public RClassEventImpl(ClassEvent event)
+        throws RemoteException
+    {
+        super();
+        this.event = event;
+    }
+    
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.event.RClassEvent#getEventId()
+     */
+    public int getEventId()
+        throws RemoteException
+    {
+        return event.getEventId();
+    }
+    
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.event.RClassEvent#getRClass()
+     */
+    public RClass getRClass() throws RemoteException
+    {
+        return WrapperPool.instance().getWrapper(event.getBClass());
+    }
+    
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.event.RClassEvent#isClassCompiled()
+     */
+    public boolean isClassCompiled() throws RemoteException
+    {
+        return event.isClassCompiled();
+    }
+    
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.event.RClassEvent#getNewName()
+     */
+    public String getOldName()
+        throws RemoteException
+    {
+        return event.getOldName();
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassListener.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..4aab7b35d1d6e22f94009395586473b07e044674
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassListener.java
@@ -0,0 +1,49 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2011  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Interface representing remote class listeners.
+ * 
+ * @author Davin McCall
+ */
+public interface RClassListener extends Remote
+{
+    /**
+     * The class state changed. This means that the class source was
+     * changed so that the class is now uncompiled, or the class was
+     * compiled.
+     * 
+     * <p>Use event.isCompiled() to check the class compilation state.
+     * 
+     * <p>This is called from the Swing event queue on the main VM, so calls which
+     * require access to the event queue must not be made from the same thread.
+     * 
+     * @throws RemoteException  if a remote exception occurs
+     */
+    public void classStateChanged(RClassEvent event)
+        throws RemoteException;
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassListenerImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassListenerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b2105ba8ad0efda5cb82528c054c55bf1e04dad
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassListenerImpl.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.RemoteException;
+
+/**
+ * Abstract implementation of the RClassListener interface
+ * @author dam
+ *
+ */
+public abstract class RClassListenerImpl extends java.rmi.server.UnicastRemoteObject
+    implements RClassListener
+{
+    public RClassListenerImpl() throws RemoteException
+    {
+        super();
+    }
+    
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.event.RClassListener#classStateChanged(rmiextension.wrappers.event.RClassEvent)
+     */
+    public abstract void classStateChanged(RClassEvent event)
+        throws RemoteException;
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassListenerWrapper.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassListenerWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce5187a019bc474572922ce80d86a9fc033a1930
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RClassListenerWrapper.java
@@ -0,0 +1,65 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.RemoteException;
+import java.rmi.ServerError;
+import java.rmi.ServerException;
+
+import rmiextension.wrappers.RBlueJImpl;
+
+import bluej.extensions.event.ClassEvent;
+import bluej.extensions.event.ClassListener;
+import bluej.utility.Debug;
+
+/**
+ * Wraps a remote class listener (RClassListener) as a local listener.
+ */
+public class RClassListenerWrapper implements ClassListener
+{
+    private RClassListener remoteListener;
+    private RBlueJImpl bluej;
+    
+    public RClassListenerWrapper(RBlueJImpl bluej, RClassListener listener)
+    {
+        this.bluej = bluej;
+        remoteListener = listener;
+    }
+    
+    public void classStateChanged(ClassEvent event)
+    {
+        try {
+            remoteListener.classStateChanged(new RClassEventImpl(event));
+        }
+        catch (ServerError se) {
+            Debug.reportError("Remote class listener ServerError", se.getCause());
+        }
+        catch (ServerException se) {
+            Debug.reportError("Remote class listener ServerException", se.getCause());
+        }
+        catch (RemoteException re) {
+            // Connection interrupted or other problem; remote VM no longer accessible
+            bluej.removeClassListener(remoteListener);
+        }
+    }
+
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileEvent.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..cda8e0530188ee7292aa4c098e5229bb533d99a1
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileEvent.java
@@ -0,0 +1,71 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.io.File;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: RCompileEvent.java 6216 2009-03-30 13:41:07Z polle $
+ *  
+ */
+public interface RCompileEvent
+    extends Remote
+{
+    /**
+     * @return
+     */
+    public int getErrorLineNumber()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public String getErrorMessage()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public int getEvent()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public File[] getFiles()
+        throws RemoteException;
+
+    /**
+     * @param aLineNumber
+     */
+    public void setErrorLineNumber(int aLineNumber)
+        throws RemoteException;
+
+    /**
+     * @param anErrorMessage
+     */
+    public void setErrorMessage(String anErrorMessage)
+        throws RemoteException;
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileEventImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileEventImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b9932c19d9100df25488aa3c565ab5542becea4
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileEventImpl.java
@@ -0,0 +1,95 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.io.File;
+import java.rmi.RemoteException;
+
+import bluej.extensions.event.CompileEvent;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: RCompileEventImpl.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public class RCompileEventImpl extends java.rmi.server.UnicastRemoteObject
+    implements RCompileEvent
+{
+    private CompileEvent compileEvent;
+
+    /**
+     * @param event
+     */
+    public RCompileEventImpl(CompileEvent event)
+        throws RemoteException
+    {
+        super();
+        this.compileEvent = event;
+    }
+
+    /**
+     * @return
+     */
+    public int getErrorLineNumber()
+    {
+        return compileEvent.getErrorLineNumber();
+    }
+
+    /**
+     * @return
+     */
+    public String getErrorMessage()
+    {
+        return compileEvent.getErrorMessage();
+    }
+
+    /**
+     * @return
+     */
+    public int getEvent()
+    {
+        return compileEvent.getEvent();
+    }
+
+    /**
+     * @return
+     */
+    public File[] getFiles()
+    {
+        return compileEvent.getFiles();
+    }
+
+    /**
+     * @param aLineNumber
+     */
+    public void setErrorLineNumber(int aLineNumber)
+    {
+        compileEvent.setErrorLineNumber(aLineNumber);
+    }
+
+    /**
+     * @param anErrorMessage
+     */
+    public void setErrorMessage(String anErrorMessage)
+    {
+        compileEvent.setErrorMessage(anErrorMessage);
+    }
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileListener.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9e69e62b8d030339c9bd5b68dfba0fbe0589e8d
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileListener.java
@@ -0,0 +1,68 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: RCompileListener.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public interface RCompileListener
+    extends Remote
+{
+    /**
+     * This method will be called when a compilation starts. If a long operation
+     * must be performed you should start a Thread.
+     */
+    public void compileStarted(RCompileEvent event)
+        throws RemoteException;
+
+    /**
+     * This method will be called when there is a report of a compile error. If
+     * a long operation must be performed you should start a Thread.
+     */
+    public void compileError(RCompileEvent event)
+        throws RemoteException;
+
+    /**
+     * This method will be called when there is a report of a compile warning.
+     * If a long operation must be performed you should start a Thread.
+     */
+    public void compileWarning(RCompileEvent event)
+        throws RemoteException;
+
+    /**
+     * This method will be called when the compile ends successfully. If a long
+     * operation must be performed you should start a Thread.
+     */
+    public void compileSucceeded(RCompileEvent event)
+        throws RemoteException;
+
+    /**
+     * This method will be called when the compile fails. If a long operation
+     * must be performed you should start a Thread.
+     */
+    public void compileFailed(RCompileEvent event)
+        throws RemoteException;
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileListenerImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileListenerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..58b0d700eab24f2e67950de37263cfb3984e3364
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileListenerImpl.java
@@ -0,0 +1,74 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.RemoteException;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: RCompileListenerImpl.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public abstract class RCompileListenerImpl extends java.rmi.server.UnicastRemoteObject
+    implements RCompileListener
+{
+
+    public RCompileListenerImpl()
+        throws RemoteException
+    {
+        super();
+    }
+
+    /**
+     * This method will be called when a compilation starts. If a long operation
+     * must be performed you should start a Thread.
+     */
+    public abstract void compileStarted(RCompileEvent event)
+        throws RemoteException;
+
+    /**
+     * This method will be called when there is a report of a compile error. If
+     * a long operation must be performed you should start a Thread.
+     */
+    public abstract void compileError(RCompileEvent event)
+        throws RemoteException;
+
+    /**
+     * This method will be called when there is a report of a compile warning.
+     * If a long operation must be performed you should start a Thread.
+     */
+    public abstract void compileWarning(RCompileEvent event)
+        throws RemoteException;
+
+    /**
+     * This method will be called when the compile ends successfully. If a long
+     * operation must be performed you should start a Thread.
+     */
+    public abstract void compileSucceeded(RCompileEvent event)
+        throws RemoteException;
+
+    /**
+     * This method will be called when the compile fails. If a long operation
+     * must be performed you should start a Thread.
+     */
+    public abstract void compileFailed(RCompileEvent event)
+        throws RemoteException;
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileListenerWrapper.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileListenerWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0cad619a08e4b6bf9b99671eba6c4136c70ce6a
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RCompileListenerWrapper.java
@@ -0,0 +1,232 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.io.File;
+import java.rmi.RemoteException;
+import java.rmi.ServerError;
+import java.rmi.ServerException;
+
+import rmiextension.wrappers.RBlueJImpl;
+
+import bluej.extensions.BClass;
+import bluej.extensions.BPackage;
+import bluej.extensions.BProject;
+import bluej.extensions.PackageNotFoundException;
+import bluej.extensions.ProjectNotOpenException;
+import bluej.extensions.event.CompileEvent;
+import bluej.extensions.event.CompileListener;
+import bluej.utility.Debug;
+
+/**
+ * Wrapper for remote compile listeners.
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class RCompileListenerWrapper
+    implements CompileListener
+{
+    private RCompileListener remoteListener;
+    private BProject project;
+    private RBlueJImpl blueJ;
+
+    public RCompileListenerWrapper(RCompileListener remoteListener, BProject project, RBlueJImpl blueJ)
+    {
+        this.remoteListener = remoteListener;
+        this.project = project;
+        this.blueJ = blueJ;
+    }
+
+    /**
+     * Returns true if the files are in the project associated with this listener.
+     */
+    private boolean isInThisProject(File[] files)
+    {
+        if(files.length <= 0) {
+            //Can't think of a reason why this should happen, but according to extensions API it can.
+            return true;
+        }
+        File file = files[0];
+        try {
+            BPackage[] packages = project.getPackages();
+            for (int i = 0; i < packages.length; i++) {
+                BPackage pkg = packages[i];
+                BClass[] classes = pkg.getClasses();
+                for (int j = 0; j < classes.length; j++) {
+                    BClass cls = classes[j];
+                    if(cls.getJavaFile().equals(file)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        catch (ProjectNotOpenException e) {
+            e.printStackTrace();
+        }
+        catch (PackageNotFoundException e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    /*
+     * @see bluej.extensions.event.CompileListener#compileStarted(bluej.extensions.event.CompileEvent)
+     */
+    public void compileStarted(final CompileEvent event)
+    {
+        if (isInThisProject(event.getFiles())) {
+            new Thread() {
+                @Override
+                public void run()
+                {
+                    try {
+                        RCompileEvent rEvent = new RCompileEventImpl(event);
+                        remoteListener.compileStarted(rEvent);
+                    }
+                    catch (ServerError se) {
+                        Debug.reportError("Remote compile listener ServerError", se.getCause());
+                    }
+                    catch (ServerException se) {
+                        Debug.reportError("Remote compile listener ServerException", se.getCause());
+                    }
+                    catch (RemoteException re) {
+                        // Connection interrupted or other problem; remote VM no longer accessible
+                        blueJ.removeCompileListener(remoteListener);
+                    }
+                }
+            }.start();
+        }
+    }
+
+    
+    /*
+     * @see bluej.extensions.event.CompileListener#compileError(bluej.extensions.event.CompileEvent)
+     */
+    public void compileError(final CompileEvent event)
+    {
+        if (isInThisProject(event.getFiles())) {
+            new Thread() {
+                @Override
+                public void run()
+                {
+                    try {
+                        RCompileEvent rEvent = new RCompileEventImpl(event);
+                        remoteListener.compileError(rEvent);
+                    }
+                    catch (ServerError se) {
+                        Debug.reportError("Remote compile listener ServerError", se.getCause());
+                    }
+                    catch (ServerException se) {
+                        Debug.reportError("Remote compile listener ServerException", se.getCause());
+                    }
+                    catch (RemoteException re) {
+                        // Connection interrupted or other problem; remote VM no longer accessible
+                        blueJ.removeCompileListener(remoteListener);
+                    }
+                }
+            }.start();
+        }
+    }
+
+    /*
+     * @see bluej.extensions.event.CompileListener#compileWarning(bluej.extensions.event.CompileEvent)
+     */
+    public void compileWarning(final CompileEvent event)
+    {
+        if (isInThisProject(event.getFiles())) {
+            new Thread() {
+                @Override
+                public void run()
+                {
+                    try {
+                        RCompileEvent rEvent = new RCompileEventImpl(event);
+                        remoteListener.compileWarning(rEvent);
+                    }
+                    catch (ServerError se) {
+                        Debug.reportError("Remote compile listener ServerError", se.getCause());
+                    }
+                    catch (ServerException se) {
+                        Debug.reportError("Remote compile listener ServerException", se.getCause());
+                    }
+                    catch (RemoteException re) {
+                        // Connection interrupted or other problem; remote VM no longer accessible
+                        blueJ.removeCompileListener(remoteListener);
+                    }
+                }
+            }.start();
+        }
+    }
+
+    /*
+     * @see bluej.extensions.event.CompileListener#compileSucceeded(bluej.extensions.event.CompileEvent)
+     */
+    public void compileSucceeded(final CompileEvent event)
+    {
+        if (isInThisProject(event.getFiles())) {
+            new Thread() {
+                public void run() {
+                    try {
+                        RCompileEvent rEvent = new RCompileEventImpl(event);
+                        remoteListener.compileSucceeded(rEvent);
+                    }
+                    catch (ServerError se) {
+                        Debug.reportError("Remote compile listener ServerError", se.getCause());
+                    }
+                    catch (ServerException se) {
+                        Debug.reportError("Remote compile listener ServerException", se.getCause());
+                    }
+                    catch (RemoteException re) {
+                        // Connection interrupted or other problem; remote VM no longer accessible
+                        blueJ.removeCompileListener(remoteListener);
+                    }
+                }
+            }.start();
+        }
+    }
+
+    /*
+     * @see bluej.extensions.event.CompileListener#compileFailed(bluej.extensions.event.CompileEvent)
+     */
+    public void compileFailed(final CompileEvent event)
+    {
+        if (isInThisProject(event.getFiles())) {
+            new Thread() {
+                public void run() {
+                    try {
+                        RCompileEvent rEvent = new RCompileEventImpl(event);
+                        remoteListener.compileFailed(rEvent);
+                    }
+                    catch (ServerError se) {
+                        Debug.reportError("Remote compile listener ServerError", se.getCause());
+                    }
+                    catch (ServerException se) {
+                        Debug.reportError("Remote compile listener ServerException", se.getCause());
+                    }
+                    catch (RemoteException re) {
+                        // Connection interrupted or other problem; remote VM no longer accessible
+                        blueJ.removeCompileListener(remoteListener);
+                    }
+                }
+            }.start();
+        }
+    }
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationEvent.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..3079124fe86e309154b26aa190b30ece26526404
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationEvent.java
@@ -0,0 +1,83 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import bluej.extensions.BPackage;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: RInvocationEvent.java 8234 2010-09-02 10:17:24Z nccb $
+ */
+public interface RInvocationEvent
+    extends Remote
+{
+    /**
+     * @return
+     */
+    public String getClassName()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public int getInvocationStatus()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public String getMethodName()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public String getObjectName()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public BPackage getPackage()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public String[] getParameters()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public Object getResult()
+        throws RemoteException;
+
+    /**
+     * @return
+     */
+    public Class<?>[] getSignature()
+        throws RemoteException;
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationEventImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationEventImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a68ec23464fbf99002e1b8275d61681dafd2035
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationEventImpl.java
@@ -0,0 +1,132 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.RemoteException;
+
+import rmiextension.wrappers.WrapperPool;
+import bluej.extensions.BObject;
+import bluej.extensions.BPackage;
+import bluej.extensions.event.InvocationEvent;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: RInvocationEventImpl.java 8234 2010-09-02 10:17:24Z nccb $
+ */
+public class RInvocationEventImpl extends java.rmi.server.UnicastRemoteObject
+    implements RInvocationEvent
+{
+
+    private InvocationEvent invocationEvent;
+
+    /**
+     * @throws RemoteException
+     */
+    protected RInvocationEventImpl(InvocationEvent invocationEvent)
+        throws RemoteException
+    {
+        super();
+        this.invocationEvent = invocationEvent;
+    }
+
+    /**
+     * @return
+     */
+    public String getClassName()
+        throws RemoteException
+    {
+        return invocationEvent.getClassName();
+    }
+
+    /**
+     * @return
+     */
+    public int getInvocationStatus()
+        throws RemoteException
+    {
+        return invocationEvent.getInvocationStatus();
+    }
+
+    /**
+     * @return
+     */
+    public String getMethodName()
+        throws RemoteException
+    {
+        return invocationEvent.getMethodName();
+    }
+
+    /**
+     * @return
+     */
+    public String getObjectName()
+        throws RemoteException
+    {
+        return invocationEvent.getObjectName();
+    }
+
+    /**
+     * @return
+     */
+    public BPackage getPackage()
+        throws RemoteException
+    {
+        return invocationEvent.getPackage();
+    }
+
+    /**
+     * @return
+     */
+    public String[] getParameters()
+        throws RemoteException
+    {
+        return invocationEvent.getParameters();
+    }
+
+    /**
+     * @return
+     */
+    public Object getResult()
+        throws RemoteException
+    {
+        Object result = invocationEvent.getResult();
+        if (result == null) {
+            return null;
+        }
+
+        if (result instanceof BObject) {
+            result = WrapperPool.instance().getWrapper((BObject) result);
+        }
+
+        return result;
+    }
+
+    /**
+     * @return
+     */
+    public Class<?>[] getSignature()
+        throws RemoteException
+    {
+        return invocationEvent.getSignature();
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationListener.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc9704eaa7890fad8c9d05468c6716d7c9d56160
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationListener.java
@@ -0,0 +1,39 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.RemoteException;
+
+/**
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: RInvocationListener.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public interface RInvocationListener
+    extends java.rmi.Remote
+{
+
+    /**
+     * This method will be called when an invocation has finished.
+     */
+    public void invocationFinished(RInvocationEvent event)
+        throws RemoteException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationListenerImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationListenerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a224b607049495ed96b64c94b46e3f07b00feb3
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationListenerImpl.java
@@ -0,0 +1,53 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.RemoteException;
+
+/**
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ * @version $Id: RInvocationListenerImpl.java,v 1.3 2004/11/18 09:43:50 polle
+ *          Exp $
+ */
+public abstract class RInvocationListenerImpl extends java.rmi.server.UnicastRemoteObject
+    implements RInvocationListener
+{
+
+    /**
+     * @throws RemoteException
+     */
+    public RInvocationListenerImpl(/* InvocationListener invocationListener */)
+        throws RemoteException
+    {
+        super();
+        //  this.invocationListener = invocationListener;
+    }
+
+    /**
+     * This method will be called when an invocation has finished. If a long
+     * operation must be performed you should start a Thread.
+     */
+    public abstract void invocationFinished(RInvocationEvent event)
+        throws RemoteException;
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationListenerWrapper.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationListenerWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..1242caac1b0a0e18625cd664de92d13bd7d32859
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RInvocationListenerWrapper.java
@@ -0,0 +1,71 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009,2010  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.RemoteException;
+import java.rmi.ServerError;
+import java.rmi.ServerException;
+
+import rmiextension.wrappers.RBlueJImpl;
+
+import bluej.extensions.event.InvocationEvent;
+import bluej.extensions.event.InvocationListener;
+import bluej.utility.Debug;
+
+/**
+ * Wrapper for remote invocation listeners
+ * 
+ * @author Poul Henriksen <polle@mip.sdu.dk>
+ */
+public class RInvocationListenerWrapper
+    implements InvocationListener
+{
+    private RInvocationListener remoteListener;
+    private RBlueJImpl blueJ;
+
+    public RInvocationListenerWrapper(RInvocationListener remoteListener)
+    {
+        this.remoteListener = remoteListener;
+    }
+
+    /*
+     * @see bluej.extensions.event.InvocationListener#invocationFinished(bluej.extensions.event.InvocationEvent)
+     */
+    public void invocationFinished(InvocationEvent event)
+    {
+        try {
+            RInvocationEvent rEvent = new RInvocationEventImpl(event);
+            remoteListener.invocationFinished(rEvent);
+        }
+        catch (ServerError se) {
+            Debug.reportError("Remote compile listener ServerError", se.getCause());
+        }
+        catch (ServerException se) {
+            Debug.reportError("Remote compile listener ServerException", se.getCause());
+        }
+        catch (RemoteException re) {
+            // Connection interrupted or other problem; remote VM no longer accessible
+            blueJ.removeInvocationListener(remoteListener);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RProjectListener.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RProjectListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..44006e04e2d5e4c294d90d89f19f0005dfcfcd15
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RProjectListener.java
@@ -0,0 +1,44 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * A listener for project events. Currently the only event is a project close.
+ * 
+ * @author Davin McCall
+ * @version $Id: RProjectListener.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public interface RProjectListener
+    extends Remote
+{
+    /**
+     * The project is about to close. This is called before the project actually
+     * closes, and will only be called if the close() method in RProject is used
+     * to close the project.
+     * 
+     * @throws RemoteException
+     */
+    public void projectClosing() throws RemoteException;
+}
diff --git a/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RProjectListenerImpl.java b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RProjectListenerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..6fb24936d1629495f2c32232a6c00eb4386be669
--- /dev/null
+++ b/Sd1/P/Maven/greenfoot/src/main/java/rmiextension/wrappers/event/RProjectListenerImpl.java
@@ -0,0 +1,45 @@
+/*
+ This file is part of the Greenfoot program. 
+ Copyright (C) 2005-2009  Poul Henriksen and Michael Kolling 
+ 
+ This program is free software; you can redistribute it and/or 
+ modify it under the terms of the GNU General Public License 
+ as published by the Free Software Foundation; either version 2 
+ of the License, or (at your option) any later version. 
+ 
+ This program is distributed in the hope that it will be useful, 
+ but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ GNU General Public License for more details. 
+ 
+ You should have received a copy of the GNU General Public License 
+ along with this program; if not, write to the Free Software 
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
+ 
+ This file is subject to the Classpath exception as provided in the  
+ LICENSE.txt file that accompanied this code.
+ */
+package rmiextension.wrappers.event;
+
+import java.rmi.RemoteException;
+
+/**
+ * Abstract implementation of an RProjectListener.
+ * 
+ * @author Davin McCall
+ * @version $Id: RProjectListenerImpl.java 6216 2009-03-30 13:41:07Z polle $
+ */
+public abstract class RProjectListenerImpl extends java.rmi.server.UnicastRemoteObject
+    implements RProjectListener
+{
+    public RProjectListenerImpl() throws RemoteException
+    {
+        super();
+    }
+    
+    /* (non-Javadoc)
+     * @see rmiextension.wrappers.event.RProjectListener#projectClosing()
+     */
+    public abstract void projectClosing();
+
+}